examples/migration: add unique pet name for each owner (#3875)

This commit is contained in:
Ariel Mashraki
2023-12-31 12:00:46 +02:00
committed by GitHub
parent e875474929
commit bd8f9eac01
13 changed files with 224 additions and 11 deletions

View File

@@ -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:

View File

@@ -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`);

View File

@@ -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=

View File

@@ -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{

View File

@@ -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

View File

@@ -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(", ")

View File

@@ -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()

View File

@@ -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))

View File

@@ -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,

View File

@@ -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...)

View File

@@ -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,

View File

@@ -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.

View File

@@ -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(),
}
}