From 009b396d7ef57b3fe29c67a4e231cf78db1f75c8 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:59:59 +0300 Subject: [PATCH] schema/field: allow setting time fields as unique (#4220) * schema/field: allow setting time fields as unique * .github: goodbye crate-ci/typos --- .github/workflows/ci.yml | 12 ---- .github/workflows/typos.toml | 15 ---- entc/integration/ent/entql.go | 20 ++++-- entc/integration/ent/file.go | 14 ++++ entc/integration/ent/file/file.go | 8 +++ entc/integration/ent/file/where.go | 57 +++++++++++++++ entc/integration/ent/file_create.go | 79 +++++++++++++++++++++ entc/integration/ent/file_update.go | 53 ++++++++++++++ entc/integration/ent/migrate/schema.go | 13 ++-- entc/integration/ent/mutation.go | 75 ++++++++++++++++++- entc/integration/ent/schema/file.go | 3 + entc/integration/gremlin/ent/file.go | 42 ++++++----- entc/integration/gremlin/ent/file/file.go | 2 + entc/integration/gremlin/ent/file/where.go | 79 +++++++++++++++++++++ entc/integration/gremlin/ent/file_create.go | 24 ++++++- entc/integration/gremlin/ent/file_update.go | 65 ++++++++++++++++- entc/integration/gremlin/ent/mutation.go | 75 ++++++++++++++++++- entc/integration/integration_test.go | 9 +++ schema/field/field.go | 6 ++ 19 files changed, 590 insertions(+), 61 deletions(-) delete mode 100644 .github/workflows/typos.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8497d96e..f301644e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,18 +10,6 @@ on: - 'doc/**' jobs: - typos-check: - name: Spell Check with Typos - runs-on: ubuntu-latest - steps: - - name: Checkout Actions Repository - uses: actions/checkout@v4 - - name: Check spelling with custom config file - uses: crate-ci/typos@v1.24.5 - with: - config: .github/workflows/typos.toml - - lint: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/typos.toml b/.github/workflows/typos.toml deleted file mode 100644 index b2e419f58..000000000 --- a/.github/workflows/typos.toml +++ /dev/null @@ -1,15 +0,0 @@ -# See https://github.com/crate-ci/typos/blob/master/docs/reference.md to configure typos -[default.extend-words] -ba = "ba" -importent = "importent" -mis = "mis" -nd = "nd" -ons = "ons" -ser = "ser" -ue = "ue" -udo = "udo" -leafs = "leafs" -hax = "hax" -[files] -extend-exclude = [] - diff --git a/entc/integration/ent/entql.go b/entc/integration/ent/entql.go index c04019fa0..e4596d8b1 100644 --- a/entc/integration/ent/entql.go +++ b/entc/integration/ent/entql.go @@ -208,13 +208,14 @@ var schemaGraph = func() *sqlgraph.Schema { }, Type: "File", Fields: map[string]*sqlgraph.FieldSpec{ - file.FieldSetID: {Type: field.TypeInt, Column: file.FieldSetID}, - file.FieldSize: {Type: field.TypeInt, Column: file.FieldSize}, - file.FieldName: {Type: field.TypeString, Column: file.FieldName}, - file.FieldUser: {Type: field.TypeString, Column: file.FieldUser}, - file.FieldGroup: {Type: field.TypeString, Column: file.FieldGroup}, - file.FieldOp: {Type: field.TypeBool, Column: file.FieldOp}, - file.FieldFieldID: {Type: field.TypeInt, Column: file.FieldFieldID}, + file.FieldSetID: {Type: field.TypeInt, Column: file.FieldSetID}, + file.FieldSize: {Type: field.TypeInt, Column: file.FieldSize}, + file.FieldName: {Type: field.TypeString, Column: file.FieldName}, + file.FieldUser: {Type: field.TypeString, Column: file.FieldUser}, + file.FieldGroup: {Type: field.TypeString, Column: file.FieldGroup}, + file.FieldOp: {Type: field.TypeBool, Column: file.FieldOp}, + file.FieldFieldID: {Type: field.TypeInt, Column: file.FieldFieldID}, + file.FieldCreateTime: {Type: field.TypeTime, Column: file.FieldCreateTime}, }, } graph.Nodes[7] = &sqlgraph.Node{ @@ -1506,6 +1507,11 @@ func (f *FileFilter) WhereFieldID(p entql.IntP) { f.Where(p.Field(file.FieldFieldID)) } +// WhereCreateTime applies the entql time.Time predicate on the create_time field. +func (f *FileFilter) WhereCreateTime(p entql.TimeP) { + f.Where(p.Field(file.FieldCreateTime)) +} + // WhereHasOwner applies a predicate to check if query has an edge owner. func (f *FileFilter) WhereHasOwner() { f.Where(entql.HasEdge("owner")) diff --git a/entc/integration/ent/file.go b/entc/integration/ent/file.go index adf63d486..a599f826e 100644 --- a/entc/integration/ent/file.go +++ b/entc/integration/ent/file.go @@ -9,6 +9,7 @@ package ent import ( "fmt" "strings" + "time" "entgo.io/ent" "entgo.io/ent/dialect/sql" @@ -36,6 +37,8 @@ type File struct { Op bool `json:"op,omitempty"` // FieldID holds the value of the "field_id" field. FieldID int `json:"field_id,omitempty"` + // CreateTime holds the value of the "create_time" field. + CreateTime time.Time `json:"create_time,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the FileQuery when eager-loading is set. Edges FileEdges `json:"file_edges"` @@ -101,6 +104,8 @@ func (*File) scanValues(columns []string) ([]any, error) { values[i] = new(sql.NullInt64) case file.FieldName, file.FieldUser, file.FieldGroup: values[i] = new(sql.NullString) + case file.FieldCreateTime: + values[i] = new(sql.NullTime) case file.ForeignKeys[0]: // file_type_files values[i] = new(sql.NullInt64) case file.ForeignKeys[1]: // group_files @@ -171,6 +176,12 @@ func (f *File) assignValues(columns []string, values []any) error { } else if value.Valid { f.FieldID = int(value.Int64) } + case file.FieldCreateTime: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field create_time", values[i]) + } else if value.Valid { + f.CreateTime = value.Time + } case file.ForeignKeys[0]: if value, ok := values[i].(*sql.NullInt64); !ok { return fmt.Errorf("unexpected type %T for edge-field file_type_files", value) @@ -265,6 +276,9 @@ func (f *File) String() string { builder.WriteString(", ") builder.WriteString("field_id=") builder.WriteString(fmt.Sprintf("%v", f.FieldID)) + builder.WriteString(", ") + builder.WriteString("create_time=") + builder.WriteString(f.CreateTime.Format(time.ANSIC)) builder.WriteByte(')') return builder.String() } diff --git a/entc/integration/ent/file/file.go b/entc/integration/ent/file/file.go index e9f52a742..731a1dc82 100644 --- a/entc/integration/ent/file/file.go +++ b/entc/integration/ent/file/file.go @@ -30,6 +30,8 @@ const ( FieldOp = "op" // FieldFieldID holds the string denoting the field_id field in the database. FieldFieldID = "field_id" + // FieldCreateTime holds the string denoting the create_time field in the database. + FieldCreateTime = "create_time" // EdgeOwner holds the string denoting the owner edge name in mutations. EdgeOwner = "owner" // EdgeType holds the string denoting the type edge name in mutations. @@ -71,6 +73,7 @@ var Columns = []string{ FieldGroup, FieldOp, FieldFieldID, + FieldCreateTime, } // ForeignKeys holds the SQL foreign-keys that are owned by the "files" @@ -148,6 +151,11 @@ func ByFieldID(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldFieldID, opts...).ToFunc() } +// ByCreateTime orders the results by the create_time field. +func ByCreateTime(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreateTime, opts...).ToFunc() +} + // ByOwnerField orders the results by owner field. func ByOwnerField(field string, opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { diff --git a/entc/integration/ent/file/where.go b/entc/integration/ent/file/where.go index 43173d577..ee54b3bbb 100644 --- a/entc/integration/ent/file/where.go +++ b/entc/integration/ent/file/where.go @@ -7,6 +7,8 @@ package file import ( + "time" + "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/entc/integration/ent/predicate" @@ -87,6 +89,11 @@ func Op(v bool) predicate.File { return predicate.File(sql.FieldEQ(FieldOp, v)) } +// CreateTime applies equality check predicate on the "create_time" field. It's identical to CreateTimeEQ. +func CreateTime(v time.Time) predicate.File { + return predicate.File(sql.FieldEQ(FieldCreateTime, v)) +} + // SetIDEQ applies the EQ predicate on the "set_id" field. func SetIDEQ(v int) predicate.File { return predicate.File(sql.FieldEQ(FieldSetID, v)) @@ -462,6 +469,56 @@ func FieldIDNotNil() predicate.File { return predicate.File(sql.FieldNotNull(FieldFieldID)) } +// CreateTimeEQ applies the EQ predicate on the "create_time" field. +func CreateTimeEQ(v time.Time) predicate.File { + return predicate.File(sql.FieldEQ(FieldCreateTime, v)) +} + +// CreateTimeNEQ applies the NEQ predicate on the "create_time" field. +func CreateTimeNEQ(v time.Time) predicate.File { + return predicate.File(sql.FieldNEQ(FieldCreateTime, v)) +} + +// CreateTimeIn applies the In predicate on the "create_time" field. +func CreateTimeIn(vs ...time.Time) predicate.File { + return predicate.File(sql.FieldIn(FieldCreateTime, vs...)) +} + +// CreateTimeNotIn applies the NotIn predicate on the "create_time" field. +func CreateTimeNotIn(vs ...time.Time) predicate.File { + return predicate.File(sql.FieldNotIn(FieldCreateTime, vs...)) +} + +// CreateTimeGT applies the GT predicate on the "create_time" field. +func CreateTimeGT(v time.Time) predicate.File { + return predicate.File(sql.FieldGT(FieldCreateTime, v)) +} + +// CreateTimeGTE applies the GTE predicate on the "create_time" field. +func CreateTimeGTE(v time.Time) predicate.File { + return predicate.File(sql.FieldGTE(FieldCreateTime, v)) +} + +// CreateTimeLT applies the LT predicate on the "create_time" field. +func CreateTimeLT(v time.Time) predicate.File { + return predicate.File(sql.FieldLT(FieldCreateTime, v)) +} + +// CreateTimeLTE applies the LTE predicate on the "create_time" field. +func CreateTimeLTE(v time.Time) predicate.File { + return predicate.File(sql.FieldLTE(FieldCreateTime, v)) +} + +// CreateTimeIsNil applies the IsNil predicate on the "create_time" field. +func CreateTimeIsNil() predicate.File { + return predicate.File(sql.FieldIsNull(FieldCreateTime)) +} + +// CreateTimeNotNil applies the NotNil predicate on the "create_time" field. +func CreateTimeNotNil() predicate.File { + return predicate.File(sql.FieldNotNull(FieldCreateTime)) +} + // HasOwner applies the HasEdge predicate on the "owner" edge. func HasOwner() predicate.File { return predicate.File(func(s *sql.Selector) { diff --git a/entc/integration/ent/file_create.go b/entc/integration/ent/file_create.go index ebbb1d236..7e29aab35 100644 --- a/entc/integration/ent/file_create.go +++ b/entc/integration/ent/file_create.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" @@ -118,6 +119,20 @@ func (fc *FileCreate) SetNillableFieldID(i *int) *FileCreate { return fc } +// SetCreateTime sets the "create_time" field. +func (fc *FileCreate) SetCreateTime(t time.Time) *FileCreate { + fc.mutation.SetCreateTime(t) + return fc +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (fc *FileCreate) SetNillableCreateTime(t *time.Time) *FileCreate { + if t != nil { + fc.SetCreateTime(*t) + } + return fc +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (fc *FileCreate) SetOwnerID(id int) *FileCreate { fc.mutation.SetOwnerID(id) @@ -285,6 +300,10 @@ func (fc *FileCreate) createSpec() (*File, *sqlgraph.CreateSpec) { _spec.SetField(file.FieldFieldID, field.TypeInt, value) _node.FieldID = value } + if value, ok := fc.mutation.CreateTime(); ok { + _spec.SetField(file.FieldCreateTime, field.TypeTime, value) + _node.CreateTime = value + } if nodes := fc.mutation.OwnerIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -519,6 +538,24 @@ func (u *FileUpsert) ClearFieldID() *FileUpsert { return u } +// SetCreateTime sets the "create_time" field. +func (u *FileUpsert) SetCreateTime(v time.Time) *FileUpsert { + u.Set(file.FieldCreateTime, v) + return u +} + +// UpdateCreateTime sets the "create_time" field to the value that was provided on create. +func (u *FileUpsert) UpdateCreateTime() *FileUpsert { + u.SetExcluded(file.FieldCreateTime) + return u +} + +// ClearCreateTime clears the value of the "create_time" field. +func (u *FileUpsert) ClearCreateTime() *FileUpsert { + u.SetNull(file.FieldCreateTime) + return u +} + // UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // @@ -713,6 +750,27 @@ func (u *FileUpsertOne) ClearFieldID() *FileUpsertOne { }) } +// SetCreateTime sets the "create_time" field. +func (u *FileUpsertOne) SetCreateTime(v time.Time) *FileUpsertOne { + return u.Update(func(s *FileUpsert) { + s.SetCreateTime(v) + }) +} + +// UpdateCreateTime sets the "create_time" field to the value that was provided on create. +func (u *FileUpsertOne) UpdateCreateTime() *FileUpsertOne { + return u.Update(func(s *FileUpsert) { + s.UpdateCreateTime() + }) +} + +// ClearCreateTime clears the value of the "create_time" field. +func (u *FileUpsertOne) ClearCreateTime() *FileUpsertOne { + return u.Update(func(s *FileUpsert) { + s.ClearCreateTime() + }) +} + // Exec executes the query. func (u *FileUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -1071,6 +1129,27 @@ func (u *FileUpsertBulk) ClearFieldID() *FileUpsertBulk { }) } +// SetCreateTime sets the "create_time" field. +func (u *FileUpsertBulk) SetCreateTime(v time.Time) *FileUpsertBulk { + return u.Update(func(s *FileUpsert) { + s.SetCreateTime(v) + }) +} + +// UpdateCreateTime sets the "create_time" field to the value that was provided on create. +func (u *FileUpsertBulk) UpdateCreateTime() *FileUpsertBulk { + return u.Update(func(s *FileUpsert) { + s.UpdateCreateTime() + }) +} + +// ClearCreateTime clears the value of the "create_time" field. +func (u *FileUpsertBulk) ClearCreateTime() *FileUpsertBulk { + return u.Update(func(s *FileUpsert) { + s.ClearCreateTime() + }) +} + // Exec executes the query. func (u *FileUpsertBulk) Exec(ctx context.Context) error { if u.create.err != nil { diff --git a/entc/integration/ent/file_update.go b/entc/integration/ent/file_update.go index 4be792ab1..793675011 100644 --- a/entc/integration/ent/file_update.go +++ b/entc/integration/ent/file_update.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" @@ -184,6 +185,26 @@ func (fu *FileUpdate) ClearFieldID() *FileUpdate { return fu } +// SetCreateTime sets the "create_time" field. +func (fu *FileUpdate) SetCreateTime(t time.Time) *FileUpdate { + fu.mutation.SetCreateTime(t) + return fu +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (fu *FileUpdate) SetNillableCreateTime(t *time.Time) *FileUpdate { + if t != nil { + fu.SetCreateTime(*t) + } + return fu +} + +// ClearCreateTime clears the value of the "create_time" field. +func (fu *FileUpdate) ClearCreateTime() *FileUpdate { + fu.mutation.ClearCreateTime() + return fu +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (fu *FileUpdate) SetOwnerID(id int) *FileUpdate { fu.mutation.SetOwnerID(id) @@ -380,6 +401,12 @@ func (fu *FileUpdate) sqlSave(ctx context.Context) (n int, err error) { if fu.mutation.FieldIDCleared() { _spec.ClearField(file.FieldFieldID, field.TypeInt) } + if value, ok := fu.mutation.CreateTime(); ok { + _spec.SetField(file.FieldCreateTime, field.TypeTime, value) + } + if fu.mutation.CreateTimeCleared() { + _spec.ClearField(file.FieldCreateTime, field.TypeTime) + } if fu.mutation.OwnerCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -654,6 +681,26 @@ func (fuo *FileUpdateOne) ClearFieldID() *FileUpdateOne { return fuo } +// SetCreateTime sets the "create_time" field. +func (fuo *FileUpdateOne) SetCreateTime(t time.Time) *FileUpdateOne { + fuo.mutation.SetCreateTime(t) + return fuo +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (fuo *FileUpdateOne) SetNillableCreateTime(t *time.Time) *FileUpdateOne { + if t != nil { + fuo.SetCreateTime(*t) + } + return fuo +} + +// ClearCreateTime clears the value of the "create_time" field. +func (fuo *FileUpdateOne) ClearCreateTime() *FileUpdateOne { + fuo.mutation.ClearCreateTime() + return fuo +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (fuo *FileUpdateOne) SetOwnerID(id int) *FileUpdateOne { fuo.mutation.SetOwnerID(id) @@ -880,6 +927,12 @@ func (fuo *FileUpdateOne) sqlSave(ctx context.Context) (_node *File, err error) if fuo.mutation.FieldIDCleared() { _spec.ClearField(file.FieldFieldID, field.TypeInt) } + if value, ok := fuo.mutation.CreateTime(); ok { + _spec.SetField(file.FieldCreateTime, field.TypeTime, value) + } + if fuo.mutation.CreateTimeCleared() { + _spec.ClearField(file.FieldCreateTime, field.TypeTime) + } if fuo.mutation.OwnerCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, diff --git a/entc/integration/ent/migrate/schema.go b/entc/integration/ent/migrate/schema.go index 24f965678..8405755e6 100644 --- a/entc/integration/ent/migrate/schema.go +++ b/entc/integration/ent/migrate/schema.go @@ -202,6 +202,7 @@ var ( {Name: "group", Type: field.TypeString, Nullable: true}, {Name: "op", Type: field.TypeBool, Nullable: true}, {Name: "field_id", Type: field.TypeInt, Nullable: true}, + {Name: "create_time", Type: field.TypeTime, Unique: true, Nullable: true}, {Name: "file_type_files", Type: field.TypeInt, Nullable: true}, {Name: "group_files", Type: field.TypeInt, Nullable: true}, {Name: "user_files", Type: field.TypeInt, Nullable: true}, @@ -214,19 +215,19 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "files_file_types_files", - Columns: []*schema.Column{FilesColumns[8]}, + Columns: []*schema.Column{FilesColumns[9]}, RefColumns: []*schema.Column{FileTypesColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "files_groups_files", - Columns: []*schema.Column{FilesColumns[9]}, + Columns: []*schema.Column{FilesColumns[10]}, RefColumns: []*schema.Column{GroupsColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "files_users_files", - Columns: []*schema.Column{FilesColumns[10]}, + Columns: []*schema.Column{FilesColumns[11]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.SetNull, }, @@ -245,17 +246,17 @@ var ( { Name: "file_user_files_file_type_files", Unique: false, - Columns: []*schema.Column{FilesColumns[10], FilesColumns[8]}, + Columns: []*schema.Column{FilesColumns[11], FilesColumns[9]}, }, { Name: "file_name_user_files_file_type_files", Unique: true, - Columns: []*schema.Column{FilesColumns[3], FilesColumns[10], FilesColumns[8]}, + Columns: []*schema.Column{FilesColumns[3], FilesColumns[11], FilesColumns[9]}, }, { Name: "file_name_user_files", Unique: false, - Columns: []*schema.Column{FilesColumns[3], FilesColumns[10]}, + Columns: []*schema.Column{FilesColumns[3], FilesColumns[11]}, }, }, } diff --git a/entc/integration/ent/mutation.go b/entc/integration/ent/mutation.go index 7c2a9f8d4..64d7f424c 100644 --- a/entc/integration/ent/mutation.go +++ b/entc/integration/ent/mutation.go @@ -8809,6 +8809,7 @@ type FileMutation struct { _op *bool field_id *int addfield_id *int + create_time *time.Time clearedFields map[string]struct{} owner *int clearedowner bool @@ -9299,6 +9300,55 @@ func (m *FileMutation) ResetFieldID() { delete(m.clearedFields, file.FieldFieldID) } +// SetCreateTime sets the "create_time" field. +func (m *FileMutation) SetCreateTime(t time.Time) { + m.create_time = &t +} + +// CreateTime returns the value of the "create_time" field in the mutation. +func (m *FileMutation) CreateTime() (r time.Time, exists bool) { + v := m.create_time + if v == nil { + return + } + return *v, true +} + +// OldCreateTime returns the old "create_time" field's value of the File entity. +// If the File object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *FileMutation) OldCreateTime(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreateTime is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreateTime requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreateTime: %w", err) + } + return oldValue.CreateTime, nil +} + +// ClearCreateTime clears the value of the "create_time" field. +func (m *FileMutation) ClearCreateTime() { + m.create_time = nil + m.clearedFields[file.FieldCreateTime] = struct{}{} +} + +// CreateTimeCleared returns if the "create_time" field was cleared in this mutation. +func (m *FileMutation) CreateTimeCleared() bool { + _, ok := m.clearedFields[file.FieldCreateTime] + return ok +} + +// ResetCreateTime resets all changes to the "create_time" field. +func (m *FileMutation) ResetCreateTime() { + m.create_time = nil + delete(m.clearedFields, file.FieldCreateTime) +} + // SetOwnerID sets the "owner" edge to the User entity by id. func (m *FileMutation) SetOwnerID(id int) { m.owner = &id @@ -9465,7 +9515,7 @@ func (m *FileMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *FileMutation) Fields() []string { - fields := make([]string, 0, 7) + fields := make([]string, 0, 8) if m.set_id != nil { fields = append(fields, file.FieldSetID) } @@ -9487,6 +9537,9 @@ func (m *FileMutation) Fields() []string { if m.field_id != nil { fields = append(fields, file.FieldFieldID) } + if m.create_time != nil { + fields = append(fields, file.FieldCreateTime) + } return fields } @@ -9509,6 +9562,8 @@ func (m *FileMutation) Field(name string) (ent.Value, bool) { return m.GetOp() case file.FieldFieldID: return m.FieldID() + case file.FieldCreateTime: + return m.CreateTime() } return nil, false } @@ -9532,6 +9587,8 @@ func (m *FileMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldOp(ctx) case file.FieldFieldID: return m.OldFieldID(ctx) + case file.FieldCreateTime: + return m.OldCreateTime(ctx) } return nil, fmt.Errorf("unknown File field %s", name) } @@ -9590,6 +9647,13 @@ func (m *FileMutation) SetField(name string, value ent.Value) error { } m.SetFieldID(v) return nil + case file.FieldCreateTime: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreateTime(v) + return nil } return fmt.Errorf("unknown File field %s", name) } @@ -9674,6 +9738,9 @@ func (m *FileMutation) ClearedFields() []string { if m.FieldCleared(file.FieldFieldID) { fields = append(fields, file.FieldFieldID) } + if m.FieldCleared(file.FieldCreateTime) { + fields = append(fields, file.FieldCreateTime) + } return fields } @@ -9703,6 +9770,9 @@ func (m *FileMutation) ClearField(name string) error { case file.FieldFieldID: m.ClearFieldID() return nil + case file.FieldCreateTime: + m.ClearCreateTime() + return nil } return fmt.Errorf("unknown File nullable field %s", name) } @@ -9732,6 +9802,9 @@ func (m *FileMutation) ResetField(name string) error { case file.FieldFieldID: m.ResetFieldID() return nil + case file.FieldCreateTime: + m.ResetCreateTime() + return nil } return fmt.Errorf("unknown File field %s", name) } diff --git a/entc/integration/ent/schema/file.go b/entc/integration/ent/schema/file.go index b306ce693..e64832648 100644 --- a/entc/integration/ent/schema/file.go +++ b/entc/integration/ent/schema/file.go @@ -49,6 +49,9 @@ func (File) Fields() []ent.Field { // as it conflicts with the "FieldID" constant. field.Int("field_id"). Optional(), + field.Time("create_time"). + Optional(). + Unique(), } } diff --git a/entc/integration/gremlin/ent/file.go b/entc/integration/gremlin/ent/file.go index 9d13e48c0..45bf5fba8 100644 --- a/entc/integration/gremlin/ent/file.go +++ b/entc/integration/gremlin/ent/file.go @@ -9,6 +9,7 @@ package ent import ( "fmt" "strings" + "time" "entgo.io/ent/dialect/gremlin" "entgo.io/ent/entc/integration/gremlin/ent/filetype" @@ -34,6 +35,8 @@ type File struct { Op bool `json:"op,omitempty"` // FieldID holds the value of the "field_id" field. FieldID int `json:"field_id,omitempty"` + // CreateTime holds the value of the "create_time" field. + CreateTime time.Time `json:"create_time,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the FileQuery when eager-loading is set. Edges FileEdges `json:"file_edges"` @@ -90,14 +93,15 @@ func (f *File) FromResponse(res *gremlin.Response) error { return err } var scanf struct { - ID string `json:"id,omitempty"` - SetID int `json:"set_id,omitempty"` - Size int `json:"fsize,omitempty"` - Name string `json:"name,omitempty"` - User *string `json:"user,omitempty"` - Group string `json:"group,omitempty"` - Op bool `json:"op,omitempty"` - FieldID int `json:"field_id,omitempty"` + ID string `json:"id,omitempty"` + SetID int `json:"set_id,omitempty"` + Size int `json:"fsize,omitempty"` + Name string `json:"name,omitempty"` + User *string `json:"user,omitempty"` + Group string `json:"group,omitempty"` + Op bool `json:"op,omitempty"` + FieldID int `json:"field_id,omitempty"` + CreateTime int64 `json:"create_time,omitempty"` } if err := vmap.Decode(&scanf); err != nil { return err @@ -110,6 +114,7 @@ func (f *File) FromResponse(res *gremlin.Response) error { f.Group = scanf.Group f.Op = scanf.Op f.FieldID = scanf.FieldID + f.CreateTime = time.Unix(0, scanf.CreateTime) return nil } @@ -173,6 +178,9 @@ func (f *File) String() string { builder.WriteString(", ") builder.WriteString("field_id=") builder.WriteString(fmt.Sprintf("%v", f.FieldID)) + builder.WriteString(", ") + builder.WriteString("create_time=") + builder.WriteString(f.CreateTime.Format(time.ANSIC)) builder.WriteByte(')') return builder.String() } @@ -187,14 +195,15 @@ func (f *Files) FromResponse(res *gremlin.Response) error { return err } var scanf []struct { - ID string `json:"id,omitempty"` - SetID int `json:"set_id,omitempty"` - Size int `json:"fsize,omitempty"` - Name string `json:"name,omitempty"` - User *string `json:"user,omitempty"` - Group string `json:"group,omitempty"` - Op bool `json:"op,omitempty"` - FieldID int `json:"field_id,omitempty"` + ID string `json:"id,omitempty"` + SetID int `json:"set_id,omitempty"` + Size int `json:"fsize,omitempty"` + Name string `json:"name,omitempty"` + User *string `json:"user,omitempty"` + Group string `json:"group,omitempty"` + Op bool `json:"op,omitempty"` + FieldID int `json:"field_id,omitempty"` + CreateTime int64 `json:"create_time,omitempty"` } if err := vmap.Decode(&scanf); err != nil { return err @@ -208,6 +217,7 @@ func (f *Files) FromResponse(res *gremlin.Response) error { node.Group = v.Group node.Op = v.Op node.FieldID = v.FieldID + node.CreateTime = time.Unix(0, v.CreateTime) *f = append(*f, node) } return nil diff --git a/entc/integration/gremlin/ent/file/file.go b/entc/integration/gremlin/ent/file/file.go index 2ec1c2974..d1652d734 100644 --- a/entc/integration/gremlin/ent/file/file.go +++ b/entc/integration/gremlin/ent/file/file.go @@ -29,6 +29,8 @@ const ( FieldOp = "op" // FieldFieldID holds the string denoting the field_id field in the database. FieldFieldID = "field_id" + // FieldCreateTime holds the string denoting the create_time field in the database. + FieldCreateTime = "create_time" // EdgeOwner holds the string denoting the owner edge name in mutations. EdgeOwner = "owner" // EdgeType holds the string denoting the type edge name in mutations. diff --git a/entc/integration/gremlin/ent/file/where.go b/entc/integration/gremlin/ent/file/where.go index e85251659..98ba0a749 100644 --- a/entc/integration/gremlin/ent/file/where.go +++ b/entc/integration/gremlin/ent/file/where.go @@ -7,6 +7,8 @@ package file import ( + "time" + "entgo.io/ent/dialect/gremlin/graph/dsl" "entgo.io/ent/dialect/gremlin/graph/dsl/__" "entgo.io/ent/dialect/gremlin/graph/dsl/p" @@ -126,6 +128,13 @@ func Op(v bool) predicate.File { }) } +// CreateTime applies equality check predicate on the "create_time" field. It's identical to CreateTimeEQ. +func CreateTime(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.EQ(v)) + }) +} + // SetIDEQ applies the EQ predicate on the "set_id" field. func SetIDEQ(v int) predicate.File { return predicate.File(func(t *dsl.Traversal) { @@ -609,6 +618,76 @@ func FieldIDNotNil() predicate.File { }) } +// CreateTimeEQ applies the EQ predicate on the "create_time" field. +func CreateTimeEQ(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.EQ(v)) + }) +} + +// CreateTimeNEQ applies the NEQ predicate on the "create_time" field. +func CreateTimeNEQ(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.NEQ(v)) + }) +} + +// CreateTimeIn applies the In predicate on the "create_time" field. +func CreateTimeIn(vs ...time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.Within(vs...)) + }) +} + +// CreateTimeNotIn applies the NotIn predicate on the "create_time" field. +func CreateTimeNotIn(vs ...time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.Without(vs...)) + }) +} + +// CreateTimeGT applies the GT predicate on the "create_time" field. +func CreateTimeGT(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.GT(v)) + }) +} + +// CreateTimeGTE applies the GTE predicate on the "create_time" field. +func CreateTimeGTE(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.GTE(v)) + }) +} + +// CreateTimeLT applies the LT predicate on the "create_time" field. +func CreateTimeLT(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.LT(v)) + }) +} + +// CreateTimeLTE applies the LTE predicate on the "create_time" field. +func CreateTimeLTE(v time.Time) predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.Has(Label, FieldCreateTime, p.LTE(v)) + }) +} + +// CreateTimeIsNil applies the IsNil predicate on the "create_time" field. +func CreateTimeIsNil() predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.HasLabel(Label).HasNot(FieldCreateTime) + }) +} + +// CreateTimeNotNil applies the NotNil predicate on the "create_time" field. +func CreateTimeNotNil() predicate.File { + return predicate.File(func(t *dsl.Traversal) { + t.HasLabel(Label).Has(FieldCreateTime) + }) +} + // HasOwner applies the HasEdge predicate on the "owner" edge. func HasOwner() predicate.File { return predicate.File(func(t *dsl.Traversal) { diff --git a/entc/integration/gremlin/ent/file_create.go b/entc/integration/gremlin/ent/file_create.go index 8d84737df..7551121d6 100644 --- a/entc/integration/gremlin/ent/file_create.go +++ b/entc/integration/gremlin/ent/file_create.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "entgo.io/ent/dialect/gremlin" "entgo.io/ent/dialect/gremlin/graph/dsl" @@ -118,6 +119,20 @@ func (fc *FileCreate) SetNillableFieldID(i *int) *FileCreate { return fc } +// SetCreateTime sets the "create_time" field. +func (fc *FileCreate) SetCreateTime(t time.Time) *FileCreate { + fc.mutation.SetCreateTime(t) + return fc +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (fc *FileCreate) SetNillableCreateTime(t *time.Time) *FileCreate { + if t != nil { + fc.SetCreateTime(*t) + } + return fc +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (fc *FileCreate) SetOwnerID(id string) *FileCreate { fc.mutation.SetOwnerID(id) @@ -259,7 +274,7 @@ func (fc *FileCreate) gremlin() *dsl.Traversal { pred *dsl.Traversal // constraint predicate. test *dsl.Traversal // test matches and its constant. } - constraints := make([]*constraint, 0, 1) + constraints := make([]*constraint, 0, 2) v := g.AddV(file.Label) if value, ok := fc.mutation.SetID(); ok { v.Property(dsl.Single, file.FieldSetID, value) @@ -282,6 +297,13 @@ func (fc *FileCreate) gremlin() *dsl.Traversal { if value, ok := fc.mutation.FieldID(); ok { v.Property(dsl.Single, file.FieldFieldID, value) } + if value, ok := fc.mutation.CreateTime(); ok { + constraints = append(constraints, &constraint{ + pred: g.V().Has(file.Label, file.FieldCreateTime, value).Count(), + test: __.Is(p.NEQ(0)).Constant(NewErrUniqueField(file.Label, file.FieldCreateTime, value)), + }) + v.Property(dsl.Single, file.FieldCreateTime, value) + } for _, id := range fc.mutation.OwnerIDs() { v.AddE(user.FilesLabel).From(g.V(id)).InV() } diff --git a/entc/integration/gremlin/ent/file_update.go b/entc/integration/gremlin/ent/file_update.go index c0c4d1d41..6ceee443b 100644 --- a/entc/integration/gremlin/ent/file_update.go +++ b/entc/integration/gremlin/ent/file_update.go @@ -10,6 +10,7 @@ import ( "context" "errors" "fmt" + "time" "entgo.io/ent/dialect/gremlin" "entgo.io/ent/dialect/gremlin/graph/dsl" @@ -184,6 +185,26 @@ func (fu *FileUpdate) ClearFieldID() *FileUpdate { return fu } +// SetCreateTime sets the "create_time" field. +func (fu *FileUpdate) SetCreateTime(t time.Time) *FileUpdate { + fu.mutation.SetCreateTime(t) + return fu +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (fu *FileUpdate) SetNillableCreateTime(t *time.Time) *FileUpdate { + if t != nil { + fu.SetCreateTime(*t) + } + return fu +} + +// ClearCreateTime clears the value of the "create_time" field. +func (fu *FileUpdate) ClearCreateTime() *FileUpdate { + fu.mutation.ClearCreateTime() + return fu +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (fu *FileUpdate) SetOwnerID(id string) *FileUpdate { fu.mutation.SetOwnerID(id) @@ -338,7 +359,7 @@ func (fu *FileUpdate) gremlin() *dsl.Traversal { pred *dsl.Traversal // constraint predicate. test *dsl.Traversal // test matches and its constant. } - constraints := make([]*constraint, 0, 1) + constraints := make([]*constraint, 0, 2) v := g.V().HasLabel(file.Label) for _, p := range fu.mutation.predicates { p(v) @@ -379,6 +400,13 @@ func (fu *FileUpdate) gremlin() *dsl.Traversal { if value, ok := fu.mutation.AddedFieldID(); ok { v.Property(dsl.Single, file.FieldFieldID, __.Union(__.Values(file.FieldFieldID), __.Constant(value)).Sum()) } + if value, ok := fu.mutation.CreateTime(); ok { + constraints = append(constraints, &constraint{ + pred: g.V().Has(file.Label, file.FieldCreateTime, value).Count(), + test: __.Is(p.NEQ(0)).Constant(NewErrUniqueField(file.Label, file.FieldCreateTime, value)), + }) + v.Property(dsl.Single, file.FieldCreateTime, value) + } var properties []any if fu.mutation.SetIDCleared() { properties = append(properties, file.FieldSetID) @@ -395,6 +423,9 @@ func (fu *FileUpdate) gremlin() *dsl.Traversal { if fu.mutation.FieldIDCleared() { properties = append(properties, file.FieldFieldID) } + if fu.mutation.CreateTimeCleared() { + properties = append(properties, file.FieldCreateTime) + } if len(properties) > 0 { v.SideEffect(__.Properties(properties...).Drop()) } @@ -595,6 +626,26 @@ func (fuo *FileUpdateOne) ClearFieldID() *FileUpdateOne { return fuo } +// SetCreateTime sets the "create_time" field. +func (fuo *FileUpdateOne) SetCreateTime(t time.Time) *FileUpdateOne { + fuo.mutation.SetCreateTime(t) + return fuo +} + +// SetNillableCreateTime sets the "create_time" field if the given value is not nil. +func (fuo *FileUpdateOne) SetNillableCreateTime(t *time.Time) *FileUpdateOne { + if t != nil { + fuo.SetCreateTime(*t) + } + return fuo +} + +// ClearCreateTime clears the value of the "create_time" field. +func (fuo *FileUpdateOne) ClearCreateTime() *FileUpdateOne { + fuo.mutation.ClearCreateTime() + return fuo +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (fuo *FileUpdateOne) SetOwnerID(id string) *FileUpdateOne { fuo.mutation.SetOwnerID(id) @@ -770,7 +821,7 @@ func (fuo *FileUpdateOne) gremlin(id string) *dsl.Traversal { pred *dsl.Traversal // constraint predicate. test *dsl.Traversal // test matches and its constant. } - constraints := make([]*constraint, 0, 1) + constraints := make([]*constraint, 0, 2) v := g.V(id) var ( rv = v.Clone() @@ -808,6 +859,13 @@ func (fuo *FileUpdateOne) gremlin(id string) *dsl.Traversal { if value, ok := fuo.mutation.AddedFieldID(); ok { v.Property(dsl.Single, file.FieldFieldID, __.Union(__.Values(file.FieldFieldID), __.Constant(value)).Sum()) } + if value, ok := fuo.mutation.CreateTime(); ok { + constraints = append(constraints, &constraint{ + pred: g.V().Has(file.Label, file.FieldCreateTime, value).Count(), + test: __.Is(p.NEQ(0)).Constant(NewErrUniqueField(file.Label, file.FieldCreateTime, value)), + }) + v.Property(dsl.Single, file.FieldCreateTime, value) + } var properties []any if fuo.mutation.SetIDCleared() { properties = append(properties, file.FieldSetID) @@ -824,6 +882,9 @@ func (fuo *FileUpdateOne) gremlin(id string) *dsl.Traversal { if fuo.mutation.FieldIDCleared() { properties = append(properties, file.FieldFieldID) } + if fuo.mutation.CreateTimeCleared() { + properties = append(properties, file.FieldCreateTime) + } if len(properties) > 0 { v.SideEffect(__.Properties(properties...).Drop()) } diff --git a/entc/integration/gremlin/ent/mutation.go b/entc/integration/gremlin/ent/mutation.go index c6be4782b..a60ae8dd8 100644 --- a/entc/integration/gremlin/ent/mutation.go +++ b/entc/integration/gremlin/ent/mutation.go @@ -8810,6 +8810,7 @@ type FileMutation struct { _op *bool field_id *int addfield_id *int + create_time *time.Time clearedFields map[string]struct{} owner *string clearedowner bool @@ -9300,6 +9301,55 @@ func (m *FileMutation) ResetFieldID() { delete(m.clearedFields, file.FieldFieldID) } +// SetCreateTime sets the "create_time" field. +func (m *FileMutation) SetCreateTime(t time.Time) { + m.create_time = &t +} + +// CreateTime returns the value of the "create_time" field in the mutation. +func (m *FileMutation) CreateTime() (r time.Time, exists bool) { + v := m.create_time + if v == nil { + return + } + return *v, true +} + +// OldCreateTime returns the old "create_time" field's value of the File entity. +// If the File object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *FileMutation) OldCreateTime(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldCreateTime is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldCreateTime requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreateTime: %w", err) + } + return oldValue.CreateTime, nil +} + +// ClearCreateTime clears the value of the "create_time" field. +func (m *FileMutation) ClearCreateTime() { + m.create_time = nil + m.clearedFields[file.FieldCreateTime] = struct{}{} +} + +// CreateTimeCleared returns if the "create_time" field was cleared in this mutation. +func (m *FileMutation) CreateTimeCleared() bool { + _, ok := m.clearedFields[file.FieldCreateTime] + return ok +} + +// ResetCreateTime resets all changes to the "create_time" field. +func (m *FileMutation) ResetCreateTime() { + m.create_time = nil + delete(m.clearedFields, file.FieldCreateTime) +} + // SetOwnerID sets the "owner" edge to the User entity by id. func (m *FileMutation) SetOwnerID(id string) { m.owner = &id @@ -9466,7 +9516,7 @@ func (m *FileMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *FileMutation) Fields() []string { - fields := make([]string, 0, 7) + fields := make([]string, 0, 8) if m.set_id != nil { fields = append(fields, file.FieldSetID) } @@ -9488,6 +9538,9 @@ func (m *FileMutation) Fields() []string { if m.field_id != nil { fields = append(fields, file.FieldFieldID) } + if m.create_time != nil { + fields = append(fields, file.FieldCreateTime) + } return fields } @@ -9510,6 +9563,8 @@ func (m *FileMutation) Field(name string) (ent.Value, bool) { return m.GetOp() case file.FieldFieldID: return m.FieldID() + case file.FieldCreateTime: + return m.CreateTime() } return nil, false } @@ -9533,6 +9588,8 @@ func (m *FileMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldOp(ctx) case file.FieldFieldID: return m.OldFieldID(ctx) + case file.FieldCreateTime: + return m.OldCreateTime(ctx) } return nil, fmt.Errorf("unknown File field %s", name) } @@ -9591,6 +9648,13 @@ func (m *FileMutation) SetField(name string, value ent.Value) error { } m.SetFieldID(v) return nil + case file.FieldCreateTime: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreateTime(v) + return nil } return fmt.Errorf("unknown File field %s", name) } @@ -9675,6 +9739,9 @@ func (m *FileMutation) ClearedFields() []string { if m.FieldCleared(file.FieldFieldID) { fields = append(fields, file.FieldFieldID) } + if m.FieldCleared(file.FieldCreateTime) { + fields = append(fields, file.FieldCreateTime) + } return fields } @@ -9704,6 +9771,9 @@ func (m *FileMutation) ClearField(name string) error { case file.FieldFieldID: m.ClearFieldID() return nil + case file.FieldCreateTime: + m.ClearCreateTime() + return nil } return fmt.Errorf("unknown File nullable field %s", name) } @@ -9733,6 +9803,9 @@ func (m *FileMutation) ResetField(name string) error { case file.FieldFieldID: m.ResetFieldID() return nil + case file.FieldCreateTime: + m.ResetCreateTime() + return nil } return fmt.Errorf("unknown File field %s", name) } diff --git a/entc/integration/integration_test.go b/entc/integration/integration_test.go index a89ab5658..ebadf893c 100644 --- a/entc/integration/integration_test.go +++ b/entc/integration/integration_test.go @@ -1599,6 +1599,15 @@ func UniqueConstraint(t *testing.T, client *ent.Client) { require.Error(err) err = cm1.Update().SetUniqueFloat(math.E).Exec(ctx) require.Error(err) + + t.Log("unique constraint on time fields") + now := time.Now() + client.File.Create().SetName("a").SetSize(10).SetCreateTime(now).ExecX(ctx) + err = client.File.Create().SetName("b").SetSize(20).SetCreateTime(now).Exec(ctx) + require.Error(err) + require.True(ent.IsConstraintError(err)) + now = now.Add(time.Second) + client.File.Create().SetName("b").SetSize(20).SetCreateTime(now).ExecX(ctx) } type mocker struct{ mock.Mock } diff --git a/schema/field/field.go b/schema/field/field.go index f70ea3f3b..07ce08095 100644 --- a/schema/field/field.go +++ b/schema/field/field.go @@ -477,6 +477,12 @@ func (b *timeBuilder) Deprecated(reason ...string) *timeBuilder { return b } +// Unique makes the field unique within all vertices of this type. +func (b *timeBuilder) Unique() *timeBuilder { + b.desc.Unique = true + return b +} + // Descriptor implements the ent.Field interface by returning its descriptor. func (b *timeBuilder) Descriptor() *Descriptor { if b.desc.Default != nil {