snapshot of https://github.com/ent/ent.git (master, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
81
schema/field/annotation.go
Normal file
81
schema/field/annotation.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// 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 "entgo.io/ent/schema"
|
||||
|
||||
// Annotation is a builtin schema annotation for
|
||||
// configuring the schema fields in codegen.
|
||||
type Annotation struct {
|
||||
// The StructTag option allows overriding the struct-tag
|
||||
// of the fields in the generated entity. For example:
|
||||
//
|
||||
// field.Annotation{
|
||||
// StructTag: map[string]string{
|
||||
// "id": `json:"id,omitempty" yaml:"-"`,
|
||||
// },
|
||||
// }
|
||||
//
|
||||
StructTag map[string]string
|
||||
|
||||
// ID defines a multi-field schema identifier. Note,
|
||||
// the annotation is valid only for edge schemas.
|
||||
//
|
||||
// func (TweetLike) Annotations() []schema.Annotation {
|
||||
// return []schema.Annotation{
|
||||
// field.ID("user_id", "tweet_id"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
ID []string
|
||||
}
|
||||
|
||||
// ID defines a multi-field schema identifier. Note, the
|
||||
// annotation is valid only for edge schemas.
|
||||
//
|
||||
// func (TweetLike) Annotations() []schema.Annotation {
|
||||
// return []schema.Annotation{
|
||||
// field.ID("user_id", "tweet_id"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
func ID(first, second string, fields ...string) *Annotation {
|
||||
return &Annotation{ID: append([]string{first, second}, fields...)}
|
||||
}
|
||||
|
||||
// Name describes the annotation name.
|
||||
func (Annotation) Name() string {
|
||||
return "Fields"
|
||||
}
|
||||
|
||||
// Merge implements the schema.Merger interface.
|
||||
func (a Annotation) Merge(other schema.Annotation) schema.Annotation {
|
||||
var ant Annotation
|
||||
switch other := other.(type) {
|
||||
case Annotation:
|
||||
ant = other
|
||||
case *Annotation:
|
||||
if other != nil {
|
||||
ant = *other
|
||||
}
|
||||
default:
|
||||
return a
|
||||
}
|
||||
if a.StructTag == nil && len(ant.StructTag) > 0 {
|
||||
a.StructTag = make(map[string]string, len(ant.StructTag))
|
||||
}
|
||||
for k, v := range ant.StructTag {
|
||||
a.StructTag[k] = v
|
||||
}
|
||||
if len(ant.ID) > 0 {
|
||||
a.ID = ant.ID
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
schema.Annotation
|
||||
schema.Merger
|
||||
} = (*Annotation)(nil)
|
||||
26
schema/field/annotation_test.go
Normal file
26
schema/field/annotation_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"entgo.io/ent/schema/field"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAnnotation_Merge(t *testing.T) {
|
||||
ant := field.Annotation{}
|
||||
a := ant.Merge(field.Annotation{
|
||||
StructTag: map[string]string{"foo": "bar"},
|
||||
})
|
||||
assert.Equal(t, a.(field.Annotation).StructTag["foo"], "bar")
|
||||
a = ant.Merge(&field.Annotation{
|
||||
StructTag: map[string]string{"foo": "baz", "baz": "qux"},
|
||||
})
|
||||
assert.Equal(t, a.(field.Annotation).StructTag["foo"], "baz")
|
||||
assert.Equal(t, a.(field.Annotation).StructTag["baz"], "qux")
|
||||
}
|
||||
1909
schema/field/field.go
Normal file
1909
schema/field/field.go
Normal file
File diff suppressed because it is too large
Load Diff
1017
schema/field/field_test.go
Normal file
1017
schema/field/field_test.go
Normal file
File diff suppressed because it is too large
Load Diff
56
schema/field/internal/gen.go
Normal file
56
schema/field/internal/gen.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
// gen is a codegen cmd for generating numeric build types from template.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/format"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"entgo.io/ent/schema/field"
|
||||
)
|
||||
|
||||
func main() {
|
||||
buf, err := os.ReadFile("internal/numeric.tmpl")
|
||||
if err != nil {
|
||||
log.Fatal("reading template file:", err)
|
||||
}
|
||||
intTmpl := template.Must(template.New("numeric").
|
||||
Funcs(template.FuncMap{"title": strings.Title, "hasPrefix": strings.HasPrefix, "toUpper": strings.ToUpper}).
|
||||
Parse(string(buf)))
|
||||
b := &bytes.Buffer{}
|
||||
if err := intTmpl.Execute(b, struct {
|
||||
Ints, Floats []field.Type
|
||||
}{
|
||||
Ints: []field.Type{
|
||||
field.TypeInt,
|
||||
field.TypeUint,
|
||||
field.TypeInt8,
|
||||
field.TypeInt16,
|
||||
field.TypeInt32,
|
||||
field.TypeInt64,
|
||||
field.TypeUint8,
|
||||
field.TypeUint16,
|
||||
field.TypeUint32,
|
||||
field.TypeUint64,
|
||||
},
|
||||
Floats: []field.Type{
|
||||
field.TypeFloat64,
|
||||
field.TypeFloat32,
|
||||
},
|
||||
}); err != nil {
|
||||
log.Fatal("executing template:", err)
|
||||
}
|
||||
if buf, err = format.Source(b.Bytes()); err != nil {
|
||||
log.Fatal("formatting output:", err)
|
||||
}
|
||||
if err := os.WriteFile("numeric.go", buf, 0644); err != nil {
|
||||
log.Fatal("writing go file:", err)
|
||||
}
|
||||
}
|
||||
470
schema/field/internal/numeric.tmpl
Normal file
470
schema/field/internal/numeric.tmpl
Normal file
@@ -0,0 +1,470 @@
|
||||
{{ define "numeric" }}
|
||||
// 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.
|
||||
|
||||
// Code generated by internal/numeric.tmpl, DO NOT EDIT.
|
||||
|
||||
package field
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"entgo.io/ent/schema"
|
||||
)
|
||||
|
||||
//go:generate go run internal/gen.go
|
||||
|
||||
{{ range $t := $.Ints }}
|
||||
{{ $title := title $t.String }}
|
||||
// {{ $title }} returns a new Field with type {{ $t }}.
|
||||
func {{ $title }}(name string) *{{ $t }}Builder { return &{{ $t }}Builder{&Descriptor{
|
||||
Name: name,
|
||||
Info: &TypeInfo{Type: Type{{ $title }} },
|
||||
}}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
// Float returns a new Field with type float64.
|
||||
func Float(name string) *float64Builder { return &float64Builder{&Descriptor{
|
||||
Name: name,
|
||||
Info: &TypeInfo{Type: TypeFloat64},
|
||||
}}
|
||||
}
|
||||
|
||||
// Float32 returns a new Field with type float32.
|
||||
func Float32(name string) *float32Builder { return &float32Builder{&Descriptor{
|
||||
Name: name,
|
||||
Info: &TypeInfo{Type: TypeFloat32},
|
||||
}}
|
||||
}
|
||||
|
||||
{{ range $t := $.Ints }}
|
||||
{{ $builder := printf "%sBuilder" $t }}
|
||||
|
||||
// {{ $builder }} is the builder for {{ $t }} field.
|
||||
type {{ $builder }} struct {
|
||||
desc *Descriptor
|
||||
}
|
||||
|
||||
// Unique makes the field unique within all vertices of this type.
|
||||
func (b *{{ $builder }}) Unique() *{{ $builder }} {
|
||||
b.desc.Unique = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Range adds a range validator for this field where the given value needs to be in the range of [i, j].
|
||||
func (b *{{ $builder }}) Range(i, j {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Validators = append(b.desc.Validators, func(v {{ $t }}) error {
|
||||
if v < i || v > j {
|
||||
return errors.New("value out of range")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Min adds a minimum value validator for this field. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Min(i {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Validators = append(b.desc.Validators, func(v {{ $t }}) error {
|
||||
if v < i {
|
||||
return errors.New("value out of range")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Max adds a maximum value validator for this field. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Max(i {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Validators = append(b.desc.Validators, func(v {{ $t }}) error {
|
||||
if v > i {
|
||||
return errors.New("value out of range")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Positive adds a minimum value validator with the value of 1. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Positive() *{{ $builder }} {
|
||||
return b.Min(1)
|
||||
}
|
||||
|
||||
{{ if hasPrefix $t.String "uint" | not }}
|
||||
// Negative adds a maximum value validator with the value of -1. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Negative() *{{ $builder }} {
|
||||
return b.Max(-1)
|
||||
}
|
||||
|
||||
// NonNegative adds a minimum value validator with the value of 0. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) NonNegative() *{{ $builder }} {
|
||||
return b.Min(0)
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
// Default sets the default value of the field.
|
||||
func (b *{{ $builder }}) Default(i {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Default = i
|
||||
return b
|
||||
}
|
||||
|
||||
// DefaultFunc sets the function that is applied to set the default value
|
||||
// of the field on creation.
|
||||
func (b *{{ $builder }}) DefaultFunc(fn any) *{{ $builder }} {
|
||||
b.desc.Default = fn
|
||||
return b
|
||||
}
|
||||
|
||||
// UpdateDefault sets the function that is applied to set default value
|
||||
// of the field on update. For example:
|
||||
//
|
||||
// field.{{ title $t.String }}("{{$t.String}}").
|
||||
// Default(0).
|
||||
// UpdateDefault(GenNumber),
|
||||
//
|
||||
func (b *{{ $builder }}) UpdateDefault(fn any) *{{ $builder }} {
|
||||
b.desc.UpdateDefault = 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 *{{ $builder }}) Nillable() *{{ $builder }} {
|
||||
b.desc.Nillable = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Comment sets the comment of the field.
|
||||
func (b *{{ $builder }}) Comment(c string) *{{ $builder }} {
|
||||
b.desc.Comment = c
|
||||
return b
|
||||
}
|
||||
|
||||
// Optional indicates that this field is optional on create.
|
||||
// Unlike edges, fields are required by default.
|
||||
func (b *{{ $builder }}) Optional() *{{ $builder }} {
|
||||
b.desc.Optional = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Immutable indicates that this field cannot be updated.
|
||||
func (b *{{ $builder }}) Immutable() *{{ $builder }} {
|
||||
b.desc.Immutable = true
|
||||
return b
|
||||
}
|
||||
|
||||
// StructTag sets the struct tag of the field.
|
||||
func (b *{{ $builder }}) StructTag(s string) *{{ $builder }} {
|
||||
b.desc.Tag = s
|
||||
return b
|
||||
}
|
||||
|
||||
// Validate adds a validator for this field. Operation fails if the validation fails.
|
||||
func (b *{{ $builder }}) Validate(fn func({{ $t }}) error) *{{ $builder }} {
|
||||
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 *{{ $builder }}) StorageKey(key string) *{{ $builder }} {
|
||||
b.desc.StorageKey = key
|
||||
return b
|
||||
}
|
||||
|
||||
// SchemaType overrides the default database type with a custom
|
||||
// schema type (per dialect) for {{ $t.String }}.
|
||||
//
|
||||
// field.{{ title $t.String }}("oid").
|
||||
// SchemaType(map[string]string{
|
||||
// dialect.Postgres: "CustomType",
|
||||
// })
|
||||
//
|
||||
func (b *{{ $builder }}) SchemaType(types map[string]string) *{{ $builder }} {
|
||||
b.desc.SchemaType = types
|
||||
return b
|
||||
}
|
||||
|
||||
{{ $tt := title $t.String }}
|
||||
// GoType overrides the default Go type with a custom one.
|
||||
// If the provided type implements the Validator interface
|
||||
// and no validators have been set, the type validator will
|
||||
// be used.
|
||||
//
|
||||
// field.{{ $tt }}("{{ $t }}").
|
||||
// GoType(pkg.{{ $tt }}(0))
|
||||
//
|
||||
// Note that, the custom Go type `T` needs to implement the
|
||||
// `Add(T) T` method in order to support the `Add<F>` operation
|
||||
// in mutations. For example:
|
||||
//
|
||||
// func(t1 T) Add(t2 T) T {
|
||||
// return add(t1, t2)
|
||||
// }
|
||||
//
|
||||
func (b *{{ $builder }}) GoType(typ any) *{{ $builder }} {
|
||||
b.desc.goType(typ)
|
||||
return b
|
||||
}
|
||||
|
||||
// ValueScanner provides an external value scanner for the given GoType.
|
||||
// Using this option allow users to use field types that do not implement
|
||||
// the sql.Scanner and driver.Valuer interfaces.
|
||||
func (b *{{ $builder }}) ValueScanner(vs any) *{{ $builder }} {
|
||||
b.desc.ValueScanner = vs
|
||||
return b
|
||||
}
|
||||
|
||||
// Annotations adds a list of annotations to the field object to be used by
|
||||
// codegen extensions.
|
||||
//
|
||||
// field.{{ $tt }}("{{ $t }}").
|
||||
// Annotations(entgql.OrderField("{{ $t.String | toUpper }}"))
|
||||
//
|
||||
func (b *{{ $builder }}) Annotations(annotations ...schema.Annotation) *{{ $builder }} {
|
||||
b.desc.Annotations = append(b.desc.Annotations, annotations...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Deprecated marks the field as deprecated. Deprecated fields are not
|
||||
// selected by default in queries, and their struct fields are annotated
|
||||
// with `deprecated` in the generated code.
|
||||
func (b *{{ $builder }}) Deprecated(reason ...string) *{{ $builder }} {
|
||||
b.desc.Deprecated = true
|
||||
if len(reason) > 0 {
|
||||
b.desc.DeprecatedReason = strings.Join(reason, " ")
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Descriptor implements the ent.Field interface by returning its descriptor.
|
||||
func (b *{{ $builder }}) Descriptor() *Descriptor {
|
||||
if b.desc.Default != nil || b.desc.UpdateDefault != nil {
|
||||
b.desc.checkDefaultFunc({{ $t }}Type)
|
||||
}
|
||||
b.desc.checkGoType({{ $t }}Type)
|
||||
return b.desc
|
||||
}
|
||||
|
||||
{{ end }}
|
||||
|
||||
var (
|
||||
{{- range $t := $.Ints }}
|
||||
{{ $t }}Type = reflect.TypeOf({{ $t }}(0))
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
{{ range $t := $.Floats }}
|
||||
{{ $builder := printf "%sBuilder" $t }}
|
||||
|
||||
// {{ $builder }} is the builder for float fields.
|
||||
type {{ $builder }} struct {
|
||||
desc *Descriptor
|
||||
}
|
||||
|
||||
// Unique makes the field unique within all vertices of this type.
|
||||
func (b *{{ $builder }}) Unique() *{{ $builder }} {
|
||||
b.desc.Unique = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Range adds a range validator for this field where the given value needs to be in the range of [i, j].
|
||||
func (b *{{ $builder }}) Range(i, j {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Validators = append(b.desc.Validators, func(v {{ $t }}) error {
|
||||
if v < i || v > j {
|
||||
return errors.New("value out of range")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Min adds a minimum value validator for this field. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Min(i {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Validators = append(b.desc.Validators, func(v {{ $t }}) error {
|
||||
if v < i {
|
||||
return errors.New("value out of range")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Max adds a maximum value validator for this field. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Max(i {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Validators = append(b.desc.Validators, func(v {{ $t }}) error {
|
||||
if v > i {
|
||||
return errors.New("value out of range")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// Positive adds a minimum value validator with the value of 0.000001. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Positive() *{{ $builder }} {
|
||||
return b.Min(1e-06)
|
||||
}
|
||||
|
||||
// Negative adds a maximum value validator with the value of -0.000001. Operation fails if the validator fails.
|
||||
func (b *{{ $builder }}) Negative() *{{ $builder }} {
|
||||
return b.Max(-1e-06)
|
||||
}
|
||||
|
||||
// Default sets the default value of the field.
|
||||
func (b *{{ $builder }}) Default(i {{ $t }}) *{{ $builder }} {
|
||||
b.desc.Default = i
|
||||
return b
|
||||
}
|
||||
|
||||
// DefaultFunc sets the function that is applied to set the default value
|
||||
// of the field on creation.
|
||||
func (b *{{ $builder }}) DefaultFunc(fn any) *{{ $builder }} {
|
||||
b.desc.Default = fn
|
||||
return b
|
||||
}
|
||||
|
||||
// UpdateDefault sets the function that is applied to set default value
|
||||
// of the field on update. For example:
|
||||
//
|
||||
// field.{{ title $t.String }}("{{$t.String}}").
|
||||
// Default(0).
|
||||
// UpdateDefault(GenNumber),
|
||||
//
|
||||
func (b *{{ $builder }}) UpdateDefault(fn any) *{{ $builder }} {
|
||||
b.desc.UpdateDefault = 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 *{{ $builder }}) Nillable() *{{ $builder }} {
|
||||
b.desc.Nillable = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Comment sets the comment of the field.
|
||||
func (b *{{ $builder }}) Comment(c string) *{{ $builder }} {
|
||||
b.desc.Comment = c
|
||||
return b
|
||||
}
|
||||
|
||||
// Optional indicates that this field is optional on create.
|
||||
// Unlike edges, fields are required by default.
|
||||
func (b *{{ $builder }}) Optional() *{{ $builder }} {
|
||||
b.desc.Optional = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Immutable indicates that this field cannot be updated.
|
||||
func (b *{{ $builder }}) Immutable() *{{ $builder }} {
|
||||
b.desc.Immutable = true
|
||||
return b
|
||||
}
|
||||
|
||||
// StructTag sets the struct tag of the field.
|
||||
func (b *{{ $builder }}) StructTag(s string) *{{ $builder }} {
|
||||
b.desc.Tag = s
|
||||
return b
|
||||
}
|
||||
|
||||
// Validate adds a validator for this field. Operation fails if the validation fails.
|
||||
func (b *{{ $builder }}) Validate(fn func({{ $t }}) error) *{{ $builder }} {
|
||||
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 *{{ $builder }}) StorageKey(key string) *{{ $builder }} {
|
||||
b.desc.StorageKey = key
|
||||
return b
|
||||
}
|
||||
|
||||
// SchemaType overrides the default database type with a custom
|
||||
// schema type (per dialect) for {{ $t.String }}.
|
||||
//
|
||||
// field.{{ title $t.String }}("amount").
|
||||
// SchemaType(map[string]string{
|
||||
// dialect.MySQL: "decimal(5, 2)",
|
||||
// dialect.Postgres: "numeric(5, 2)",
|
||||
// })
|
||||
//
|
||||
func (b *{{ $builder }}) SchemaType(types map[string]string) *{{ $builder }} {
|
||||
b.desc.SchemaType = types
|
||||
return b
|
||||
}
|
||||
|
||||
{{ $tt := title $t.String }}
|
||||
// GoType overrides the default Go type with a custom one.
|
||||
// If the provided type implements the Validator interface
|
||||
// and no validators have been set, the type validator will
|
||||
// be used.
|
||||
//
|
||||
// field.{{ $tt }}("{{ $t }}").
|
||||
// GoType(pkg.{{ $tt }}(0))
|
||||
//
|
||||
// Note that, the custom Go type `T` needs to implement the
|
||||
// `Add(T) T` method in order to support the `Add<F>` operation
|
||||
// in mutations. For example:
|
||||
//
|
||||
// func(t1 T) Add(t2 T) T {
|
||||
// return add(t1, t2)
|
||||
// }
|
||||
//
|
||||
func (b *{{ $builder }}) GoType(typ any) *{{ $builder }} {
|
||||
b.desc.goType(typ)
|
||||
return b
|
||||
}
|
||||
|
||||
// ValueScanner provides an external value scanner for the given GoType.
|
||||
// Using this option allow users to use field types that do not implement
|
||||
// the sql.Scanner and driver.Valuer interfaces.
|
||||
func (b *{{ $builder }}) ValueScanner(vs any) *{{ $builder }} {
|
||||
b.desc.ValueScanner = vs
|
||||
return b
|
||||
}
|
||||
|
||||
// Annotations adds a list of annotations to the field object to be used by
|
||||
// codegen extensions.
|
||||
//
|
||||
// field.{{ $tt }}("{{ $t }}").
|
||||
// Annotations(entgql.OrderField("{{ $t.String | toUpper }}"))
|
||||
//
|
||||
func (b *{{ $builder }}) Annotations(annotations ...schema.Annotation) *{{ $builder }} {
|
||||
b.desc.Annotations = append(b.desc.Annotations, annotations...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Deprecated marks the field as deprecated. Deprecated fields are not
|
||||
// selected by default in queries, and their struct fields are annotated
|
||||
// with `deprecated` in the generated code.
|
||||
func (b *{{ $builder }}) Deprecated(reason ...string) *{{ $builder }} {
|
||||
b.desc.Deprecated = true
|
||||
if len(reason) > 0 {
|
||||
b.desc.DeprecatedReason = strings.Join(reason, " ")
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Descriptor implements the ent.Field interface by returning its descriptor.
|
||||
func (b *{{ $builder }}) Descriptor() *Descriptor {
|
||||
if b.desc.Default != nil || b.desc.UpdateDefault != nil {
|
||||
b.desc.checkDefaultFunc({{ $t }}Type)
|
||||
}
|
||||
b.desc.checkGoType({{ $t }}Type)
|
||||
return b.desc
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
var (
|
||||
{{- range $t := $.Floats }}
|
||||
{{ $t }}Type = reflect.TypeOf({{ $t }}(0))
|
||||
{{- end }}
|
||||
)
|
||||
|
||||
{{ end }}
|
||||
2449
schema/field/numeric.go
Normal file
2449
schema/field/numeric.go
Normal file
File diff suppressed because it is too large
Load Diff
252
schema/field/type.go
Normal file
252
schema/field/type.go
Normal file
@@ -0,0 +1,252 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Type represents a field type.
|
||||
type Type uint8
|
||||
|
||||
// List of field types.
|
||||
const (
|
||||
TypeInvalid Type = iota
|
||||
TypeBool
|
||||
TypeTime
|
||||
TypeJSON
|
||||
TypeUUID
|
||||
TypeBytes
|
||||
TypeEnum
|
||||
TypeString
|
||||
TypeOther
|
||||
TypeInt8
|
||||
TypeInt16
|
||||
TypeInt32
|
||||
TypeInt
|
||||
TypeInt64
|
||||
TypeUint8
|
||||
TypeUint16
|
||||
TypeUint32
|
||||
TypeUint
|
||||
TypeUint64
|
||||
TypeFloat32
|
||||
TypeFloat64
|
||||
TypeBlob
|
||||
endTypes
|
||||
)
|
||||
|
||||
// String returns the string representation of a type.
|
||||
func (t Type) String() string {
|
||||
if t < endTypes {
|
||||
return typeNames[t]
|
||||
}
|
||||
return typeNames[TypeInvalid]
|
||||
}
|
||||
|
||||
// Numeric reports if the given type is a numeric type.
|
||||
func (t Type) Numeric() bool {
|
||||
return t >= TypeInt8 && t < TypeBlob
|
||||
}
|
||||
|
||||
// Float reports if the given type is a float type.
|
||||
func (t Type) Float() bool {
|
||||
return t == TypeFloat32 || t == TypeFloat64
|
||||
}
|
||||
|
||||
// Integer reports if the given type is an integral type.
|
||||
func (t Type) Integer() bool {
|
||||
return t.Numeric() && !t.Float()
|
||||
}
|
||||
|
||||
// Valid reports if the given type if known type.
|
||||
func (t Type) Valid() bool {
|
||||
return t > TypeInvalid && t < endTypes
|
||||
}
|
||||
|
||||
// ConstName returns the constant name of an info type.
|
||||
// It's used by entc for printing the constant name in templates.
|
||||
func (t Type) ConstName() string {
|
||||
switch {
|
||||
case !t.Valid():
|
||||
return typeNames[TypeInvalid]
|
||||
case int(t) < len(constNames) && constNames[t] != "":
|
||||
return constNames[t]
|
||||
default:
|
||||
return "Type" + strings.Title(typeNames[t])
|
||||
}
|
||||
}
|
||||
|
||||
// TypeInfo holds the information regarding field type.
|
||||
// Used by complex types like JSON and Bytes.
|
||||
type TypeInfo struct {
|
||||
Type Type
|
||||
Ident string
|
||||
PkgPath string // import path.
|
||||
PkgName string // local package name.
|
||||
Nillable bool // slices or pointers.
|
||||
RType *RType
|
||||
}
|
||||
|
||||
// String returns the string representation of a type.
|
||||
func (t TypeInfo) String() string {
|
||||
switch {
|
||||
case t.Ident != "":
|
||||
return t.Ident
|
||||
case t.Type < endTypes:
|
||||
return typeNames[t.Type]
|
||||
default:
|
||||
return typeNames[TypeInvalid]
|
||||
}
|
||||
}
|
||||
|
||||
// Valid reports if the given type if known type.
|
||||
func (t TypeInfo) Valid() bool {
|
||||
return t.Type.Valid()
|
||||
}
|
||||
|
||||
// Numeric reports if the given type is a numeric type.
|
||||
func (t TypeInfo) Numeric() bool {
|
||||
return t.Type.Numeric()
|
||||
}
|
||||
|
||||
// ConstName returns the const name of the info type.
|
||||
func (t TypeInfo) ConstName() string {
|
||||
return t.Type.ConstName()
|
||||
}
|
||||
|
||||
// ValueScanner indicates if this type implements the ValueScanner interface.
|
||||
func (t TypeInfo) ValueScanner() bool {
|
||||
return t.RType.Implements(valueScannerType)
|
||||
}
|
||||
|
||||
// Validator indicates if this type implements the Validator interface.
|
||||
func (t TypeInfo) Validator() bool {
|
||||
return t.RType.Implements(validatorType)
|
||||
}
|
||||
|
||||
// Valuer indicates if this type implements the driver.Valuer interface.
|
||||
func (t TypeInfo) Valuer() bool {
|
||||
return t.RType.Implements(valuerType)
|
||||
}
|
||||
|
||||
// Comparable reports whether values of this type are comparable.
|
||||
func (t TypeInfo) Comparable() bool {
|
||||
switch t.Type {
|
||||
case TypeBool, TypeTime, TypeUUID, TypeEnum, TypeString:
|
||||
return true
|
||||
case TypeOther:
|
||||
// Always accept custom types as comparable on the database side.
|
||||
// In the future, we should consider adding an interface to let
|
||||
// custom types tell if they are comparable or not (see #1304).
|
||||
return true
|
||||
default:
|
||||
return t.Numeric()
|
||||
}
|
||||
}
|
||||
|
||||
var stringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
|
||||
// Stringer indicates if this type implements the Stringer interface.
|
||||
func (t TypeInfo) Stringer() bool {
|
||||
return t.RType.Implements(stringerType)
|
||||
}
|
||||
|
||||
var (
|
||||
typeNames = [...]string{
|
||||
TypeInvalid: "invalid",
|
||||
TypeBool: "bool",
|
||||
TypeTime: "time.Time",
|
||||
TypeJSON: "json.RawMessage",
|
||||
TypeUUID: "[16]byte",
|
||||
TypeBytes: "[]byte",
|
||||
TypeEnum: "string",
|
||||
TypeString: "string",
|
||||
TypeOther: "other",
|
||||
TypeBlob: "blob",
|
||||
TypeInt: "int",
|
||||
TypeInt8: "int8",
|
||||
TypeInt16: "int16",
|
||||
TypeInt32: "int32",
|
||||
TypeInt64: "int64",
|
||||
TypeUint: "uint",
|
||||
TypeUint8: "uint8",
|
||||
TypeUint16: "uint16",
|
||||
TypeUint32: "uint32",
|
||||
TypeUint64: "uint64",
|
||||
TypeFloat32: "float32",
|
||||
TypeFloat64: "float64",
|
||||
}
|
||||
constNames = [...]string{
|
||||
TypeJSON: "TypeJSON",
|
||||
TypeUUID: "TypeUUID",
|
||||
TypeTime: "TypeTime",
|
||||
TypeEnum: "TypeEnum",
|
||||
TypeBytes: "TypeBytes",
|
||||
TypeOther: "TypeOther",
|
||||
TypeBlob: "TypeBlob",
|
||||
}
|
||||
)
|
||||
|
||||
// RType holds a serializable reflect.Type information of
|
||||
// Go object. Used by the entc package.
|
||||
type RType struct {
|
||||
Name string // reflect.Type.Name
|
||||
Ident string // reflect.Type.String
|
||||
Kind reflect.Kind
|
||||
PkgPath string
|
||||
Methods map[string]struct{ In, Out []*RType }
|
||||
// Used only for in-package checks.
|
||||
rtype reflect.Type
|
||||
}
|
||||
|
||||
// TypeEqual reports if the underlying type is equal to the RType (after pointer indirections).
|
||||
func (r *RType) TypeEqual(t reflect.Type) bool {
|
||||
tv := indirect(t)
|
||||
return r.Name == tv.Name() && r.Kind == t.Kind() && r.PkgPath == tv.PkgPath()
|
||||
}
|
||||
|
||||
// RType returns the string value of the indirect reflect.Type.
|
||||
func (r *RType) String() string {
|
||||
if r.rtype != nil {
|
||||
return r.rtype.String()
|
||||
}
|
||||
return r.Ident
|
||||
}
|
||||
|
||||
// IsPtr reports if the reflect-type is a pointer type.
|
||||
func (r *RType) IsPtr() bool {
|
||||
return r != nil && r.Kind == reflect.Ptr
|
||||
}
|
||||
|
||||
// Implements reports whether the RType ~implements the given interface type.
|
||||
func (r *RType) Implements(typ reflect.Type) bool {
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
n := typ.NumMethod()
|
||||
for i := 0; i < n; i++ {
|
||||
m0 := typ.Method(i)
|
||||
m1, ok := r.Methods[m0.Name]
|
||||
if !ok || len(m1.In) != m0.Type.NumIn() || len(m1.Out) != m0.Type.NumOut() {
|
||||
return false
|
||||
}
|
||||
in := m0.Type.NumIn()
|
||||
for j := 0; j < in; j++ {
|
||||
if !m1.In[j].TypeEqual(m0.Type.In(j)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
out := m0.Type.NumOut()
|
||||
for j := 0; j < out; j++ {
|
||||
if !m1.Out[j].TypeEqual(m0.Type.Out(j)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user