schema/field: add DefaultFunc for numeric types and add support for it in entc (#1153)

* entc/load: allow defaultfuncs on numeric types

* schema/field: add DefaultFunc on numeric types

* docs: document DefaultFunc better

* chore: update generated files

* pr: address issues

* docs: updates on faq, address requested changes
This commit is contained in:
Morgan
2021-01-10 13:05:45 +01:00
committed by GitHub
parent 727e41e357
commit e4cc63c411
8 changed files with 239 additions and 13 deletions

View File

@@ -6,13 +6,14 @@ sidebar_label: FAQ
## Questions
[How to create an entity from a struct `T`?](#how-to-create-an-entity-from-a-struct-t)
[How to create a struct (or a mutation) level validator?](#how-to-create-a-mutation-level-validator)
[How to write an audit-log extension?](#how-to-write-an-audit-log-extension)
[How to write custom predicates?](#how-to-write-custom-predicates)
[How to add custom predicates to the codegen assets?](#how-to-add-custom-predicates-to-the-codegen-assets)
[How to define a network address field in PostgreSQL?](#how-to-define-a-network-address-field-in-postgresql)
[How to customize time fields to type `DATETIME` in MySQL?](#how-to-customize-time-fields-to-type-datetime-in-mysql)
[How to create an entity from a struct `T`?](#how-to-create-an-entity-from-a-struct-t) \
[How to create a struct (or a mutation) level validator?](#how-to-create-a-mutation-level-validator) \
[How to write an audit-log extension?](#how-to-write-an-audit-log-extension) \
[How to write custom predicates?](#how-to-write-custom-predicates) \
[How to add custom predicates to the codegen assets?](#how-to-add-custom-predicates-to-the-codegen-assets) \
[How to define a network address field in PostgreSQL?](#how-to-define-a-network-address-field-in-postgresql) \
[How to customize time fields to type `DATETIME` in MySQL?](#how-to-customize-time-fields-to-type-datetime-in-mysql) \
[How do I use a custom generator of IDs?](#how-do-i-use-a-custom-generator-of-ids)
## Answers
@@ -307,7 +308,7 @@ func (i Inet) Value() (driver.Value, error) {
#### How to customize time fields to type `DATETIME` in MySQL?
`Time` fields use the MySQL `TIMESTAMP` type in the schema creation by default, and this type
has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC (see, [MySQL docs](https://dev.mysql.com/doc/refman/5.6/en/datetime.html)).
has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC (see, [MySQL docs](https://dev.mysql.com/doc/refman/5.6/en/datetime.html)).
In order to customize time fields for a wider range, use the MySQL `DATETIME` as follows:
```go
@@ -316,4 +317,75 @@ field.Time("birth_date").
SchemaType(map[string]string{
dialect.MySQL: "datetime",
}),
```
```
#### How do I use a custom generator of IDs?
If you're using a custom ID generator instead of using auto-incrementing IDs in
your database (e.g. Twitter's [Snowflake](https://github.com/twitter-archive/snowflake/tree/snowflake-2010)),
you will need to write a custom ID field which automatically calls the generator
on resource creation.
To achieve this, you can either make use of `DefaultFunc` or of schema hooks -
depending on your use case. If the generator does not return an error,
`DefaultFunc` is more concise, whereas setting a hook on resource creation
will allow you to capture errors as well. An example of how to use
`DefaultFunc` can be seen in the section regarding [the ID field](schema-fields.md#id-field).
Here is an example of how to use a custom generator with hooks, taking as an
example [sonyflake](https://github.com/sony/sonyflake).
```go
// BaseMixin to be shared will all different schemas.
type BaseMixin struct {
mixin.Schema
}
func (BaseMixin) Fields() []ent.Field {
return []ent.Field{
field.Uint64("id"),
}
}
func (BaseMixin) Hooks() []ent.Hook {
return []ent.Hook{
hook.On(IDHook(), ent.OpCreate),
}
}
var sf = sonyflake.NewSonyflake(sonyflage.Settings{})
func IDHook() ent.Hook {
type IDSetter interface {
SetID(uint64)
}
return func(next ent.Mutator) ent.Mutator {
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
is, ok := m.(IDSetter)
if !ok {
return nil, fmt.Errorf("unexpected mutation %T", m)
}
id, err := sf.NextID()
if err != nil {
return nil, err
}
is.SetID(id)
return next.Mutate(ctx, m)
})
}
}
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Mixin of the User.
func (User) Mixin() []ent.Mixin {
return []ent.Mixin{
// Embed the BaseMixin in the user schema.
BaseMixin{},
}
}
```

View File

@@ -144,6 +144,25 @@ func (Pet) Fields() []ent.Field {
}
```
If you need to set a custom function to generate IDs, you can use `DefaultFunc`
to specify a function which will always be ran when the resource is created.
See the [related FAQ](faq.md#how-do-i-use-a-custom-generator-of-ids) for more information.
```go
var globalIDCounter int64 = 0
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int64("id").
DefaultFunc(func() int64 {
// example of a dumb ID generator - use a production-ready alternative instead
return time.Now().Unix() << 8 | atomic.AddInt64(&counter, 1) % 256
}),
}
}
```
## Database Type
Each database dialect has its own mapping from Go type to database type. For example,
@@ -169,7 +188,7 @@ func (Card) Fields() []ent.Field {
return []ent.Field{
field.Float("amount").
SchemaType(map[string]string{
dialect.MySQL: "decimal(6,2)", // Override MySQL.
dialect.MySQL: "decimal(6,2)", // Override MySQL.
dialect.Postgres: "numeric", // Override Postgres.
}),
}
@@ -223,6 +242,7 @@ func (Card) Fields() []ent.Field {
## Default Values
**Non-unique** fields support default values using the `Default` and `UpdateDefault` methods.
You can also specify `DefaultFunc` instead to have a custom generator.
```go
// Fields of the User.
@@ -241,6 +261,9 @@ func (User) Fields() []ent.Field {
}
```
In case your `DefaultFunc` is also returning an error, it is better if it is
handled properly. [See this FAQ.](faq.md#how-do-i-use-a-custom-generator-of-ids)
## Validators
A field validator is a function from type `func(T) error` that is defined in the schema