From 2e36c6569a53ca9d82a3d90bbb13e69db9b51319 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Mon, 28 Mar 2022 12:54:39 +0300 Subject: [PATCH] dialect/sql/schema: prefix sqlite unique indexes with table name (#2433) Fixed https://github.com/ent/ent/issues/2421 --- dialect/sql/schema/sqlite.go | 6 +- entc/integration/migrate/entv2/car.go | 14 +- entc/integration/migrate/entv2/car/car.go | 3 + entc/integration/migrate/entv2/car/where.go | 132 +++++++++++++ entc/integration/migrate/entv2/car_create.go | 22 +++ entc/integration/migrate/entv2/car_query.go | 24 +++ entc/integration/migrate/entv2/car_update.go | 66 +++++++ .../migrate/entv2/migrate/schema.go | 6 +- entc/integration/migrate/entv2/mutation.go | 176 +++++++++++++++++- entc/integration/migrate/entv2/pet.go | 14 +- entc/integration/migrate/entv2/pet/pet.go | 3 + entc/integration/migrate/entv2/pet/where.go | 132 +++++++++++++ entc/integration/migrate/entv2/pet_create.go | 22 +++ entc/integration/migrate/entv2/pet_query.go | 24 +++ entc/integration/migrate/entv2/pet_update.go | 66 +++++++ entc/integration/migrate/entv2/schema/user.go | 16 ++ 16 files changed, 715 insertions(+), 11 deletions(-) diff --git a/dialect/sql/schema/sqlite.go b/dialect/sql/schema/sqlite.go index 2881a75f85..ce46631bd4 100644 --- a/dialect/sql/schema/sqlite.go +++ b/dialect/sql/schema/sqlite.go @@ -408,15 +408,15 @@ func (d *SQLite) atTypeC(c1 *Column, c2 *schema.Column) error { func (d *SQLite) atUniqueC(t1 *Table, c1 *Column, t2 *schema.Table, c2 *schema.Column) { // For UNIQUE columns, SQLite create an implicit index named - // "sqlite_autoindex__". Ent uses the MySQL approach - // in its migration, and name these indexes as the columns. + // "sqlite_autoindex_
_". Ent uses the PostgreSQL approach + // in its migration, and name these indexes as "
__key". for _, idx := range t1.Indexes { // Index also defined explicitly, and will be add in atIndexes. if idx.Unique && d.atImplicitIndexName(idx, t1, c1) { return } } - t2.AddIndexes(schema.NewUniqueIndex(c1.Name).AddColumns(c2)) + t2.AddIndexes(schema.NewUniqueIndex(fmt.Sprintf("%s_%s_key", t2.Name, c1.Name)).AddColumns(c2)) } func (d *SQLite) atImplicitIndexName(idx *Index, t1 *Table, c1 *Column) bool { diff --git a/entc/integration/migrate/entv2/car.go b/entc/integration/migrate/entv2/car.go index a8c549ceec..d34c482161 100644 --- a/entc/integration/migrate/entv2/car.go +++ b/entc/integration/migrate/entv2/car.go @@ -17,9 +17,11 @@ import ( // Car is the model entity for the Car schema. type Car struct { - config + config `json:"-"` // ID of the ent. ID int `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the CarQuery when eager-loading is set. Edges CarEdges `json:"edges"` @@ -56,6 +58,8 @@ func (*Car) scanValues(columns []string) ([]interface{}, error) { switch columns[i] { case car.FieldID: values[i] = new(sql.NullInt64) + case car.FieldName: + values[i] = new(sql.NullString) case car.ForeignKeys[0]: // user_car values[i] = new(sql.NullInt64) default: @@ -79,6 +83,12 @@ func (c *Car) assignValues(columns []string, values []interface{}) error { return fmt.Errorf("unexpected type %T for field id", value) } c.ID = int(value.Int64) + case car.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + c.Name = value.String + } case car.ForeignKeys[0]: if value, ok := values[i].(*sql.NullInt64); !ok { return fmt.Errorf("unexpected type %T for edge-field user_car", value) @@ -119,6 +129,8 @@ func (c *Car) String() string { var builder strings.Builder builder.WriteString("Car(") builder.WriteString(fmt.Sprintf("id=%v", c.ID)) + builder.WriteString(", name=") + builder.WriteString(c.Name) builder.WriteByte(')') return builder.String() } diff --git a/entc/integration/migrate/entv2/car/car.go b/entc/integration/migrate/entv2/car/car.go index e2dcfe8cbc..a6c9dbb350 100644 --- a/entc/integration/migrate/entv2/car/car.go +++ b/entc/integration/migrate/entv2/car/car.go @@ -11,6 +11,8 @@ const ( Label = "car" // FieldID holds the string denoting the id field in the database. FieldID = "id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" // EdgeOwner holds the string denoting the owner edge name in mutations. EdgeOwner = "owner" // UserFieldID holds the string denoting the ID field of the User. @@ -29,6 +31,7 @@ const ( // Columns holds all SQL columns for car fields. var Columns = []string{ FieldID, + FieldName, } // ForeignKeys holds the SQL foreign-keys that are owned by the "Car" diff --git a/entc/integration/migrate/entv2/car/where.go b/entc/integration/migrate/entv2/car/where.go index 8831e6ce91..d7b7ea96cd 100644 --- a/entc/integration/migrate/entv2/car/where.go +++ b/entc/integration/migrate/entv2/car/where.go @@ -95,6 +95,138 @@ func IDLTE(id int) predicate.Car { }) } +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldName), v)) + }) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Car { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Car(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldName), v...)) + }) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Car { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Car(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldName), v...)) + }) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldName), v)) + }) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldName), v)) + }) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldName), v)) + }) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldName), v)) + }) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldName), v)) + }) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldName), v)) + }) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldName), v)) + }) +} + +// NameIsNil applies the IsNil predicate on the "name" field. +func NameIsNil() predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldName))) + }) +} + +// NameNotNil applies the NotNil predicate on the "name" field. +func NameNotNil() predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldName))) + }) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldName), v)) + }) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Car { + return predicate.Car(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldName), v)) + }) +} + // HasOwner applies the HasEdge predicate on the "owner" edge. func HasOwner() predicate.Car { return predicate.Car(func(s *sql.Selector) { diff --git a/entc/integration/migrate/entv2/car_create.go b/entc/integration/migrate/entv2/car_create.go index 7f8dc04d53..fd14b2f2e4 100644 --- a/entc/integration/migrate/entv2/car_create.go +++ b/entc/integration/migrate/entv2/car_create.go @@ -24,6 +24,20 @@ type CarCreate struct { hooks []Hook } +// SetName sets the "name" field. +func (cc *CarCreate) SetName(s string) *CarCreate { + cc.mutation.SetName(s) + return cc +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (cc *CarCreate) SetNillableName(s *string) *CarCreate { + if s != nil { + cc.SetName(*s) + } + return cc +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (cc *CarCreate) SetOwnerID(id int) *CarCreate { cc.mutation.SetOwnerID(id) @@ -135,6 +149,14 @@ func (cc *CarCreate) createSpec() (*Car, *sqlgraph.CreateSpec) { }, } ) + if value, ok := cc.mutation.Name(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: car.FieldName, + }) + _node.Name = value + } if nodes := cc.mutation.OwnerIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, diff --git a/entc/integration/migrate/entv2/car_query.go b/entc/integration/migrate/entv2/car_query.go index dae4e7be12..70dc4abbf3 100644 --- a/entc/integration/migrate/entv2/car_query.go +++ b/entc/integration/migrate/entv2/car_query.go @@ -291,6 +291,19 @@ func (cq *CarQuery) WithOwner(opts ...func(*UserQuery)) *CarQuery { // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Car.Query(). +// GroupBy(car.FieldName). +// Aggregate(entv2.Count()). +// Scan(ctx, &v) +// func (cq *CarQuery) GroupBy(field string, fields ...string) *CarGroupBy { grbuild := &CarGroupBy{config: cq.config} grbuild.fields = append([]string{field}, fields...) @@ -307,6 +320,17 @@ func (cq *CarQuery) GroupBy(field string, fields ...string) *CarGroupBy { // Select allows the selection one or more fields/columns for the given query, // instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// } +// +// client.Car.Query(). +// Select(car.FieldName). +// Scan(ctx, &v) +// func (cq *CarQuery) Select(fields ...string) *CarSelect { cq.fields = append(cq.fields, fields...) selbuild := &CarSelect{CarQuery: cq} diff --git a/entc/integration/migrate/entv2/car_update.go b/entc/integration/migrate/entv2/car_update.go index 8156e20a79..538af98443 100644 --- a/entc/integration/migrate/entv2/car_update.go +++ b/entc/integration/migrate/entv2/car_update.go @@ -32,6 +32,26 @@ func (cu *CarUpdate) Where(ps ...predicate.Car) *CarUpdate { return cu } +// SetName sets the "name" field. +func (cu *CarUpdate) SetName(s string) *CarUpdate { + cu.mutation.SetName(s) + return cu +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (cu *CarUpdate) SetNillableName(s *string) *CarUpdate { + if s != nil { + cu.SetName(*s) + } + return cu +} + +// ClearName clears the value of the "name" field. +func (cu *CarUpdate) ClearName() *CarUpdate { + cu.mutation.ClearName() + return cu +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (cu *CarUpdate) SetOwnerID(id int) *CarUpdate { cu.mutation.SetOwnerID(id) @@ -140,6 +160,19 @@ func (cu *CarUpdate) sqlSave(ctx context.Context) (n int, err error) { } } } + if value, ok := cu.mutation.Name(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: car.FieldName, + }) + } + if cu.mutation.NameCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: car.FieldName, + }) + } if cu.mutation.OwnerCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -194,6 +227,26 @@ type CarUpdateOne struct { mutation *CarMutation } +// SetName sets the "name" field. +func (cuo *CarUpdateOne) SetName(s string) *CarUpdateOne { + cuo.mutation.SetName(s) + return cuo +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (cuo *CarUpdateOne) SetNillableName(s *string) *CarUpdateOne { + if s != nil { + cuo.SetName(*s) + } + return cuo +} + +// ClearName clears the value of the "name" field. +func (cuo *CarUpdateOne) ClearName() *CarUpdateOne { + cuo.mutation.ClearName() + return cuo +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (cuo *CarUpdateOne) SetOwnerID(id int) *CarUpdateOne { cuo.mutation.SetOwnerID(id) @@ -326,6 +379,19 @@ func (cuo *CarUpdateOne) sqlSave(ctx context.Context) (_node *Car, err error) { } } } + if value, ok := cuo.mutation.Name(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: car.FieldName, + }) + } + if cuo.mutation.NameCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: car.FieldName, + }) + } if cuo.mutation.OwnerCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, diff --git a/entc/integration/migrate/entv2/migrate/schema.go b/entc/integration/migrate/entv2/migrate/schema.go index e49628fecb..5d349c257a 100644 --- a/entc/integration/migrate/entv2/migrate/schema.go +++ b/entc/integration/migrate/entv2/migrate/schema.go @@ -16,6 +16,7 @@ var ( // CarColumns holds the columns for the "Car" table. CarColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "name", Type: field.TypeString, Unique: true, Nullable: true}, {Name: "user_car", Type: field.TypeInt}, } // CarTable holds the schema information for the "Car" table. @@ -26,7 +27,7 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "Car_users_car", - Columns: []*schema.Column{CarColumns[1]}, + Columns: []*schema.Column{CarColumns[2]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.NoAction, }, @@ -108,6 +109,7 @@ var ( // PetsColumns holds the columns for the "pets" table. PetsColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "name", Type: field.TypeString, Unique: true, Nullable: true}, {Name: "owner_id", Type: field.TypeInt, Unique: true, Nullable: true}, } // PetsTable holds the schema information for the "pets" table. @@ -118,7 +120,7 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "user_pet_id", - Columns: []*schema.Column{PetsColumns[1]}, + Columns: []*schema.Column{PetsColumns[2]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.SetNull, }, diff --git a/entc/integration/migrate/entv2/mutation.go b/entc/integration/migrate/entv2/mutation.go index 455727e139..abf3e9092b 100644 --- a/entc/integration/migrate/entv2/mutation.go +++ b/entc/integration/migrate/entv2/mutation.go @@ -48,6 +48,7 @@ type CarMutation struct { op Op typ string id *int + name *string clearedFields map[string]struct{} owner *int clearedowner bool @@ -154,6 +155,55 @@ func (m *CarMutation) IDs(ctx context.Context) ([]int, error) { } } +// SetName sets the "name" field. +func (m *CarMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *CarMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the Car entity. +// If the Car 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 *CarMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ClearName clears the value of the "name" field. +func (m *CarMutation) ClearName() { + m.name = nil + m.clearedFields[car.FieldName] = struct{}{} +} + +// NameCleared returns if the "name" field was cleared in this mutation. +func (m *CarMutation) NameCleared() bool { + _, ok := m.clearedFields[car.FieldName] + return ok +} + +// ResetName resets all changes to the "name" field. +func (m *CarMutation) ResetName() { + m.name = nil + delete(m.clearedFields, car.FieldName) +} + // SetOwnerID sets the "owner" edge to the User entity by id. func (m *CarMutation) SetOwnerID(id int) { m.owner = &id @@ -212,7 +262,10 @@ func (m *CarMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *CarMutation) Fields() []string { - fields := make([]string, 0, 0) + fields := make([]string, 0, 1) + if m.name != nil { + fields = append(fields, car.FieldName) + } return fields } @@ -220,6 +273,10 @@ func (m *CarMutation) Fields() []string { // return value indicates that this field was not set, or was not defined in the // schema. func (m *CarMutation) Field(name string) (ent.Value, bool) { + switch name { + case car.FieldName: + return m.Name() + } return nil, false } @@ -227,6 +284,10 @@ func (m *CarMutation) Field(name string) (ent.Value, bool) { // returned if the mutation operation is not UpdateOne, or the query to the // database failed. func (m *CarMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case car.FieldName: + return m.OldName(ctx) + } return nil, fmt.Errorf("unknown Car field %s", name) } @@ -235,6 +296,13 @@ func (m *CarMutation) OldField(ctx context.Context, name string) (ent.Value, err // type. func (m *CarMutation) SetField(name string, value ent.Value) error { switch name { + case car.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil } return fmt.Errorf("unknown Car field %s", name) } @@ -256,13 +324,19 @@ func (m *CarMutation) AddedField(name string) (ent.Value, bool) { // the field is not defined in the schema, or if the type mismatched the field // type. func (m *CarMutation) AddField(name string, value ent.Value) error { + switch name { + } return fmt.Errorf("unknown Car numeric field %s", name) } // ClearedFields returns all nullable fields that were cleared during this // mutation. func (m *CarMutation) ClearedFields() []string { - return nil + var fields []string + if m.FieldCleared(car.FieldName) { + fields = append(fields, car.FieldName) + } + return fields } // FieldCleared returns a boolean indicating if a field with the given name was @@ -275,12 +349,22 @@ func (m *CarMutation) FieldCleared(name string) bool { // ClearField clears the value of the field with the given name. It returns an // error if the field is not defined in the schema. func (m *CarMutation) ClearField(name string) error { + switch name { + case car.FieldName: + m.ClearName() + return nil + } return fmt.Errorf("unknown Car nullable field %s", name) } // ResetField resets all changes in the mutation for the field with the given name. // It returns an error if the field is not defined in the schema. func (m *CarMutation) ResetField(name string) error { + switch name { + case car.FieldName: + m.ResetName() + return nil + } return fmt.Errorf("unknown Car field %s", name) } @@ -2344,6 +2428,7 @@ type PetMutation struct { op Op typ string id *int + name *string clearedFields map[string]struct{} owner *int clearedowner bool @@ -2450,6 +2535,55 @@ func (m *PetMutation) IDs(ctx context.Context) ([]int, error) { } } +// SetName sets the "name" field. +func (m *PetMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *PetMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the Pet entity. +// If the Pet 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 *PetMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ClearName clears the value of the "name" field. +func (m *PetMutation) ClearName() { + m.name = nil + m.clearedFields[pet.FieldName] = struct{}{} +} + +// NameCleared returns if the "name" field was cleared in this mutation. +func (m *PetMutation) NameCleared() bool { + _, ok := m.clearedFields[pet.FieldName] + return ok +} + +// ResetName resets all changes to the "name" field. +func (m *PetMutation) ResetName() { + m.name = nil + delete(m.clearedFields, pet.FieldName) +} + // SetOwnerID sets the "owner" edge to the User entity by id. func (m *PetMutation) SetOwnerID(id int) { m.owner = &id @@ -2508,7 +2642,10 @@ func (m *PetMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *PetMutation) Fields() []string { - fields := make([]string, 0, 0) + fields := make([]string, 0, 1) + if m.name != nil { + fields = append(fields, pet.FieldName) + } return fields } @@ -2516,6 +2653,10 @@ func (m *PetMutation) Fields() []string { // return value indicates that this field was not set, or was not defined in the // schema. func (m *PetMutation) Field(name string) (ent.Value, bool) { + switch name { + case pet.FieldName: + return m.Name() + } return nil, false } @@ -2523,6 +2664,10 @@ func (m *PetMutation) Field(name string) (ent.Value, bool) { // returned if the mutation operation is not UpdateOne, or the query to the // database failed. func (m *PetMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case pet.FieldName: + return m.OldName(ctx) + } return nil, fmt.Errorf("unknown Pet field %s", name) } @@ -2531,6 +2676,13 @@ func (m *PetMutation) OldField(ctx context.Context, name string) (ent.Value, err // type. func (m *PetMutation) SetField(name string, value ent.Value) error { switch name { + case pet.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil } return fmt.Errorf("unknown Pet field %s", name) } @@ -2552,13 +2704,19 @@ func (m *PetMutation) AddedField(name string) (ent.Value, bool) { // the field is not defined in the schema, or if the type mismatched the field // type. func (m *PetMutation) AddField(name string, value ent.Value) error { + switch name { + } return fmt.Errorf("unknown Pet numeric field %s", name) } // ClearedFields returns all nullable fields that were cleared during this // mutation. func (m *PetMutation) ClearedFields() []string { - return nil + var fields []string + if m.FieldCleared(pet.FieldName) { + fields = append(fields, pet.FieldName) + } + return fields } // FieldCleared returns a boolean indicating if a field with the given name was @@ -2571,12 +2729,22 @@ func (m *PetMutation) FieldCleared(name string) bool { // ClearField clears the value of the field with the given name. It returns an // error if the field is not defined in the schema. func (m *PetMutation) ClearField(name string) error { + switch name { + case pet.FieldName: + m.ClearName() + return nil + } return fmt.Errorf("unknown Pet nullable field %s", name) } // ResetField resets all changes in the mutation for the field with the given name. // It returns an error if the field is not defined in the schema. func (m *PetMutation) ResetField(name string) error { + switch name { + case pet.FieldName: + m.ResetName() + return nil + } return fmt.Errorf("unknown Pet field %s", name) } diff --git a/entc/integration/migrate/entv2/pet.go b/entc/integration/migrate/entv2/pet.go index 51b0378dc7..7269625f39 100644 --- a/entc/integration/migrate/entv2/pet.go +++ b/entc/integration/migrate/entv2/pet.go @@ -17,9 +17,11 @@ import ( // Pet is the model entity for the Pet schema. type Pet struct { - config + config `json:"-"` // ID of the ent. ID int `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the PetQuery when eager-loading is set. Edges PetEdges `json:"edges"` @@ -56,6 +58,8 @@ func (*Pet) scanValues(columns []string) ([]interface{}, error) { switch columns[i] { case pet.FieldID: values[i] = new(sql.NullInt64) + case pet.FieldName: + values[i] = new(sql.NullString) case pet.ForeignKeys[0]: // owner_id values[i] = new(sql.NullInt64) default: @@ -79,6 +83,12 @@ func (pe *Pet) assignValues(columns []string, values []interface{}) error { return fmt.Errorf("unexpected type %T for field id", value) } pe.ID = int(value.Int64) + case pet.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + pe.Name = value.String + } case pet.ForeignKeys[0]: if value, ok := values[i].(*sql.NullInt64); !ok { return fmt.Errorf("unexpected type %T for edge-field owner_id", value) @@ -119,6 +129,8 @@ func (pe *Pet) String() string { var builder strings.Builder builder.WriteString("Pet(") builder.WriteString(fmt.Sprintf("id=%v", pe.ID)) + builder.WriteString(", name=") + builder.WriteString(pe.Name) builder.WriteByte(')') return builder.String() } diff --git a/entc/integration/migrate/entv2/pet/pet.go b/entc/integration/migrate/entv2/pet/pet.go index d24b211967..b0c9ef76a2 100644 --- a/entc/integration/migrate/entv2/pet/pet.go +++ b/entc/integration/migrate/entv2/pet/pet.go @@ -11,6 +11,8 @@ const ( Label = "pet" // FieldID holds the string denoting the id field in the database. FieldID = "id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" // EdgeOwner holds the string denoting the owner edge name in mutations. EdgeOwner = "owner" // UserFieldID holds the string denoting the ID field of the User. @@ -29,6 +31,7 @@ const ( // Columns holds all SQL columns for pet fields. var Columns = []string{ FieldID, + FieldName, } // ForeignKeys holds the SQL foreign-keys that are owned by the "pets" diff --git a/entc/integration/migrate/entv2/pet/where.go b/entc/integration/migrate/entv2/pet/where.go index c9bae23641..f28093b7fc 100644 --- a/entc/integration/migrate/entv2/pet/where.go +++ b/entc/integration/migrate/entv2/pet/where.go @@ -95,6 +95,138 @@ func IDLTE(id int) predicate.Pet { }) } +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldName), v)) + }) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Pet { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Pet(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldName), v...)) + }) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Pet { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Pet(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldName), v...)) + }) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldName), v)) + }) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldName), v)) + }) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldName), v)) + }) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldName), v)) + }) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldName), v)) + }) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldName), v)) + }) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldName), v)) + }) +} + +// NameIsNil applies the IsNil predicate on the "name" field. +func NameIsNil() predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldName))) + }) +} + +// NameNotNil applies the NotNil predicate on the "name" field. +func NameNotNil() predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldName))) + }) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldName), v)) + }) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Pet { + return predicate.Pet(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldName), v)) + }) +} + // HasOwner applies the HasEdge predicate on the "owner" edge. func HasOwner() predicate.Pet { return predicate.Pet(func(s *sql.Selector) { diff --git a/entc/integration/migrate/entv2/pet_create.go b/entc/integration/migrate/entv2/pet_create.go index 9a06f85308..95f86a5a58 100644 --- a/entc/integration/migrate/entv2/pet_create.go +++ b/entc/integration/migrate/entv2/pet_create.go @@ -23,6 +23,20 @@ type PetCreate struct { hooks []Hook } +// SetName sets the "name" field. +func (pc *PetCreate) SetName(s string) *PetCreate { + pc.mutation.SetName(s) + return pc +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (pc *PetCreate) SetNillableName(s *string) *PetCreate { + if s != nil { + pc.SetName(*s) + } + return pc +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (pc *PetCreate) SetOwnerID(id int) *PetCreate { pc.mutation.SetOwnerID(id) @@ -139,6 +153,14 @@ func (pc *PetCreate) createSpec() (*Pet, *sqlgraph.CreateSpec) { }, } ) + if value, ok := pc.mutation.Name(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: pet.FieldName, + }) + _node.Name = value + } if nodes := pc.mutation.OwnerIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2O, diff --git a/entc/integration/migrate/entv2/pet_query.go b/entc/integration/migrate/entv2/pet_query.go index 7f198ce3ad..c6801d5cc1 100644 --- a/entc/integration/migrate/entv2/pet_query.go +++ b/entc/integration/migrate/entv2/pet_query.go @@ -291,6 +291,19 @@ func (pq *PetQuery) WithOwner(opts ...func(*UserQuery)) *PetQuery { // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Pet.Query(). +// GroupBy(pet.FieldName). +// Aggregate(entv2.Count()). +// Scan(ctx, &v) +// func (pq *PetQuery) GroupBy(field string, fields ...string) *PetGroupBy { grbuild := &PetGroupBy{config: pq.config} grbuild.fields = append([]string{field}, fields...) @@ -307,6 +320,17 @@ func (pq *PetQuery) GroupBy(field string, fields ...string) *PetGroupBy { // Select allows the selection one or more fields/columns for the given query, // instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// } +// +// client.Pet.Query(). +// Select(pet.FieldName). +// Scan(ctx, &v) +// func (pq *PetQuery) Select(fields ...string) *PetSelect { pq.fields = append(pq.fields, fields...) selbuild := &PetSelect{PetQuery: pq} diff --git a/entc/integration/migrate/entv2/pet_update.go b/entc/integration/migrate/entv2/pet_update.go index 86e5f2a1fd..7fcb9cbc50 100644 --- a/entc/integration/migrate/entv2/pet_update.go +++ b/entc/integration/migrate/entv2/pet_update.go @@ -32,6 +32,26 @@ func (pu *PetUpdate) Where(ps ...predicate.Pet) *PetUpdate { return pu } +// SetName sets the "name" field. +func (pu *PetUpdate) SetName(s string) *PetUpdate { + pu.mutation.SetName(s) + return pu +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (pu *PetUpdate) SetNillableName(s *string) *PetUpdate { + if s != nil { + pu.SetName(*s) + } + return pu +} + +// ClearName clears the value of the "name" field. +func (pu *PetUpdate) ClearName() *PetUpdate { + pu.mutation.ClearName() + return pu +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (pu *PetUpdate) SetOwnerID(id int) *PetUpdate { pu.mutation.SetOwnerID(id) @@ -134,6 +154,19 @@ func (pu *PetUpdate) sqlSave(ctx context.Context) (n int, err error) { } } } + if value, ok := pu.mutation.Name(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: pet.FieldName, + }) + } + if pu.mutation.NameCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: pet.FieldName, + }) + } if pu.mutation.OwnerCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2O, @@ -188,6 +221,26 @@ type PetUpdateOne struct { mutation *PetMutation } +// SetName sets the "name" field. +func (puo *PetUpdateOne) SetName(s string) *PetUpdateOne { + puo.mutation.SetName(s) + return puo +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (puo *PetUpdateOne) SetNillableName(s *string) *PetUpdateOne { + if s != nil { + puo.SetName(*s) + } + return puo +} + +// ClearName clears the value of the "name" field. +func (puo *PetUpdateOne) ClearName() *PetUpdateOne { + puo.mutation.ClearName() + return puo +} + // SetOwnerID sets the "owner" edge to the User entity by ID. func (puo *PetUpdateOne) SetOwnerID(id int) *PetUpdateOne { puo.mutation.SetOwnerID(id) @@ -314,6 +367,19 @@ func (puo *PetUpdateOne) sqlSave(ctx context.Context) (_node *Pet, err error) { } } } + if value, ok := puo.mutation.Name(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: pet.FieldName, + }) + } + if puo.mutation.NameCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: pet.FieldName, + }) + } if puo.mutation.OwnerCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2O, diff --git a/entc/integration/migrate/entv2/schema/user.go b/entc/integration/migrate/entv2/schema/user.go index 45186bdc67..08ee012050 100644 --- a/entc/integration/migrate/entv2/schema/user.go +++ b/entc/integration/migrate/entv2/schema/user.go @@ -152,6 +152,14 @@ func (Car) Annotations() []schema.Annotation { } } +func (Car) Fields() []ent.Field { + return []ent.Field{ + field.String("name"). + Optional(). + Unique(), + } +} + func (Car) Edges() []ent.Edge { return []ent.Edge{ edge.From("owner", User.Type). @@ -171,6 +179,14 @@ type Pet struct { ent.Schema } +func (Pet) Fields() []ent.Field { + return []ent.Field{ + field.String("name"). + Optional(). + Unique(), + } +} + func (Pet) Edges() []ent.Edge { return []ent.Edge{ edge.From("owner", User.Type).