From 8a8c72f377234dc2754e90cc4e64405180df72bb Mon Sep 17 00:00:00 2001 From: Ariel Mashraki <7413593+a8m@users.noreply.github.com> Date: Mon, 14 Nov 2022 13:58:35 +0200 Subject: [PATCH] example/migration: improve atlas migration example (#3092) --- dialect/entsql/annotation.go | 24 +++ doc/md/versioned-migrations.mdx | 11 +- examples/migration/README.md | 14 +- examples/migration/ent/migrate/main.go | 13 +- .../20220814190333_create_users.down.sql | 2 - ...up.sql => 20221114082343_create_users.sql} | 0 .../migrations/20221114090322_add_age.sql | 2 + .../migrations/20221114101516_add_name.sql | 2 + .../ent/migrate/migrations/atlas.sum | 6 +- examples/migration/ent/migrate/schema.go | 9 + examples/migration/ent/mutation.go | 160 +++++++++++++++- examples/migration/ent/schema/user.go | 28 ++- examples/migration/ent/user.go | 29 ++- examples/migration/ent/user/user.go | 6 + examples/migration/ent/user/where.go | 177 ++++++++++++++++++ examples/migration/ent/user_create.go | 27 +++ examples/migration/ent/user_query.go | 22 +++ examples/migration/ent/user_update.go | 56 ++++++ 18 files changed, 559 insertions(+), 29 deletions(-) delete mode 100644 examples/migration/ent/migrate/migrations/20220814190333_create_users.down.sql rename examples/migration/ent/migrate/migrations/{20220814190333_create_users.up.sql => 20221114082343_create_users.sql} (100%) create mode 100644 examples/migration/ent/migrate/migrations/20221114090322_add_age.sql create mode 100644 examples/migration/ent/migrate/migrations/20221114101516_add_name.sql diff --git a/dialect/entsql/annotation.go b/dialect/entsql/annotation.go index 9a7464169..bdbe9f525 100644 --- a/dialect/entsql/annotation.go +++ b/dialect/entsql/annotation.go @@ -136,6 +136,30 @@ func (Annotation) Name() string { return "EntSQL" } +// Check allows injecting custom "DDL" for setting an unnamed "CHECK" clause in "CREATE TABLE". +// +// entsql.Annotation{ +// Check: "(`age` < 10)", +// } +func Check(c string) *Annotation { + return &Annotation{ + Check: c, + } +} + +// Checks allows injecting custom "DDL" for setting named "CHECK" clauses in "CREATE TABLE". +// +// entsql.Annotation{ +// Checks: map[string]string{ +// "valid_discount": "price > discount_price", +// }, +// } +func Checks(c map[string]string) *Annotation { + return &Annotation{ + Checks: c, + } +} + // Default specifies a literal default value of a column. Note that using // this option overrides the default behavior of the code-generation. // diff --git a/doc/md/versioned-migrations.mdx b/doc/md/versioned-migrations.mdx index f4a9e652a..32c188e23 100644 --- a/doc/md/versioned-migrations.mdx +++ b/doc/md/versioned-migrations.mdx @@ -470,16 +470,19 @@ Let's run `atlas migrate lint` with the necessary parameters to run migration li go run -mod=mod ariga.io/atlas/cmd/atlas@master migrate lint \ --dev-url="mysql://root:pass@localhost:3306/test" \ --dir="file://ent/migrate/migrations" \ - --dir-format="golang-migrate" \ --latest=1 ``` An output of such a run might look as follows: -```text -Destructive changes detected in file 20220814125800_name.up.sql: +```text {3,7} +20221114090322_add_age.sql: data dependent changes detected: - L1: Dropping table "posts" + L2: Adding a non-nullable "double" column "age" on table "users" without a default value implicitly sets existing rows with 0 + +20221114101516_add_name.sql: data dependent changes detected: + + L2: Adding a non-nullable "varchar" column "name" on table "users" without a default value implicitly sets existing rows with "" ``` diff --git a/examples/migration/README.md b/examples/migration/README.md index 8734eb814..6711c387d 100644 --- a/examples/migration/README.md +++ b/examples/migration/README.md @@ -12,19 +12,25 @@ Versioned migration files exists under `ent/migrate/migrations` and follows the 2\. Run `go generate ./ent` - ### Generate new versioned migration +1\. Create a dev-database container if there is no one. + +```shell +docker run --name migration --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=test -d mysql +``` + +2\. Generate a new versioned migration file: + ```go go run -mod=mod ent/migrate/main.go ``` -### Run linting +### Run migration linting ```bash -go run -mod=mod ariga.io/atlas/cmd/atlas@master migrate lint \ +go run -mod=mod ariga.io/atlas/cmd/atlas@latest migrate lint \ --dev-url="mysql://root:pass@localhost:3306/test" \ --dir="file://ent/migrate/migrations" \ - --dir-format="golang-migrate" \ --latest=1 ``` diff --git a/examples/migration/ent/migrate/main.go b/examples/migration/ent/migrate/main.go index 25e5f2dd4..b0055e7ac 100644 --- a/examples/migration/ent/migrate/main.go +++ b/examples/migration/ent/migrate/main.go @@ -11,7 +11,7 @@ import ( "log" "os" - "ariga.io/atlas/sql/sqltool" + atlas "ariga.io/atlas/sql/migrate" "entgo.io/ent/dialect" "entgo.io/ent/dialect/sql/schema" "entgo.io/ent/examples/migration/ent/migrate" @@ -20,17 +20,16 @@ import ( func main() { ctx := context.Background() - // Create a local migration directory able to understand - // golang-migrate migration files for replay. - dir, err := sqltool.NewGolangMigrateDir("ent/migrate/migrations") + dir, err := atlas.NewLocalDir("ent/migrate/migrations") if err != nil { log.Fatalf("failed creating atlas migration directory: %v", err) } // Migrate diff options. opts := []schema.MigrateOption{ - schema.WithDir(dir), // provide migration directory - schema.WithMigrationMode(schema.ModeReplay), // provide migration mode - schema.WithDialect(dialect.MySQL), // Ent dialect to use + schema.WithDir(dir), // provide migration directory + schema.WithMigrationMode(schema.ModeReplay), // provide migration mode + schema.WithDialect(dialect.MySQL), // Ent dialect to use + schema.WithFormatter(atlas.DefaultFormatter), // Default Atlas formatter } if len(os.Args) != 2 { log.Fatalln("migration name is required. Use: 'go run -mod=mod ./ent/migrate/main.go '") diff --git a/examples/migration/ent/migrate/migrations/20220814190333_create_users.down.sql b/examples/migration/ent/migrate/migrations/20220814190333_create_users.down.sql deleted file mode 100644 index 6a8c12cbd..000000000 --- a/examples/migration/ent/migrate/migrations/20220814190333_create_users.down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- reverse: create "users" table -DROP TABLE `users`; diff --git a/examples/migration/ent/migrate/migrations/20220814190333_create_users.up.sql b/examples/migration/ent/migrate/migrations/20221114082343_create_users.sql similarity index 100% rename from examples/migration/ent/migrate/migrations/20220814190333_create_users.up.sql rename to examples/migration/ent/migrate/migrations/20221114082343_create_users.sql diff --git a/examples/migration/ent/migrate/migrations/20221114090322_add_age.sql b/examples/migration/ent/migrate/migrations/20221114090322_add_age.sql new file mode 100644 index 000000000..ca9358791 --- /dev/null +++ b/examples/migration/ent/migrate/migrations/20221114090322_add_age.sql @@ -0,0 +1,2 @@ +-- modify "users" table +ALTER TABLE `users` ADD CHECK (age > 0), ADD COLUMN `age` double NOT NULL; diff --git a/examples/migration/ent/migrate/migrations/20221114101516_add_name.sql b/examples/migration/ent/migrate/migrations/20221114101516_add_name.sql new file mode 100644 index 000000000..ac594f655 --- /dev/null +++ b/examples/migration/ent/migrate/migrations/20221114101516_add_name.sql @@ -0,0 +1,2 @@ +-- modify "users" table +ALTER TABLE `users` ADD CONSTRAINT `name_not_empty` CHECK (name <> ''), ADD COLUMN `name` varchar(255) NOT NULL; diff --git a/examples/migration/ent/migrate/migrations/atlas.sum b/examples/migration/ent/migrate/migrations/atlas.sum index 5e18a739a..b13256fad 100644 --- a/examples/migration/ent/migrate/migrations/atlas.sum +++ b/examples/migration/ent/migrate/migrations/atlas.sum @@ -1,2 +1,4 @@ -h1:xTs5+xjXcSCUFE4LOrZmcfnsCRBRHF7GoSEg5aC6lYc= -20220814190333_create_users.up.sql h1:kqsTUgWM7DTjW8gn/tMCgtmlxVf2hEwUTEU6FHcM5mY= +h1:uJ67zyvQoeKI01UWjiq/dHlKBBjzMcgwKdDKq4YCLy8= +20221114082343_create_users.sql h1:EeOPKbOeYUHO830P1MCXKUsxT3wLk/hSgcpT9GzlGZQ= +20221114090322_add_age.sql h1:weRCTqS5cqKyrvIjGXk7Bn24YUXo0nhLNWD0EZBcaoQ= +20221114101516_add_name.sql h1:leQgI2JN3URZyujlNzX3gI53MSiTA02MKI/G9cnMu6I= diff --git a/examples/migration/ent/migrate/schema.go b/examples/migration/ent/migrate/schema.go index 6ce24099d..8b772af30 100644 --- a/examples/migration/ent/migrate/schema.go +++ b/examples/migration/ent/migrate/schema.go @@ -7,6 +7,7 @@ package migrate import ( + "entgo.io/ent/dialect/entsql" "entgo.io/ent/dialect/sql/schema" "entgo.io/ent/schema/field" ) @@ -15,6 +16,8 @@ var ( // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "age", Type: field.TypeFloat64}, + {Name: "name", Type: field.TypeString}, } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ @@ -29,4 +32,10 @@ var ( ) func init() { + UsersTable.Annotation = &entsql.Annotation{ + Check: "(`age` > 0)", + } + UsersTable.Annotation.Checks = map[string]string{ + "name_not_empty": "name <> ''", + } } diff --git a/examples/migration/ent/mutation.go b/examples/migration/ent/mutation.go index eeddc2216..c6196c50e 100644 --- a/examples/migration/ent/mutation.go +++ b/examples/migration/ent/mutation.go @@ -12,8 +12,10 @@ import ( "fmt" "sync" - "entgo.io/ent" "entgo.io/ent/examples/migration/ent/predicate" + "entgo.io/ent/examples/migration/ent/user" + + "entgo.io/ent" ) const ( @@ -34,6 +36,9 @@ type UserMutation struct { op Op typ string id *int + age *float64 + addage *float64 + name *string clearedFields map[string]struct{} done bool oldValue func(context.Context) (*User, error) @@ -138,6 +143,98 @@ func (m *UserMutation) IDs(ctx context.Context) ([]int, error) { } } +// SetAge sets the "age" field. +func (m *UserMutation) SetAge(f float64) { + m.age = &f + m.addage = nil +} + +// Age returns the value of the "age" field in the mutation. +func (m *UserMutation) Age() (r float64, exists bool) { + v := m.age + if v == nil { + return + } + return *v, true +} + +// OldAge returns the old "age" field's value of the User entity. +// If the User 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 *UserMutation) OldAge(ctx context.Context) (v float64, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldAge is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldAge requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldAge: %w", err) + } + return oldValue.Age, nil +} + +// AddAge adds f to the "age" field. +func (m *UserMutation) AddAge(f float64) { + if m.addage != nil { + *m.addage += f + } else { + m.addage = &f + } +} + +// AddedAge returns the value that was added to the "age" field in this mutation. +func (m *UserMutation) AddedAge() (r float64, exists bool) { + v := m.addage + if v == nil { + return + } + return *v, true +} + +// ResetAge resets all changes to the "age" field. +func (m *UserMutation) ResetAge() { + m.age = nil + m.addage = nil +} + +// SetName sets the "name" field. +func (m *UserMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *UserMutation) 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 User entity. +// If the User 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 *UserMutation) 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 *UserMutation) ResetName() { + m.name = nil +} + // Where appends a list predicates to the UserMutation builder. func (m *UserMutation) Where(ps ...predicate.User) { m.predicates = append(m.predicates, ps...) @@ -157,7 +254,13 @@ func (m *UserMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *UserMutation) Fields() []string { - fields := make([]string, 0, 0) + fields := make([]string, 0, 2) + if m.age != nil { + fields = append(fields, user.FieldAge) + } + if m.name != nil { + fields = append(fields, user.FieldName) + } return fields } @@ -165,6 +268,12 @@ func (m *UserMutation) Fields() []string { // return value indicates that this field was not set, or was not defined in the // schema. func (m *UserMutation) Field(name string) (ent.Value, bool) { + switch name { + case user.FieldAge: + return m.Age() + case user.FieldName: + return m.Name() + } return nil, false } @@ -172,6 +281,12 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { // returned if the mutation operation is not UpdateOne, or the query to the // database failed. func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case user.FieldAge: + return m.OldAge(ctx) + case user.FieldName: + return m.OldName(ctx) + } return nil, fmt.Errorf("unknown User field %s", name) } @@ -180,6 +295,20 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er // type. func (m *UserMutation) SetField(name string, value ent.Value) error { switch name { + case user.FieldAge: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetAge(v) + return nil + case user.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 User field %s", name) } @@ -187,13 +316,21 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { // AddedFields returns all numeric fields that were incremented/decremented during // this mutation. func (m *UserMutation) AddedFields() []string { - return nil + var fields []string + if m.addage != nil { + fields = append(fields, user.FieldAge) + } + return fields } // AddedField returns the numeric value that was incremented/decremented on a field // with the given name. The second boolean return value indicates that this field // was not set, or was not defined in the schema. func (m *UserMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case user.FieldAge: + return m.AddedAge() + } return nil, false } @@ -201,6 +338,15 @@ func (m *UserMutation) AddedField(name string) (ent.Value, bool) { // the field is not defined in the schema, or if the type mismatched the field // type. func (m *UserMutation) AddField(name string, value ent.Value) error { + switch name { + case user.FieldAge: + v, ok := value.(float64) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddAge(v) + return nil + } return fmt.Errorf("unknown User numeric field %s", name) } @@ -226,6 +372,14 @@ func (m *UserMutation) ClearField(name string) error { // 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 *UserMutation) ResetField(name string) error { + switch name { + case user.FieldAge: + m.ResetAge() + return nil + case user.FieldName: + m.ResetName() + return nil + } return fmt.Errorf("unknown User field %s", name) } diff --git a/examples/migration/ent/schema/user.go b/examples/migration/ent/schema/user.go index 7c14fb81d..eb9daae3b 100644 --- a/examples/migration/ent/schema/user.go +++ b/examples/migration/ent/schema/user.go @@ -1,6 +1,11 @@ package schema -import "entgo.io/ent" +import ( + "entgo.io/ent" + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "entgo.io/ent/schema/field" +) // User holds the schema definition for the User entity. type User struct { @@ -9,10 +14,23 @@ type User struct { // Fields of the User. func (User) Fields() []ent.Field { - return nil + return []ent.Field{ + field.Float("age"), + field.String("name"), + } } -// Edges of the User. -func (User) Edges() []ent.Edge { - return nil +// Annotations of the User. +func (User) Annotations() []schema.Annotation { + return []schema.Annotation{ + // Unnamed check constraints should be identical to their definition in the + // database (i.e. normalized). See: https://atlasgo.io/concepts/dev-database. + entsql.Check("(`age` > 0)"), + + // Named check constraints are compared by their name. + // Thus, the definition does not need to be normalized. + entsql.Checks(map[string]string{ + "name_not_empty": "name <> ''", + }), + } } diff --git a/examples/migration/ent/user.go b/examples/migration/ent/user.go index 1a2fd0c29..794f22be5 100644 --- a/examples/migration/ent/user.go +++ b/examples/migration/ent/user.go @@ -16,9 +16,13 @@ import ( // User is the model entity for the User schema. type User struct { - config + config `json:"-"` // ID of the ent. ID int `json:"id,omitempty"` + // Age holds the value of the "age" field. + Age float64 `json:"age,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` } // scanValues returns the types for scanning values from sql.Rows. @@ -26,8 +30,12 @@ func (*User) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { + case user.FieldAge: + values[i] = new(sql.NullFloat64) case user.FieldID: values[i] = new(sql.NullInt64) + case user.FieldName: + values[i] = new(sql.NullString) default: return nil, fmt.Errorf("unexpected column %q for type User", columns[i]) } @@ -49,6 +57,18 @@ func (u *User) assignValues(columns []string, values []any) error { return fmt.Errorf("unexpected type %T for field id", value) } u.ID = int(value.Int64) + case user.FieldAge: + if value, ok := values[i].(*sql.NullFloat64); !ok { + return fmt.Errorf("unexpected type %T for field age", values[i]) + } else if value.Valid { + u.Age = value.Float64 + } + case user.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + u.Name = value.String + } } } return nil @@ -76,7 +96,12 @@ func (u *User) Unwrap() *User { func (u *User) String() string { var builder strings.Builder builder.WriteString("User(") - builder.WriteString(fmt.Sprintf("id=%v", u.ID)) + builder.WriteString(fmt.Sprintf("id=%v, ", u.ID)) + builder.WriteString("age=") + builder.WriteString(fmt.Sprintf("%v", u.Age)) + builder.WriteString(", ") + builder.WriteString("name=") + builder.WriteString(u.Name) builder.WriteByte(')') return builder.String() } diff --git a/examples/migration/ent/user/user.go b/examples/migration/ent/user/user.go index 07249c397..a311f61c3 100644 --- a/examples/migration/ent/user/user.go +++ b/examples/migration/ent/user/user.go @@ -11,6 +11,10 @@ const ( Label = "user" // FieldID holds the string denoting the id field in the database. FieldID = "id" + // FieldAge holds the string denoting the age field in the database. + FieldAge = "age" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" // Table holds the table name of the user in the database. Table = "users" ) @@ -18,6 +22,8 @@ const ( // Columns holds all SQL columns for user fields. var Columns = []string{ FieldID, + FieldAge, + FieldName, } // ValidColumn reports if the column name is valid (part of the table columns). diff --git a/examples/migration/ent/user/where.go b/examples/migration/ent/user/where.go index 4045862a0..7ae9f0214 100644 --- a/examples/migration/ent/user/where.go +++ b/examples/migration/ent/user/where.go @@ -82,6 +82,183 @@ func IDLTE(id int) predicate.User { }) } +// Age applies equality check predicate on the "age" field. It's identical to AgeEQ. +func Age(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldAge), v)) + }) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// AgeEQ applies the EQ predicate on the "age" field. +func AgeEQ(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldAge), v)) + }) +} + +// AgeNEQ applies the NEQ predicate on the "age" field. +func AgeNEQ(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldAge), v)) + }) +} + +// AgeIn applies the In predicate on the "age" field. +func AgeIn(vs ...float64) predicate.User { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(func(s *sql.Selector) { + s.Where(sql.In(s.C(FieldAge), v...)) + }) +} + +// AgeNotIn applies the NotIn predicate on the "age" field. +func AgeNotIn(vs ...float64) predicate.User { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NotIn(s.C(FieldAge), v...)) + }) +} + +// AgeGT applies the GT predicate on the "age" field. +func AgeGT(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldAge), v)) + }) +} + +// AgeGTE applies the GTE predicate on the "age" field. +func AgeGTE(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldAge), v)) + }) +} + +// AgeLT applies the LT predicate on the "age" field. +func AgeLT(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldAge), v)) + }) +} + +// AgeLTE applies the LTE predicate on the "age" field. +func AgeLTE(v float64) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldAge), v)) + }) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.User { + return predicate.User(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.User { + return predicate.User(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.User { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(func(s *sql.Selector) { + s.Where(sql.In(s.C(FieldName), v...)) + }) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.User { + v := make([]any, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NotIn(s.C(FieldName), v...)) + }) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.User { + return predicate.User(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.User { + return predicate.User(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.User { + return predicate.User(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.User { + return predicate.User(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.User { + return predicate.User(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.User { + return predicate.User(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.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldName), v)) + }) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.User { + return predicate.User(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.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldName), v)) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.User) predicate.User { return predicate.User(func(s *sql.Selector) { diff --git a/examples/migration/ent/user_create.go b/examples/migration/ent/user_create.go index 30d874398..786d6524a 100644 --- a/examples/migration/ent/user_create.go +++ b/examples/migration/ent/user_create.go @@ -8,6 +8,7 @@ package ent import ( "context" + "errors" "fmt" "entgo.io/ent/dialect/sql/sqlgraph" @@ -22,6 +23,18 @@ type UserCreate struct { hooks []Hook } +// SetAge sets the "age" field. +func (uc *UserCreate) SetAge(f float64) *UserCreate { + uc.mutation.SetAge(f) + return uc +} + +// SetName sets the "name" field. +func (uc *UserCreate) SetName(s string) *UserCreate { + uc.mutation.SetName(s) + return uc +} + // Mutation returns the UserMutation object of the builder. func (uc *UserCreate) Mutation() *UserMutation { return uc.mutation @@ -98,6 +111,12 @@ func (uc *UserCreate) ExecX(ctx context.Context) { // check runs all checks and user-defined validators on the builder. func (uc *UserCreate) check() error { + if _, ok := uc.mutation.Age(); !ok { + return &ValidationError{Name: "age", err: errors.New(`ent: missing required field "User.age"`)} + } + if _, ok := uc.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "User.name"`)} + } return nil } @@ -125,6 +144,14 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { }, } ) + if value, ok := uc.mutation.Age(); ok { + _spec.SetField(user.FieldAge, field.TypeFloat64, value) + _node.Age = value + } + if value, ok := uc.mutation.Name(); ok { + _spec.SetField(user.FieldName, field.TypeString, value) + _node.Name = value + } return _node, _spec } diff --git a/examples/migration/ent/user_query.go b/examples/migration/ent/user_query.go index 63e81f5be..472aad63f 100644 --- a/examples/migration/ent/user_query.go +++ b/examples/migration/ent/user_query.go @@ -253,6 +253,18 @@ func (uq *UserQuery) Clone() *UserQuery { // 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 { +// Age float64 `json:"age,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.User.Query(). +// GroupBy(user.FieldAge). +// Aggregate(ent.Count()). +// Scan(ctx, &v) func (uq *UserQuery) GroupBy(field string, fields ...string) *UserGroupBy { grbuild := &UserGroupBy{config: uq.config} grbuild.fields = append([]string{field}, fields...) @@ -269,6 +281,16 @@ func (uq *UserQuery) GroupBy(field string, fields ...string) *UserGroupBy { // 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 { +// Age float64 `json:"age,omitempty"` +// } +// +// client.User.Query(). +// Select(user.FieldAge). +// Scan(ctx, &v) func (uq *UserQuery) Select(fields ...string) *UserSelect { uq.fields = append(uq.fields, fields...) selbuild := &UserSelect{UserQuery: uq} diff --git a/examples/migration/ent/user_update.go b/examples/migration/ent/user_update.go index 419849155..9095fd14d 100644 --- a/examples/migration/ent/user_update.go +++ b/examples/migration/ent/user_update.go @@ -31,6 +31,25 @@ func (uu *UserUpdate) Where(ps ...predicate.User) *UserUpdate { return uu } +// SetAge sets the "age" field. +func (uu *UserUpdate) SetAge(f float64) *UserUpdate { + uu.mutation.ResetAge() + uu.mutation.SetAge(f) + return uu +} + +// AddAge adds f to the "age" field. +func (uu *UserUpdate) AddAge(f float64) *UserUpdate { + uu.mutation.AddAge(f) + return uu +} + +// SetName sets the "name" field. +func (uu *UserUpdate) SetName(s string) *UserUpdate { + uu.mutation.SetName(s) + return uu +} + // Mutation returns the UserMutation object of the builder. func (uu *UserUpdate) Mutation() *UserMutation { return uu.mutation @@ -108,6 +127,15 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { } } } + if value, ok := uu.mutation.Age(); ok { + _spec.SetField(user.FieldAge, field.TypeFloat64, value) + } + if value, ok := uu.mutation.AddedAge(); ok { + _spec.AddField(user.FieldAge, field.TypeFloat64, value) + } + if value, ok := uu.mutation.Name(); ok { + _spec.SetField(user.FieldName, field.TypeString, value) + } if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{user.Label} @@ -127,6 +155,25 @@ type UserUpdateOne struct { mutation *UserMutation } +// SetAge sets the "age" field. +func (uuo *UserUpdateOne) SetAge(f float64) *UserUpdateOne { + uuo.mutation.ResetAge() + uuo.mutation.SetAge(f) + return uuo +} + +// AddAge adds f to the "age" field. +func (uuo *UserUpdateOne) AddAge(f float64) *UserUpdateOne { + uuo.mutation.AddAge(f) + return uuo +} + +// SetName sets the "name" field. +func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { + uuo.mutation.SetName(s) + return uuo +} + // Mutation returns the UserMutation object of the builder. func (uuo *UserUpdateOne) Mutation() *UserMutation { return uuo.mutation @@ -234,6 +281,15 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) } } } + if value, ok := uuo.mutation.Age(); ok { + _spec.SetField(user.FieldAge, field.TypeFloat64, value) + } + if value, ok := uuo.mutation.AddedAge(); ok { + _spec.AddField(user.FieldAge, field.TypeFloat64, value) + } + if value, ok := uuo.mutation.Name(); ok { + _spec.SetField(user.FieldName, field.TypeString, value) + } _node = &User{config: uuo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues