diff --git a/.github/workflows/atlas-ci-public.yaml b/.github/workflows/atlas-ci-public.yaml index d180e8fc6..159294e13 100644 --- a/.github/workflows/atlas-ci-public.yaml +++ b/.github/workflows/atlas-ci-public.yaml @@ -6,10 +6,10 @@ on: branches: - master paths: - - 'examples/migration/*' + - 'examples/migration/ent/migrate/migrations/*' pull_request: paths: - - 'examples/migration/*' + - 'examples/migration/ent/migrate/migrations/*' jobs: sync: permissions: diff --git a/examples/migration/ent/migrate/migrations/20231231091550_add_pet_name.sql b/examples/migration/ent/migrate/migrations/20231231091550_add_pet_name.sql new file mode 100644 index 000000000..fff867059 --- /dev/null +++ b/examples/migration/ent/migrate/migrations/20231231091550_add_pet_name.sql @@ -0,0 +1,2 @@ +-- Modify "pets" table +ALTER TABLE `pets` ADD COLUMN `name` varchar(255) NOT NULL, ADD UNIQUE INDEX `pet_name_owner_id` (`name`, `owner_id`); diff --git a/examples/migration/ent/migrate/migrations/atlas.sum b/examples/migration/ent/migrate/migrations/atlas.sum index 424c4b383..79eb515ed 100644 --- a/examples/migration/ent/migrate/migrations/atlas.sum +++ b/examples/migration/ent/migrate/migrations/atlas.sum @@ -1,4 +1,4 @@ -h1:JP30B60y6NKcgfLaNrIknyL1n90MwyPx5CRYGzFnBLU= +h1:bWNwoQD451P0fV9kAd46VfreaOAJdrpDXYJ9xmgATtw= 20221114082343_create_users.sql h1:EeOPKbOeYUHO830P1MCXKUsxT3wLk/hSgcpT9GzlGZQ= 20221114090322_add_age.sql h1:weRCTqS5cqKyrvIjGXk7Bn24YUXo0nhLNWD0EZBcaoQ= 20221114101516_add_name.sql h1:leQgI2JN3URZyujlNzX3gI53MSiTA02MKI/G9cnMu6I= @@ -6,3 +6,4 @@ h1:JP30B60y6NKcgfLaNrIknyL1n90MwyPx5CRYGzFnBLU= 20221126185750_backfill_user_tags.sql h1:qBPBJD4ry+uwj1eGPmTr5COJwv8Sjo2o+OR7TWFj6qs= 20230101214930_default_values.sql h1:W07mGRkz22lrW0dvcChRtRc5b03Kp2CsFAQZvsnb8qs= 20231231083716_add_card_number.sql h1:sBxY6RlbqEsE8hx6Q/hSuNXfBGvVmZ0OYiZcP8uDNOc= +20231231091550_add_pet_name.sql h1:80NyHhZ/ZC4Um0j0NLzUpf1UBj4GKvMu678EqkJsFuU= diff --git a/examples/migration/ent/migrate/schema.go b/examples/migration/ent/migrate/schema.go index 3dee082d4..ebf79965f 100644 --- a/examples/migration/ent/migrate/schema.go +++ b/examples/migration/ent/migrate/schema.go @@ -36,6 +36,7 @@ var ( // PetsColumns holds the columns for the "pets" table. PetsColumns = []*schema.Column{ {Name: "id", Type: field.TypeUUID}, + {Name: "name", Type: field.TypeString}, {Name: "best_friend_id", Type: field.TypeUUID, Unique: true, Nullable: true, Default: "00000000-0000-0000-0000-000000000000"}, {Name: "owner_id", Type: field.TypeInt, Default: 0}, } @@ -47,17 +48,24 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "pets_pets_best_friend", - Columns: []*schema.Column{PetsColumns[1]}, + Columns: []*schema.Column{PetsColumns[2]}, RefColumns: []*schema.Column{PetsColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "pets_users_owner", - Columns: []*schema.Column{PetsColumns[2]}, + Columns: []*schema.Column{PetsColumns[3]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.NoAction, }, }, + Indexes: []*schema.Index{ + { + Name: "pet_name_owner_id", + Unique: true, + Columns: []*schema.Column{PetsColumns[1], PetsColumns[3]}, + }, + }, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ diff --git a/examples/migration/ent/mutation.go b/examples/migration/ent/mutation.go index 37db6ad53..269ed01ee 100644 --- a/examples/migration/ent/mutation.go +++ b/examples/migration/ent/mutation.go @@ -478,6 +478,7 @@ type PetMutation struct { op Op typ string id *uuid.UUID + name *string clearedFields map[string]struct{} best_friend *uuid.UUID clearedbest_friend bool @@ -592,6 +593,42 @@ func (m *PetMutation) IDs(ctx context.Context) ([]uuid.UUID, 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 +} + +// ResetName resets all changes to the "name" field. +func (m *PetMutation) ResetName() { + m.name = nil +} + // SetBestFriendID sets the "best_friend_id" field. func (m *PetMutation) SetBestFriendID(u uuid.UUID) { m.best_friend = &u @@ -752,7 +789,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, 2) + fields := make([]string, 0, 3) + if m.name != nil { + fields = append(fields, pet.FieldName) + } if m.best_friend != nil { fields = append(fields, pet.FieldBestFriendID) } @@ -767,6 +807,8 @@ func (m *PetMutation) Fields() []string { // schema. func (m *PetMutation) Field(name string) (ent.Value, bool) { switch name { + case pet.FieldName: + return m.Name() case pet.FieldBestFriendID: return m.BestFriendID() case pet.FieldOwnerID: @@ -780,6 +822,8 @@ func (m *PetMutation) Field(name string) (ent.Value, bool) { // database failed. func (m *PetMutation) OldField(ctx context.Context, name string) (ent.Value, error) { switch name { + case pet.FieldName: + return m.OldName(ctx) case pet.FieldBestFriendID: return m.OldBestFriendID(ctx) case pet.FieldOwnerID: @@ -793,6 +837,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 case pet.FieldBestFriendID: v, ok := value.(uuid.UUID) if !ok { @@ -859,6 +910,9 @@ func (m *PetMutation) ClearField(name string) error { // 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 case pet.FieldBestFriendID: m.ResetBestFriendID() return nil diff --git a/examples/migration/ent/pet.go b/examples/migration/ent/pet.go index 6e5c097bc..4466ce35f 100644 --- a/examples/migration/ent/pet.go +++ b/examples/migration/ent/pet.go @@ -22,6 +22,8 @@ type Pet struct { config `json:"-"` // ID of the ent. ID uuid.UUID `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` // BestFriendID holds the value of the "best_friend_id" field. BestFriendID uuid.UUID `json:"best_friend_id,omitempty"` // OwnerID holds the value of the "owner_id" field. @@ -76,6 +78,8 @@ func (*Pet) scanValues(columns []string) ([]any, error) { switch columns[i] { case pet.FieldOwnerID: values[i] = new(sql.NullInt64) + case pet.FieldName: + values[i] = new(sql.NullString) case pet.FieldID, pet.FieldBestFriendID: values[i] = new(uuid.UUID) default: @@ -99,6 +103,12 @@ func (pe *Pet) assignValues(columns []string, values []any) error { } else if value != nil { pe.ID = *value } + 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.FieldBestFriendID: if value, ok := values[i].(*uuid.UUID); !ok { return fmt.Errorf("unexpected type %T for field best_friend_id", values[i]) @@ -157,6 +167,9 @@ 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.WriteString(", ") builder.WriteString("best_friend_id=") builder.WriteString(fmt.Sprintf("%v", pe.BestFriendID)) builder.WriteString(", ") diff --git a/examples/migration/ent/pet/pet.go b/examples/migration/ent/pet/pet.go index 29f6db70f..e9c5d91b0 100644 --- a/examples/migration/ent/pet/pet.go +++ b/examples/migration/ent/pet/pet.go @@ -17,6 +17,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" // FieldBestFriendID holds the string denoting the best_friend_id field in the database. FieldBestFriendID = "best_friend_id" // FieldOwnerID holds the string denoting the owner_id field in the database. @@ -43,6 +45,7 @@ const ( // Columns holds all SQL columns for pet fields. var Columns = []string{ FieldID, + FieldName, FieldBestFriendID, FieldOwnerID, } @@ -72,6 +75,11 @@ func ByID(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldID, opts...).ToFunc() } +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + // ByBestFriendID orders the results by the best_friend_id field. func ByBestFriendID(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldBestFriendID, opts...).ToFunc() diff --git a/examples/migration/ent/pet/where.go b/examples/migration/ent/pet/where.go index 9f2eb43cd..1efcf655e 100644 --- a/examples/migration/ent/pet/where.go +++ b/examples/migration/ent/pet/where.go @@ -58,6 +58,11 @@ func IDLTE(id uuid.UUID) predicate.Pet { return predicate.Pet(sql.FieldLTE(FieldID, id)) } +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Pet { + return predicate.Pet(sql.FieldEQ(FieldName, v)) +} + // BestFriendID applies equality check predicate on the "best_friend_id" field. It's identical to BestFriendIDEQ. func BestFriendID(v uuid.UUID) predicate.Pet { return predicate.Pet(sql.FieldEQ(FieldBestFriendID, v)) @@ -68,6 +73,71 @@ func OwnerID(v int) predicate.Pet { return predicate.Pet(sql.FieldEQ(FieldOwnerID, v)) } +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Pet { + return predicate.Pet(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Pet { + return predicate.Pet(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Pet { + return predicate.Pet(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Pet { + return predicate.Pet(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Pet { + return predicate.Pet(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Pet { + return predicate.Pet(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Pet { + return predicate.Pet(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Pet { + return predicate.Pet(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Pet { + return predicate.Pet(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Pet { + return predicate.Pet(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Pet { + return predicate.Pet(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Pet { + return predicate.Pet(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Pet { + return predicate.Pet(sql.FieldContainsFold(FieldName, v)) +} + // BestFriendIDEQ applies the EQ predicate on the "best_friend_id" field. func BestFriendIDEQ(v uuid.UUID) predicate.Pet { return predicate.Pet(sql.FieldEQ(FieldBestFriendID, v)) diff --git a/examples/migration/ent/pet_create.go b/examples/migration/ent/pet_create.go index 2ee8e613a..65016b727 100644 --- a/examples/migration/ent/pet_create.go +++ b/examples/migration/ent/pet_create.go @@ -25,6 +25,12 @@ type PetCreate struct { hooks []Hook } +// SetName sets the "name" field. +func (pc *PetCreate) SetName(s string) *PetCreate { + pc.mutation.SetName(s) + return pc +} + // SetBestFriendID sets the "best_friend_id" field. func (pc *PetCreate) SetBestFriendID(u uuid.UUID) *PetCreate { pc.mutation.SetBestFriendID(u) @@ -116,6 +122,9 @@ func (pc *PetCreate) defaults() { // check runs all checks and user-defined validators on the builder. func (pc *PetCreate) check() error { + if _, ok := pc.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Pet.name"`)} + } if _, ok := pc.mutation.BestFriendID(); !ok { return &ValidationError{Name: "best_friend_id", err: errors.New(`ent: missing required field "Pet.best_friend_id"`)} } @@ -163,6 +172,10 @@ func (pc *PetCreate) createSpec() (*Pet, *sqlgraph.CreateSpec) { _node.ID = id _spec.ID.Value = &id } + if value, ok := pc.mutation.Name(); ok { + _spec.SetField(pet.FieldName, field.TypeString, value) + _node.Name = value + } if nodes := pc.mutation.BestFriendIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2O, diff --git a/examples/migration/ent/pet_query.go b/examples/migration/ent/pet_query.go index 19a375ea9..2baf1ec23 100644 --- a/examples/migration/ent/pet_query.go +++ b/examples/migration/ent/pet_query.go @@ -337,12 +337,12 @@ func (pq *PetQuery) WithOwner(opts ...func(*UserQuery)) *PetQuery { // Example: // // var v []struct { -// BestFriendID uuid.UUID `json:"best_friend_id,omitempty"` +// Name string `json:"name,omitempty"` // Count int `json:"count,omitempty"` // } // // client.Pet.Query(). -// GroupBy(pet.FieldBestFriendID). +// GroupBy(pet.FieldName). // Aggregate(ent.Count()). // Scan(ctx, &v) func (pq *PetQuery) GroupBy(field string, fields ...string) *PetGroupBy { @@ -360,11 +360,11 @@ func (pq *PetQuery) GroupBy(field string, fields ...string) *PetGroupBy { // Example: // // var v []struct { -// BestFriendID uuid.UUID `json:"best_friend_id,omitempty"` +// Name string `json:"name,omitempty"` // } // // client.Pet.Query(). -// Select(pet.FieldBestFriendID). +// Select(pet.FieldName). // Scan(ctx, &v) func (pq *PetQuery) Select(fields ...string) *PetSelect { pq.ctx.Fields = append(pq.ctx.Fields, fields...) diff --git a/examples/migration/ent/pet_update.go b/examples/migration/ent/pet_update.go index 20501098f..71848fc61 100644 --- a/examples/migration/ent/pet_update.go +++ b/examples/migration/ent/pet_update.go @@ -33,6 +33,20 @@ 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 +} + // SetBestFriendID sets the "best_friend_id" field. func (pu *PetUpdate) SetBestFriendID(u uuid.UUID) *PetUpdate { pu.mutation.SetBestFriendID(u) @@ -138,6 +152,9 @@ func (pu *PetUpdate) sqlSave(ctx context.Context) (n int, err error) { } } } + if value, ok := pu.mutation.Name(); ok { + _spec.SetField(pet.FieldName, field.TypeString, value) + } if pu.mutation.BestFriendCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2O, @@ -216,6 +233,20 @@ 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 +} + // SetBestFriendID sets the "best_friend_id" field. func (puo *PetUpdateOne) SetBestFriendID(u uuid.UUID) *PetUpdateOne { puo.mutation.SetBestFriendID(u) @@ -351,6 +382,9 @@ func (puo *PetUpdateOne) sqlSave(ctx context.Context) (_node *Pet, err error) { } } } + if value, ok := puo.mutation.Name(); ok { + _spec.SetField(pet.FieldName, field.TypeString, value) + } if puo.mutation.BestFriendCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2O, diff --git a/examples/migration/ent/runtime.go b/examples/migration/ent/runtime.go index 9e7fa051d..107a5c193 100644 --- a/examples/migration/ent/runtime.go +++ b/examples/migration/ent/runtime.go @@ -26,7 +26,7 @@ func init() { petFields := schema.Pet{}.Fields() _ = petFields // petDescOwnerID is the schema descriptor for owner_id field. - petDescOwnerID := petFields[2].Descriptor() + petDescOwnerID := petFields[3].Descriptor() // pet.DefaultOwnerID holds the default value on creation for the owner_id field. pet.DefaultOwnerID = petDescOwnerID.Default.(int) // petDescID is the schema descriptor for id field. diff --git a/examples/migration/ent/schema/pet.go b/examples/migration/ent/schema/pet.go index c970ce6e4..8f43a2a7b 100644 --- a/examples/migration/ent/schema/pet.go +++ b/examples/migration/ent/schema/pet.go @@ -9,6 +9,7 @@ import ( "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" "github.com/google/uuid" ) @@ -22,6 +23,7 @@ func (Pet) Fields() []ent.Field { return []ent.Field{ field.UUID("id", uuid.Nil). Default(uuid.New), + field.String("name"), field.UUID("best_friend_id", uuid.Nil). Annotations( entsql.Default(uuid.Nil.String()), @@ -44,3 +46,11 @@ func (Pet) Edges() []ent.Edge { Field("owner_id"), } } + +// Indexes of the Pet. +func (Pet) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("name", "owner_id"). + Unique(), + } +}