Files
ent/schema/field/field.go
Ariel Mashraki 9e809635b2 entc/gen: ignore immutable fields on Upsert<T>.UpdateNewValues
Also, for some reason, the TimeMixin.UpdateTime was an immutable field,
but this was incorrent, because the codegen just skip generating
update setters to it. Removing the Immutable modifier allows users
to set this field explicitly.
2021-10-08 08:20:05 +03:00

1223 lines
32 KiB
Go

// Copyright 2019-present Facebook Inc. All rights reserved.
// This source code is licensed under the Apache 2.0 license found
// in the LICENSE file in the root directory of this source tree.
package field
import (
"database/sql"
"database/sql/driver"
"errors"
"fmt"
"math"
"reflect"
"regexp"
"time"
"entgo.io/ent/schema"
)
// String returns a new Field with type string.
func String(name string) *stringBuilder {
return &stringBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{Type: TypeString},
}}
}
// Text returns a new string field without limitation on the size.
// In MySQL, it is the "longtext" type, but in SQLite and Gremlin it has not effect.
func Text(name string) *stringBuilder {
return &stringBuilder{&Descriptor{
Name: name,
Size: math.MaxInt32,
Info: &TypeInfo{Type: TypeString},
}}
}
// Bytes returns a new Field with type bytes/buffer.
// In MySQL and SQLite, it is the "BLOB" type, and it does not support for Gremlin.
func Bytes(name string) *bytesBuilder {
return &bytesBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{Type: TypeBytes, Nillable: true},
}}
}
// Bool returns a new Field with type bool.
func Bool(name string) *boolBuilder {
return &boolBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{Type: TypeBool},
}}
}
// Time returns a new Field with type timestamp.
func Time(name string) *timeBuilder {
return &timeBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{Type: TypeTime, PkgPath: "time"},
}}
}
// JSON returns a new Field with type json that is serialized to the given object.
// For example:
//
// field.JSON("dirs", []http.Dir{}).
// Optional()
//
//
// field.JSON("info", &Info{}).
// Optional()
//
func JSON(name string, typ interface{}) *jsonBuilder {
t := reflect.TypeOf(typ)
b := &jsonBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{
Type: TypeJSON,
Ident: t.String(),
PkgPath: t.PkgPath(),
},
}}
b.desc.goType(typ, t)
switch t.Kind() {
case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Map:
b.desc.Info.Nillable = true
b.desc.Info.PkgPath = pkgPath(t)
}
return b
}
// Strings returns a new JSON Field with type []string.
func Strings(name string) *jsonBuilder {
return JSON(name, []string{})
}
// Ints returns a new JSON Field with type []int.
func Ints(name string) *jsonBuilder {
return JSON(name, []int{})
}
// Floats returns a new JSON Field with type []float.
func Floats(name string) *jsonBuilder {
return JSON(name, []float64{})
}
// Enum returns a new Field with type enum. An example for defining enum is as follows:
//
// field.Enum("state").
// Values(
// "on",
// "off",
// ).
// Default("on")
//
func Enum(name string) *enumBuilder {
return &enumBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{Type: TypeEnum},
}}
}
// UUID returns a new Field with type UUID. An example for defining UUID field is as follows:
//
// field.UUID("id", uuid.New())
//
func UUID(name string, typ driver.Valuer) *uuidBuilder {
rt := reflect.TypeOf(typ)
b := &uuidBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{
Type: TypeUUID,
Nillable: true,
Ident: rt.String(),
PkgPath: indirect(rt).PkgPath(),
},
}}
b.desc.goType(typ, valueScannerType)
return b
}
// Other represents a field that is not a good fit for any of the standard field types.
//
// The second argument defines the GoType and must implement the ValueScanner interface.
// The SchemaType option must be set because the field type cannot be inferred.
// An example for defining Other field is as follows:
//
// field.Other("link", &Link{}).
// SchemaType(map[string]string{
// dialect.MySQL: "text",
// dialect.Postgres: "varchar",
// })
//
func Other(name string, typ driver.Valuer) *otherBuilder {
ob := &otherBuilder{&Descriptor{
Name: name,
Info: &TypeInfo{Type: TypeOther},
}}
ob.desc.goType(typ, valueScannerType)
return ob
}
// stringBuilder is the builder for string fields.
type stringBuilder struct {
desc *Descriptor
}
// Unique makes the field unique within all vertices of this type.
func (b *stringBuilder) Unique() *stringBuilder {
b.desc.Unique = true
return b
}
// Sensitive fields not printable and not serializable.
func (b *stringBuilder) Sensitive() *stringBuilder {
b.desc.Sensitive = true
return b
}
// Match adds a regex matcher for this field. Operation fails if the regex fails.
func (b *stringBuilder) Match(re *regexp.Regexp) *stringBuilder {
b.desc.Validators = append(b.desc.Validators, func(v string) error {
if !re.MatchString(v) {
return errors.New("value does not match validation")
}
return nil
})
return b
}
// MinLen adds a length validator for this field.
// Operation fails if the length of the string is less than the given value.
func (b *stringBuilder) MinLen(i int) *stringBuilder {
b.desc.Validators = append(b.desc.Validators, func(v string) error {
if len(v) < i {
return errors.New("value is less than the required length")
}
return nil
})
return b
}
// NotEmpty adds a length validator for this field.
// Operation fails if the length of the string is zero.
func (b *stringBuilder) NotEmpty() *stringBuilder {
return b.MinLen(1)
}
// MaxLen adds a length validator for this field.
// Operation fails if the length of the string is greater than the given value.
func (b *stringBuilder) MaxLen(i int) *stringBuilder {
b.desc.Size = i
b.desc.Validators = append(b.desc.Validators, func(v string) error {
if len(v) > i {
return errors.New("value is greater than the required length")
}
return nil
})
return b
}
// Validate adds a validator for this field. Operation fails if the validation fails.
func (b *stringBuilder) Validate(fn func(string) error) *stringBuilder {
b.desc.Validators = append(b.desc.Validators, fn)
return b
}
// Default sets the default value of the field.
func (b *stringBuilder) Default(s string) *stringBuilder {
b.desc.Default = s
return b
}
// DefaultFunc sets the function that is applied to set the default value
// of the field on creation. For example:
//
// field.String("cuid").
// DefaultFunc(cuid.New)
//
func (b *stringBuilder) DefaultFunc(fn interface{}) *stringBuilder {
b.desc.Default = fn
return b
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated struct.
func (b *stringBuilder) Nillable() *stringBuilder {
b.desc.Nillable = true
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *stringBuilder) Optional() *stringBuilder {
b.desc.Optional = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *stringBuilder) Immutable() *stringBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *stringBuilder) Comment(c string) *stringBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *stringBuilder) StructTag(s string) *stringBuilder {
b.desc.Tag = s
return b
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *stringBuilder) StorageKey(key string) *stringBuilder {
b.desc.StorageKey = key
return b
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for string.
//
// field.String("name").
// SchemaType(map[string]string{
// dialect.MySQL: "text",
// dialect.Postgres: "varchar",
// })
//
func (b *stringBuilder) SchemaType(types map[string]string) *stringBuilder {
b.desc.SchemaType = types
return b
}
// GoType overrides the default Go type with a custom one.
//
// field.String("dir").
// GoType(http.Dir("dir"))
//
func (b *stringBuilder) GoType(typ interface{}) *stringBuilder {
b.desc.goType(typ, stringType)
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
//
// field.String("dir").
// Annotations(
// entgql.OrderField("DIR"),
// )
//
func (b *stringBuilder) Annotations(annotations ...schema.Annotation) *stringBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *stringBuilder) Descriptor() *Descriptor {
if b.desc.Default != nil {
b.desc.checkDefaultFunc(stringType)
}
return b.desc
}
// timeBuilder is the builder for time fields.
type timeBuilder struct {
desc *Descriptor
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated struct.
func (b *timeBuilder) Nillable() *timeBuilder {
b.desc.Nillable = true
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *timeBuilder) Optional() *timeBuilder {
b.desc.Optional = true
return b
}
// Immutable fields are fields that can be set only in the creation of the entity.
// i.e., no setters will be generated for the entity updaters (one and many).
func (b *timeBuilder) Immutable() *timeBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *timeBuilder) Comment(c string) *timeBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *timeBuilder) StructTag(s string) *timeBuilder {
b.desc.Tag = s
return b
}
// Default sets the function that is applied to set default value
// of the field on creation. For example:
//
// field.Time("created_at").
// Default(time.Now)
//
func (b *timeBuilder) Default(f func() time.Time) *timeBuilder {
b.desc.Default = f
return b
}
// UpdateDefault sets the function that is applied to set default value
// of the field on update. For example:
//
// field.Time("updated_at").
// Default(time.Now).
// UpdateDefault(time.Now),
//
func (b *timeBuilder) UpdateDefault(f func() time.Time) *timeBuilder {
b.desc.UpdateDefault = f
return b
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *timeBuilder) StorageKey(key string) *timeBuilder {
b.desc.StorageKey = key
return b
}
// GoType overrides the default Go type with a custom one.
//
// field.Time("deleted_at").
// GoType(&sql.NullTime{})
//
func (b *timeBuilder) GoType(typ interface{}) *timeBuilder {
b.desc.goType(typ, timeType)
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
//
// field.Time("deleted_at").
// Annotations(
// entgql.OrderField("DELETED_AT"),
// )
//
func (b *timeBuilder) Annotations(annotations ...schema.Annotation) *timeBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *timeBuilder) Descriptor() *Descriptor {
return b.desc
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for time.
//
// field.Time("created_at").
// SchemaType(map[string]string{
// dialect.MySQL: "datetime",
// dialect.Postgres: "time with time zone",
// })
//
func (b *timeBuilder) SchemaType(types map[string]string) *timeBuilder {
b.desc.SchemaType = types
return b
}
// boolBuilder is the builder for boolean fields.
type boolBuilder struct {
desc *Descriptor
}
// Default sets the default value of the field.
func (b *boolBuilder) Default(v bool) *boolBuilder {
b.desc.Default = v
return b
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated struct.
func (b *boolBuilder) Nillable() *boolBuilder {
b.desc.Nillable = true
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *boolBuilder) Optional() *boolBuilder {
b.desc.Optional = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *boolBuilder) Immutable() *boolBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *boolBuilder) Comment(c string) *boolBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *boolBuilder) StructTag(s string) *boolBuilder {
b.desc.Tag = s
return b
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *boolBuilder) StorageKey(key string) *boolBuilder {
b.desc.StorageKey = key
return b
}
// GoType overrides the default Go type with a custom one.
//
// field.Bool("deleted").
// GoType(&sql.NullBool{})
//
func (b *boolBuilder) GoType(typ interface{}) *boolBuilder {
b.desc.goType(typ, boolType)
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
//
// field.Bool("deleted").
// Annotations(
// entgql.OrderField("DELETED"),
// )
//
func (b *boolBuilder) Annotations(annotations ...schema.Annotation) *boolBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *boolBuilder) Descriptor() *Descriptor {
return b.desc
}
// bytesBuilder is the builder for bytes fields.
type bytesBuilder struct {
desc *Descriptor
}
// Default sets the default value of the field.
func (b *bytesBuilder) Default(v []byte) *bytesBuilder {
b.desc.Default = v
return b
}
// DefaultFunc sets the function that is applied to set the default value
// of the field on creation. For example:
//
// field.Bytes("cuid").
// DefaultFunc(cuid.New)
//
func (b *bytesBuilder) DefaultFunc(fn interface{}) *bytesBuilder {
b.desc.Default = fn
return b
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated struct.
func (b *bytesBuilder) Nillable() *bytesBuilder {
b.desc.Nillable = true
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *bytesBuilder) Optional() *bytesBuilder {
b.desc.Optional = true
return b
}
// Sensitive fields not printable and not serializable.
func (b *bytesBuilder) Sensitive() *bytesBuilder {
b.desc.Sensitive = true
return b
}
// Unique makes the field unique within all vertices of this type.
// Only supported in PostgreSQL.
func (b *bytesBuilder) Unique() *bytesBuilder {
b.desc.Unique = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *bytesBuilder) Immutable() *bytesBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *bytesBuilder) Comment(c string) *bytesBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *bytesBuilder) StructTag(s string) *bytesBuilder {
b.desc.Tag = s
return b
}
// MaxLen sets the max-length of the bytes type in the database.
// In MySQL, this affects the BLOB type (tiny 2^8-1, regular 2^16-1, medium 2^24-1, long 2^32-1).
// In SQLite, it does not have any effect on the type size, which is default to 1B bytes.
func (b *bytesBuilder) MaxLen(i int) *bytesBuilder {
b.desc.Size = i
b.desc.Validators = append(b.desc.Validators, func(buf []byte) error {
if len(buf) > i {
return errors.New("value is greater than the required length")
}
return nil
})
return b
}
// MinLen adds a length validator for this field.
// Operation fails if the length of the buffer is less than the given value.
func (b *bytesBuilder) MinLen(i int) *bytesBuilder {
b.desc.Validators = append(b.desc.Validators, func(b []byte) error {
if len(b) < i {
return errors.New("value is less than the required length")
}
return nil
})
return b
}
// NotEmpty adds a length validator for this field.
// Operation fails if the length of the buffer is zero.
func (b *bytesBuilder) NotEmpty() *bytesBuilder {
return b.MinLen(1)
}
// Validate adds a validator for this field. Operation fails if the validation fails.
//
// field.Bytes("blob").
// Validate(func(b []byte) error {
// if len(b) % 2 == 0 {
// return fmt.Errorf("ent/schema: blob length is even: %d", len(b))
// }
// return nil
// })
//
func (b *bytesBuilder) Validate(fn func([]byte) error) *bytesBuilder {
b.desc.Validators = append(b.desc.Validators, fn)
return b
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *bytesBuilder) StorageKey(key string) *bytesBuilder {
b.desc.StorageKey = key
return b
}
// GoType overrides the default Go type with a custom one.
//
// field.Bytes("ip").
// GoType(net.IP("127.0.0.1"))
//
func (b *bytesBuilder) GoType(typ interface{}) *bytesBuilder {
b.desc.goType(typ, bytesType)
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
func (b *bytesBuilder) Annotations(annotations ...schema.Annotation) *bytesBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for bytes.
//
// field.Bytes("blob").
// SchemaType(map[string]string{
// dialect.MySQL: "tinyblob",
// dialect.SQLite: "tinyblob",
// })
//
func (b *bytesBuilder) SchemaType(types map[string]string) *bytesBuilder {
b.desc.SchemaType = types
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *bytesBuilder) Descriptor() *Descriptor {
if b.desc.Default != nil {
b.desc.checkDefaultFunc(bytesType)
}
return b.desc
}
// jsonBuilder is the builder for json fields.
type jsonBuilder struct {
desc *Descriptor
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *jsonBuilder) StorageKey(key string) *jsonBuilder {
b.desc.StorageKey = key
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *jsonBuilder) Optional() *jsonBuilder {
b.desc.Optional = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *jsonBuilder) Immutable() *jsonBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *jsonBuilder) Comment(c string) *jsonBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *jsonBuilder) StructTag(s string) *jsonBuilder {
b.desc.Tag = s
return b
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for json.
//
// field.JSON("json").
// SchemaType(map[string]string{
// dialect.MySQL: "json",
// dialect.Postgres: "jsonb",
// })
//
func (b *jsonBuilder) SchemaType(types map[string]string) *jsonBuilder {
b.desc.SchemaType = types
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
func (b *jsonBuilder) Annotations(annotations ...schema.Annotation) *jsonBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *jsonBuilder) Descriptor() *Descriptor {
return b.desc
}
// enumBuilder is the builder for enum fields.
type enumBuilder struct {
desc *Descriptor
}
// Values adds given values to the enum values.
//
// field.Enum("priority").
// Values("low", "mid", "high")
//
func (b *enumBuilder) Values(values ...string) *enumBuilder {
for _, v := range values {
b.desc.Enums = append(b.desc.Enums, struct{ N, V string }{N: v, V: v})
}
return b
}
// NamedValues adds the given name, value pairs to the enum value.
// The "name" defines the Go identifier of the enum, and the value
// defines the actual value in the database.
//
// NamedValues returns an error if given an odd number of arguments.
//
// field.Enum("priority").
// NamedValues(
// "Low", "LOW",
// "Mid", "MID",
// "High", "HIGH",
// )
//
func (b *enumBuilder) NamedValues(namevalue ...string) *enumBuilder {
if len(namevalue)%2 == 1 {
b.desc.Err = fmt.Errorf("Enum.NamedValues: odd argument count")
return b
}
for i := 0; i < len(namevalue); i += 2 {
b.desc.Enums = append(b.desc.Enums, struct{ N, V string }{N: namevalue[i], V: namevalue[i+1]})
}
return b
}
// Default sets the default value of the field.
func (b *enumBuilder) Default(value string) *enumBuilder {
b.desc.Default = value
return b
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *enumBuilder) StorageKey(key string) *enumBuilder {
b.desc.StorageKey = key
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *enumBuilder) Optional() *enumBuilder {
b.desc.Optional = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *enumBuilder) Immutable() *enumBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *enumBuilder) Comment(c string) *enumBuilder {
b.desc.Comment = c
return b
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated struct.
func (b *enumBuilder) Nillable() *enumBuilder {
b.desc.Nillable = true
return b
}
// StructTag sets the struct tag of the field.
func (b *enumBuilder) StructTag(s string) *enumBuilder {
b.desc.Tag = s
return b
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for enum.
//
// field.Enum("enum").
// SchemaType(map[string]string{
// dialect.Postgres: "EnumType",
// })
//
func (b *enumBuilder) SchemaType(types map[string]string) *enumBuilder {
b.desc.SchemaType = types
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
//
// field.Enum("enum").
// Annotations(
// entgql.OrderField("ENUM"),
// )
//
func (b *enumBuilder) Annotations(annotations ...schema.Annotation) *enumBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// EnumValues defines the interface for getting the enum values.
type EnumValues interface {
Values() []string
}
// GoType overrides the default Go type with a custom one.
//
// field.Enum("enum").
// GoType(role.Enum("role"))
//
func (b *enumBuilder) GoType(ev EnumValues) *enumBuilder {
b.Values(ev.Values()...)
b.desc.goType(ev, stringType)
// If an error already exists, let that be returned instead.
// Otherwise check that the underlying type is either a string
// or implements Stringer.
if b.desc.Err == nil && b.desc.Info.RType.rtype.Kind() != reflect.String && !b.desc.Info.Stringer() {
b.desc.Err = errors.New("enum values which implement ValueScanner must also implement Stringer")
}
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *enumBuilder) Descriptor() *Descriptor {
return b.desc
}
// uuidBuilder is the builder for uuid fields.
type uuidBuilder struct {
desc *Descriptor
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *uuidBuilder) StorageKey(key string) *uuidBuilder {
b.desc.StorageKey = key
return b
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated struct.
func (b *uuidBuilder) Nillable() *uuidBuilder {
b.desc.Nillable = true
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *uuidBuilder) Optional() *uuidBuilder {
b.desc.Optional = true
return b
}
// Unique makes the field unique within all vertices of this type.
func (b *uuidBuilder) Unique() *uuidBuilder {
b.desc.Unique = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *uuidBuilder) Immutable() *uuidBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *uuidBuilder) Comment(c string) *uuidBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *uuidBuilder) StructTag(s string) *uuidBuilder {
b.desc.Tag = s
return b
}
// Default sets the function that is applied to set default value
// of the field on creation. Codegen fails if the default function
// doesn't return the same concrete that was set for the UUID type.
//
// field.UUID("id", uuid.UUID{}).
// Default(uuid.New)
//
func (b *uuidBuilder) Default(fn interface{}) *uuidBuilder {
typ := reflect.TypeOf(fn)
if typ.Kind() != reflect.Func || typ.NumIn() != 0 || typ.NumOut() != 1 || typ.Out(0).String() != b.desc.Info.String() {
b.desc.Err = fmt.Errorf("expect type (func() %s) for uuid default value", b.desc.Info)
}
b.desc.Default = fn
return b
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for uuid.
//
// field.UUID("id", uuid.New()).
// SchemaType(map[string]string{
// dialect.Postgres: "CustomUUID",
// })
//
func (b *uuidBuilder) SchemaType(types map[string]string) *uuidBuilder {
b.desc.SchemaType = types
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
//
// field.UUID("id", uuid.New()).
// Annotations(
// entgql.OrderField("ID"),
// )
//
func (b *uuidBuilder) Annotations(annotations ...schema.Annotation) *uuidBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *uuidBuilder) Descriptor() *Descriptor {
return b.desc
}
// otherBuilder is the builder for other fields.
type otherBuilder struct {
desc *Descriptor
}
// Unique makes the field unique within all vertices of this type.
func (b *otherBuilder) Unique() *otherBuilder {
b.desc.Unique = true
return b
}
// Sensitive fields not printable and not serializable.
func (b *otherBuilder) Sensitive() *otherBuilder {
b.desc.Sensitive = true
return b
}
// Default sets the default value of the field. For example:
//
// field.Other("link", &Link{}).
// SchemaType(map[string]string{
// dialect.MySQL: "text",
// dialect.Postgres: "varchar",
// }).
// // A static default value.
// Default(&Link{Addr: "0.0.0.0"})
//
// field.Other("link", &Link{}).
// SchemaType(map[string]string{
// dialect.MySQL: "text",
// dialect.Postgres: "varchar",
// }).
// // A function for generating the default value.
// Default(NewLink)
//
func (b *otherBuilder) Default(v interface{}) *otherBuilder {
b.desc.Default = v
switch fieldT, defaultT := b.desc.Info.RType.rtype, reflect.TypeOf(v); {
case fieldT == defaultT:
case defaultT.Kind() == reflect.Func:
b.desc.checkDefaultFunc(b.desc.Info.RType.rtype)
default:
b.desc.Err = fmt.Errorf("expect type (func() %[1]s) or (%[1]s) for other default value", b.desc.Info)
}
return b
}
// Nillable indicates that this field is a nillable.
// Unlike "Optional" only fields, "Nillable" fields are pointers in the generated field.
func (b *otherBuilder) Nillable() *otherBuilder {
b.desc.Nillable = true
return b
}
// Optional indicates that this field is optional on create.
// Unlike edges, fields are required by default.
func (b *otherBuilder) Optional() *otherBuilder {
b.desc.Optional = true
return b
}
// Immutable indicates that this field cannot be updated.
func (b *otherBuilder) Immutable() *otherBuilder {
b.desc.Immutable = true
return b
}
// Comment sets the comment of the field.
func (b *otherBuilder) Comment(c string) *otherBuilder {
b.desc.Comment = c
return b
}
// StructTag sets the struct tag of the field.
func (b *otherBuilder) StructTag(s string) *otherBuilder {
b.desc.Tag = s
return b
}
// StorageKey sets the storage key of the field.
// In SQL dialects is the column name and Gremlin is the property.
func (b *otherBuilder) StorageKey(key string) *otherBuilder {
b.desc.StorageKey = key
return b
}
// SchemaType overrides the default database type with a custom
// schema type (per dialect) for string.
//
// field.Other("link", Link{}).
// SchemaType(map[string]string{
// dialect.MySQL: "text",
// dialect.Postgres: "varchar",
// })
//
func (b *otherBuilder) SchemaType(types map[string]string) *otherBuilder {
b.desc.SchemaType = types
return b
}
// Annotations adds a list of annotations to the field object to be used by
// codegen extensions.
//
// field.Other("link", &Link{}).
// SchemaType(map[string]string{
// dialect.MySQL: "text",
// dialect.Postgres: "varchar",
// }).
// Annotations(
// entgql.OrderField("LINK"),
// )
//
func (b *otherBuilder) Annotations(annotations ...schema.Annotation) *otherBuilder {
b.desc.Annotations = append(b.desc.Annotations, annotations...)
return b
}
// Descriptor implements the ent.Field interface by returning its descriptor.
func (b *otherBuilder) Descriptor() *Descriptor {
if len(b.desc.SchemaType) == 0 {
b.desc.Err = fmt.Errorf("expect SchemaType to be set for other field")
}
return b.desc
}
// A Descriptor for field configuration.
type Descriptor struct {
Tag string // struct tag.
Size int // varchar size.
Name string // field name.
Info *TypeInfo // field type info.
Unique bool // unique index of field.
Nillable bool // nillable struct field.
Optional bool // nullable field in database.
Immutable bool // create-only field.
Default interface{} // default value on create.
UpdateDefault interface{} // default value on update.
Validators []interface{} // validator functions.
StorageKey string // sql column or gremlin property.
Enums []struct{ N, V string } // enum values.
Sensitive bool // sensitive info string field.
SchemaType map[string]string // override the schema type.
Annotations []schema.Annotation // field annotations.
Comment string // field comment.
Err error
}
func (d *Descriptor) goType(typ interface{}, expectType reflect.Type) {
t := reflect.TypeOf(typ)
tv := indirect(t)
info := &TypeInfo{
Type: d.Info.Type,
Ident: t.String(),
PkgPath: tv.PkgPath(),
RType: &RType{
rtype: t,
Kind: t.Kind(),
Name: tv.Name(),
Ident: tv.String(),
PkgPath: tv.PkgPath(),
Methods: make(map[string]struct{ In, Out []*RType }, t.NumMethod()),
},
}
switch t.Kind() {
case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Map:
info.Nillable = true
}
switch pt := reflect.PtrTo(t); {
case pt.Implements(valueScannerType):
t = pt
fallthrough
case t.Implements(valueScannerType):
n := t.NumMethod()
for i := 0; i < n; i++ {
m := t.Method(i)
in := make([]*RType, m.Type.NumIn()-1)
for j := range in {
arg := m.Type.In(j + 1)
in[j] = &RType{Name: arg.Name(), Ident: arg.String(), Kind: arg.Kind(), PkgPath: arg.PkgPath()}
}
out := make([]*RType, m.Type.NumOut())
for j := range out {
ret := m.Type.Out(j)
out[j] = &RType{Name: ret.Name(), Ident: ret.String(), Kind: ret.Kind(), PkgPath: ret.PkgPath()}
}
info.RType.Methods[m.Name] = struct{ In, Out []*RType }{in, out}
}
case t.Kind() == expectType.Kind() && t.ConvertibleTo(expectType):
default:
d.Err = fmt.Errorf("GoType must be a %q type or ValueScanner", expectType)
}
d.Info = info
}
func (d *Descriptor) checkDefaultFunc(expectType reflect.Type) {
for _, typ := range []reflect.Type{reflect.TypeOf(d.Default), reflect.TypeOf(d.UpdateDefault)} {
if typ == nil || typ.Kind() != reflect.Func || d.Err != nil {
continue
}
err := fmt.Errorf("expect type (func() %s) for default value", d.Info)
if typ.NumIn() != 0 || typ.NumOut() != 1 {
d.Err = err
}
rtype := expectType
if d.Info.RType != nil {
rtype = d.Info.RType.rtype
}
if !typ.Out(0).AssignableTo(rtype) {
d.Err = err
}
}
}
var (
boolType = reflect.TypeOf(false)
bytesType = reflect.TypeOf([]byte(nil))
timeType = reflect.TypeOf(time.Time{})
stringType = reflect.TypeOf("")
valuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
valueScannerType = reflect.TypeOf((*ValueScanner)(nil)).Elem()
)
// ValueScanner is the interface that groups the Value and the Scan methods.
type ValueScanner interface {
driver.Valuer
sql.Scanner
}
// indirect returns the type at the end of indirection.
func indirect(t reflect.Type) reflect.Type {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t
}
func pkgPath(t reflect.Type) string {
pkg := t.PkgPath()
if pkg != "" {
return pkg
}
switch t.Kind() {
case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Map:
return pkgPath(t.Elem())
}
return pkg
}