From 66871c98065a7cf28ce325756af7f62ffa48e3a0 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki Date: Tue, 8 Jun 2021 11:09:06 +0300 Subject: [PATCH] dialect/sql/schema: add support for index prefixes in mysql --- dialect/entsql/annotation.go | 97 +++++++++ dialect/sql/schema/inspect_test.go | 22 +- dialect/sql/schema/migrate.go | 7 + dialect/sql/schema/mysql.go | 67 +++++- dialect/sql/schema/mysql_test.go | 194 +++++++++++------- dialect/sql/schema/schema.go | 22 +- entc/gen/graph.go | 3 + entc/gen/internal/bindata.go | 4 +- entc/gen/template/migrate/schema.tmpl | 91 ++++---- entc/gen/type.go | 29 ++- entc/gen/type_test.go | 3 - .../cascadelete/ent/migrate/schema.go | 7 +- entc/integration/config/ent/migrate/schema.go | 7 +- .../customid/ent/migrate/schema.go | 14 +- .../edgefield/ent/migrate/schema.go | 7 +- entc/integration/ent/migrate/schema.go | 49 ++--- entc/integration/json/ent/migrate/schema.go | 7 +- .../migrate/entv1/migrate/schema.go | 30 ++- entc/integration/migrate/entv1/mutation.go | 75 ++++++- entc/integration/migrate/entv1/runtime.go | 2 +- entc/integration/migrate/entv1/schema/user.go | 5 + entc/integration/migrate/entv1/user.go | 12 +- entc/integration/migrate/entv1/user/user.go | 3 + entc/integration/migrate/entv1/user/where.go | 132 ++++++++++++ entc/integration/migrate/entv1/user_create.go | 22 ++ entc/integration/migrate/entv1/user_update.go | 66 ++++++ entc/integration/migrate/entv2/media.go | 12 +- entc/integration/migrate/entv2/media/media.go | 3 + entc/integration/migrate/entv2/media/where.go | 132 ++++++++++++ .../integration/migrate/entv2/media_create.go | 22 ++ .../integration/migrate/entv2/media_update.go | 66 ++++++ .../migrate/entv2/migrate/schema.go | 61 ++++-- entc/integration/migrate/entv2/mutation.go | 150 +++++++++++++- entc/integration/migrate/entv2/runtime.go | 10 +- .../integration/migrate/entv2/schema/media.go | 7 + entc/integration/migrate/entv2/schema/user.go | 7 + entc/integration/migrate/entv2/user.go | 12 +- entc/integration/migrate/entv2/user/user.go | 3 + entc/integration/migrate/entv2/user/where.go | 132 ++++++++++++ entc/integration/migrate/entv2/user_create.go | 22 ++ entc/integration/migrate/entv2/user_update.go | 66 ++++++ .../multischema/ent/migrate/schema.go | 14 +- .../integration/privacy/ent/migrate/schema.go | 14 +- .../template/ent/migrate/schema.go | 14 +- examples/edgeindex/ent/migrate/schema.go | 7 +- examples/entcpkg/ent/migrate/schema.go | 7 +- examples/m2m2types/ent/migrate/schema.go | 14 +- examples/m2mbidi/ent/migrate/schema.go | 7 +- examples/m2mrecur/ent/migrate/schema.go | 7 +- examples/o2m2types/ent/migrate/schema.go | 7 +- examples/o2o2types/ent/migrate/schema.go | 7 +- examples/privacyadmin/ent/migrate/schema.go | 7 +- examples/privacytenant/ent/migrate/schema.go | 7 +- examples/start/ent/migrate/schema.go | 14 +- examples/traversal/ent/migrate/schema.go | 7 +- 55 files changed, 1500 insertions(+), 315 deletions(-) diff --git a/dialect/entsql/annotation.go b/dialect/entsql/annotation.go index 85751b038..b88136a18 100644 --- a/dialect/entsql/annotation.go +++ b/dialect/entsql/annotation.go @@ -158,3 +158,100 @@ const ( SetNull ReferenceOption = "SET NULL" SetDefault ReferenceOption = "SET DEFAULT" ) + +// IndexAnnotation is a builtin schema annotation for attaching +// SQL metadata to schema indexes for both codegen and runtime. +type IndexAnnotation struct { + // Prefix defines a column prefix for a single string column index. + // In MySQL, the following annotation maps to: + // + // index.Fields("column"). + // Annotation(entsql.Prefix(100)) + // + // CREATE INDEX `table_column` ON `table`(`column`(100)) + // + Prefix uint + + // PrefixColumns defines column prefixes for a multi column index. + // In MySQL, the following annotation maps to: + // + // index.Fields("c1", "c2", "c3"). + // Annotation( + // entsql.PrefixColumn("c1", 100), + // entsql.PrefixColumn("c2", 200), + // ) + // + // CREATE INDEX `table_c1_c2_c3` ON `table`(`c1`(100), `c2`(200), `c3`) + // + PrefixColumns map[string]uint +} + +// Prefix returns a new index annotation with a single string column index. +// In MySQL, the following annotation maps to: +// +// index.Fields("column"). +// Annotation(entsql.Prefix(100)) +// +// CREATE INDEX `table_column` ON `table`(`column`(100)) +// +func Prefix(prefix uint) *IndexAnnotation { + return &IndexAnnotation{ + Prefix: prefix, + } +} + +// PrefixColumns returns a new index annotation with column prefix for +// multi-column indexes. In MySQL, the following annotation maps to: +// +// index.Fields("c1", "c2", "c3"). +// Annotation( +// entsql.PrefixColumn("c1", 100), +// entsql.PrefixColumn("c2", 200), +// ) +// +// CREATE INDEX `table_c1_c2_c3` ON `table`(`c1`(100), `c2`(200), `c3`) +// +func PrefixColumn(name string, prefix uint) *IndexAnnotation { + return &IndexAnnotation{ + PrefixColumns: map[string]uint{ + name: prefix, + }, + } +} + +// Name describes the annotation name. +func (IndexAnnotation) Name() string { + return "EntSQLIndexes" +} + +// Merge implements the schema.Merger interface. +func (a IndexAnnotation) Merge(other schema.Annotation) schema.Annotation { + var ant IndexAnnotation + switch other := other.(type) { + case IndexAnnotation: + ant = other + case *IndexAnnotation: + if other != nil { + ant = *other + } + default: + return a + } + if ant.Prefix != 0 { + a.Prefix = ant.Prefix + } + if ant.PrefixColumns != nil { + if a.PrefixColumns == nil { + a.PrefixColumns = make(map[string]uint) + } + for column, prefix := range ant.PrefixColumns { + a.PrefixColumns[column] = prefix + } + } + return a +} + +var ( + _ schema.Annotation = (*IndexAnnotation)(nil) + _ schema.Merger = (*IndexAnnotation)(nil) +) diff --git a/dialect/sql/schema/inspect_test.go b/dialect/sql/schema/inspect_test.go index 2873137bb..7be64dc5b 100644 --- a/dialect/sql/schema/inspect_test.go +++ b/dialect/sql/schema/inspect_test.go @@ -67,37 +67,37 @@ func TestInspector_Tables(t *testing.T) { AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", ""). AddRow("text", "longtext", "YES", "YES", "NULL", "", "", ""). AddRow("uuid", "char(36)", "YES", "YES", "NULL", "", "", "utf8mb4_bin")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("public", "users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectQuery(escape("SELECT `column_name`, `column_type`, `is_nullable`, `column_key`, `column_default`, `extra`, `character_set_name`, `collation_name` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?")). WithArgs("public", "pets"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", ""). AddRow("user_pets", "bigint(20)", "YES", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("public", "pets"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectQuery(escape("SELECT `column_name`, `column_type`, `is_nullable`, `column_key`, `column_default`, `extra`, `character_set_name`, `collation_name` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?")). WithArgs("public", "groups"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("public", "groups"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectQuery(escape("SELECT `column_name`, `column_type`, `is_nullable`, `column_key`, `column_default`, `extra`, `character_set_name`, `collation_name` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?")). WithArgs("public", "user_groups"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("user_id", "bigint(20)", "NO", "YES", "NULL", "", "", ""). AddRow("group_id", "bigint(20)", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("public", "user_groups"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"})) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"})) }, dialect.SQLite: func(mock mysqlMock) { mock.ExpectQuery(escape("SELECT `name` FROM `sqlite_schema` WHERE `type` = ?")). diff --git a/dialect/sql/schema/migrate.go b/dialect/sql/schema/migrate.go index 72b61216c..bea5ce632 100644 --- a/dialect/sql/schema/migrate.go +++ b/dialect/sql/schema/migrate.go @@ -385,6 +385,13 @@ func (m *Migrate) changeSet(curr, new *Table) (*changes, error) { case idx1.Unique != idx2.Unique: change.index.drop.append(idx2) change.index.add.append(idx1) + default: + im, ok := m.sqlDialect.(interface{ indexModified(old, new *Index) bool }) + // If the dialect supports comparing indexes. + if ok && im.indexModified(idx2, idx1) { + change.index.drop.append(idx2) + change.index.add.append(idx1) + } } } diff --git a/dialect/sql/schema/mysql.go b/dialect/sql/schema/mysql.go index 3d9b40572..ab64e49ad 100644 --- a/dialect/sql/schema/mysql.go +++ b/dialect/sql/schema/mysql.go @@ -12,6 +12,7 @@ import ( "strings" "entgo.io/ent/dialect" + "entgo.io/ent/dialect/entsql" "entgo.io/ent/dialect/sql" "entgo.io/ent/schema/field" ) @@ -100,7 +101,7 @@ func (d *MySQL) table(ctx context.Context, tx dialect.Tx, name string) (*Table, } // Add and link indexes to table columns. for _, idx := range indexes { - t.AddIndex(idx.Name, idx.Unique, idx.columns) + t.addIndex(idx) } if _, ok := d.mariadb(); ok { if err := d.normalizeJSON(ctx, tx, t); err != nil { @@ -113,7 +114,7 @@ func (d *MySQL) table(ctx context.Context, tx dialect.Tx, name string) (*Table, // table loads the table indexes from the database. func (d *MySQL) indexes(ctx context.Context, tx dialect.Tx, name string) ([]*Index, error) { rows := &sql.Rows{} - query, args := sql.Select("index_name", "column_name", "non_unique", "seq_in_index"). + query, args := sql.Select("index_name", "column_name", "sub_part", "non_unique", "seq_in_index"). From(sql.Table("STATISTICS").Schema("INFORMATION_SCHEMA")). Where(sql.And( d.matchSchema(), @@ -303,7 +304,20 @@ func (d *MySQL) addColumn(c *Column) *sql.ColumnBuilder { // addIndex returns the querying for adding an index to MySQL. func (d *MySQL) addIndex(i *Index, table string) *sql.IndexBuilder { - return i.Builder(table) + idx := sql.CreateIndex(i.Name).Table(table) + if i.Unique { + idx.Unique() + } + parts := indexParts(i) + for _, c := range i.Columns { + part, ok := parts[c.Name] + if !ok || part == 0 { + idx.Column(c.Name) + } else { + idx.Column(fmt.Sprintf("%s(%d)", idx.Builder.Quote(c.Name), part)) + } + } + return idx } // dropIndex drops a MySQL index. @@ -460,8 +474,8 @@ func (d *MySQL) scanColumn(c *Column, rows *sql.Rows) error { } // scanIndexes scans sql.Rows into an Indexes list. The query for returning the rows, -// should return the following 4 columns: INDEX_NAME, COLUMN_NAME, NON_UNIQUE, SEQ_IN_INDEX. -// SEQ_IN_INDEX specifies the position of the column in the index columns. +// should return the following 5 columns: INDEX_NAME, COLUMN_NAME, SUB_PART, NON_UNIQUE, +// SEQ_IN_INDEX. SEQ_IN_INDEX specifies the position of the column in the index columns. func (d *MySQL) scanIndexes(rows *sql.Rows) (Indexes, error) { var ( i Indexes @@ -473,8 +487,9 @@ func (d *MySQL) scanIndexes(rows *sql.Rows) (Indexes, error) { column string nonuniq bool seqindex int + subpart sql.NullInt64 ) - if err := rows.Scan(&name, &column, &nonuniq, &seqindex); err != nil { + if err := rows.Scan(&name, &column, &subpart, &nonuniq, &seqindex); err != nil { return nil, fmt.Errorf("scanning index description: %w", err) } // Ignore primary keys. @@ -483,11 +498,17 @@ func (d *MySQL) scanIndexes(rows *sql.Rows) (Indexes, error) { } idx, ok := names[name] if !ok { - idx = &Index{Name: name, Unique: !nonuniq} + idx = &Index{Name: name, Unique: !nonuniq, Annotation: &entsql.IndexAnnotation{}} i = append(i, idx) names[name] = idx } idx.columns = append(idx.columns, column) + if subpart.Int64 > 0 { + if idx.Annotation.PrefixColumns == nil { + idx.Annotation.PrefixColumns = make(map[string]uint) + } + idx.Annotation.PrefixColumns[column] = uint(subpart.Int64) + } } if err := rows.Err(); err != nil { return nil, err @@ -689,3 +710,35 @@ func (d *MySQL) defaultSize(c *Column) int64 { func (d *MySQL) needsConversion(old, new *Column) bool { return d.cType(old) != d.cType(new) } + +// indexModified used by the migration differ to check if the index was modified. +func (d *MySQL) indexModified(old, new *Index) bool { + oldParts, newParts := indexParts(old), indexParts(new) + if len(oldParts) != len(newParts) { + return true + } + for column, oldPart := range oldParts { + newPart, ok := newParts[column] + if !ok || oldPart != newPart { + return true + } + } + return false +} + +// indexParts returns a map holding the sub_part mapping if exist. +func indexParts(idx *Index) map[string]uint { + parts := make(map[string]uint) + if idx.Annotation == nil { + return parts + } + // If prefix (without a name) was defined on the + // annotation, map it to the single column index. + if idx.Annotation.Prefix > 0 && len(idx.Columns) == 1 { + parts[idx.Columns[0].Name] = idx.Annotation.Prefix + } + for column, part := range idx.Annotation.PrefixColumns { + parts[column] = part + } + return parts +} diff --git a/dialect/sql/schema/mysql_test.go b/dialect/sql/schema/mysql_test.go index 02f88ae9f..e3f530ba8 100644 --- a/dialect/sql/schema/mysql_test.go +++ b/dialect/sql/schema/mysql_test.go @@ -286,10 +286,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("decimal", "decimal(6,2)", "NO", "YES", "NULL", "", "", ""). AddRow("unsigned_decimal", "decimal(6,2) unsigned", "NO", "YES", "NULL", "", "", ""). AddRow("timestamp", "timestamp", "NO", "NO", "CURRENT_TIMESTAMP", "DEFAULT_GENERATED on update CURRENT_TIMESTAMP", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `age` bigint NOT NULL, ADD COLUMN `ts` timestamp NOT NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -321,10 +321,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", ""). AddRow("enums1", "enum('a')", "YES", "NO", "NULL", "", "", ""). AddRow("enums2", "enum('b', 'a')", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` MODIFY COLUMN `enums1` enum('a', 'b') NOT NULL, MODIFY COLUMN `enums2` enum('a') NOT NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -356,10 +356,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("created_at", "datetime", "NO", "YES", "NULL", "", "", ""). AddRow("updated_at", "timestamp", "NO", "YES", "NULL", "", "", ""). AddRow("deleted_at", "datetime", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` MODIFY COLUMN `updated_at` datetime NULL, MODIFY COLUMN `deleted_at` timestamp NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -390,10 +390,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", ""). AddRow("doc", "longblob", "YES", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `age` bigint NOT NULL DEFAULT 10")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -423,10 +423,10 @@ func TestMySQL_Create(t *testing.T) { WithArgs("users"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `tiny` tinyblob NOT NULL, ADD COLUMN `blob` blob NOT NULL, ADD COLUMN `medium` mediumblob NOT NULL, ADD COLUMN `long` longblob NOT NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -453,10 +453,10 @@ func TestMySQL_Create(t *testing.T) { WithArgs("users"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `binary` binary(20) NOT NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -486,10 +486,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("tiny", "varbinary(255)", "NO", "YES", "NULL", "", "", ""). AddRow("medium", "varbinary(255)", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` MODIFY COLUMN `medium` longblob NOT NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -518,10 +518,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec("ALTER TABLE `users` ADD COLUMN `age` double NOT NULL DEFAULT 10.1"). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -550,10 +550,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec("ALTER TABLE `users` ADD COLUMN `age` boolean NOT NULL DEFAULT true"). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -582,10 +582,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `nick` varchar(255) NOT NULL DEFAULT 'unknown'")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -614,10 +614,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `nick` longtext NOT NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -645,10 +645,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "NO", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` DROP COLUMN `name`")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -678,10 +678,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "NO", "YES", "NULL", "", "", ""). AddRow("age", "bigint(20)", "NO", "NO", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` MODIFY COLUMN `name` varchar(255) NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() @@ -709,10 +709,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("age", "bigint(20)", "NO", "", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) // create the unique index. mock.ExpectExec(escape("CREATE UNIQUE INDEX `age` ON `users`(`age`)")). WillReturnResult(sqlmock.NewResult(0, 1)) @@ -741,11 +741,11 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("age", "bigint(20)", "NO", "UNI", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1"). - AddRow("age", "age", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1"). + AddRow("age", "age", nil, "0", "1")) mock.ExpectCommit() }, }, @@ -772,11 +772,11 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("age", "bigint(20)", "NO", "UNI", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1"). - AddRow("age", "age", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1"). + AddRow("age", "age", nil, "0", "1")) // check if a foreign-key needs to be dropped. mock.ExpectQuery(escape("SELECT `CONSTRAINT_NAME` FROM `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE` WHERE `TABLE_NAME` = ? AND `COLUMN_NAME` = ? AND `POSITION_IN_UNIQUE_CONSTRAINT` IS NOT NULL AND `TABLE_SCHEMA` = (SELECT DATABASE())")). WithArgs("users", "age"). @@ -787,6 +787,50 @@ func TestMySQL_Create(t *testing.T) { mock.ExpectCommit() }, }, + { + name: "increase index sub_part", + tables: func() []*Table { + t := &Table{ + Name: "users", + Columns: []*Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "text", Type: field.TypeString, Size: math.MaxInt32, Nullable: true}, + }, + PrimaryKey: []*Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + }, + Indexes: []*Index{ + {Name: "prefix_text", Annotation: &entsql.IndexAnnotation{Prefix: 100}}, + }, + } + t.Indexes[0].Columns = t.Columns[1:] + return []*Table{t} + }(), + options: []MigrateOption{WithDropIndex(true)}, + before: func(mock mysqlMock) { + mock.start("5.7.23") + mock.tableExists("users", true) + mock.ExpectQuery(escape("SELECT `column_name`, `column_type`, `is_nullable`, `column_key`, `column_default`, `extra`, `character_set_name`, `collation_name` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ?")). + WithArgs("users"). + WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). + AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). + AddRow("text", "longtext", "YES", "NO", "NULL", "", "", "")) + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + WithArgs("users"). + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1"). + AddRow("prefix_text", "text", "50", "0", "1")) + mock.ExpectQuery(escape("SELECT `CONSTRAINT_NAME` FROM `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE` WHERE `TABLE_NAME` = ? AND `COLUMN_NAME` = ? AND `POSITION_IN_UNIQUE_CONSTRAINT` IS NOT NULL AND `TABLE_SCHEMA` = (SELECT DATABASE())")). + WithArgs("users", "text"). + WillReturnRows(sqlmock.NewRows([]string{"CONSTRAINT_NAME"})) + // modify index by dropping and creating it. + mock.ExpectExec(escape("DROP INDEX `prefix_text` ON `users`")). + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectExec(escape("CREATE INDEX `prefix_text` ON `users`(`text`(100))")). + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectCommit() + }, + }, { name: "ignore foreign keys on index dropping", tables: []*Table{ @@ -818,12 +862,12 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("parent_id", "bigint(20)", "YES", "NULL", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1"). - AddRow("old_index", "old", "0", "1"). - AddRow("parent_id", "parent_id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1"). + AddRow("old_index", "old", nil, "0", "1"). + AddRow("parent_id", "parent_id", nil, "0", "1")) // drop the unique index. mock.ExpectExec(escape("DROP INDEX `old_index` ON `users`")). WillReturnResult(sqlmock.NewResult(0, 1)) @@ -854,11 +898,11 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("parent_id", "bigint(20)", "YES", "NULL", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1"). - AddRow("parent_id", "parent_id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1"). + AddRow("parent_id", "parent_id", nil, "0", "1")) // check if a foreign-key needs to be dropped. mock.ExpectQuery(escape("SELECT `CONSTRAINT_NAME` FROM `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE` WHERE `TABLE_NAME` = ? AND `COLUMN_NAME` = ? AND `POSITION_IN_UNIQUE_CONSTRAINT` IS NOT NULL AND `TABLE_SCHEMA` = (SELECT DATABASE())")). WithArgs("users", "parent_id"). @@ -897,11 +941,11 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("parent_id", "bigint(20)", "YES", "NULL", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1"). - AddRow("parent_id", "parent_id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1"). + AddRow("parent_id", "parent_id", nil, "0", "1")) // check if there's a foreign-key that is associated with this index. mock.ExpectQuery(escape("SELECT `CONSTRAINT_NAME` FROM `INFORMATION_SCHEMA`.`KEY_COLUMN_USAGE` WHERE `TABLE_NAME` = ? AND `COLUMN_NAME` = ? AND `POSITION_IN_UNIQUE_CONSTRAINT` IS NOT NULL AND `TABLE_SCHEMA` = (SELECT DATABASE())")). WithArgs("users", "parent_id"). @@ -949,10 +993,10 @@ func TestMySQL_Create(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", ""). AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectExec(escape("ALTER TABLE `users` ADD COLUMN `spouse_id` bigint NULL")). WillReturnResult(sqlmock.NewResult(0, 1)) mock.fkExists("user_spouse_____________________390ed76f91d3c57cd3516e7690f621dc", false) @@ -1016,10 +1060,10 @@ func TestMySQL_Create(t *testing.T) { WithArgs("users"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) // query groups table. mock.ExpectQuery(escape("SELECT COUNT(*) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ?")). WithArgs("groups"). @@ -1086,10 +1130,10 @@ func TestMySQL_Create(t *testing.T) { WithArgs("users"). WillReturnRows(sqlmock.NewRows([]string{"column_name", "column_type", "is_nullable", "column_key", "column_default", "extra", "character_set_name", "collation_name"}). AddRow("id", "bigint(20)", "NO", "PRI", "NULL", "auto_increment", "", "")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) // query the auto-increment value. mock.ExpectQuery(escape("SELECT `AUTO_INCREMENT` FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ?")). WithArgs("users"). @@ -1194,10 +1238,10 @@ func TestMySQL_Create(t *testing.T) { AddRow("name", "varchar(255)", "YES", "YES", "NULL", "", "", ""). AddRow("json", "longtext", "YES", "YES", "NULL", "", "utf8mb4", "utf8mb4_bin"). AddRow("longtext", "longtext", "YES", "YES", "NULL", "", "utf8mb4", "utf8mb4_bin")) - mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). + mock.ExpectQuery(escape("SELECT `index_name`, `column_name`, `sub_part`, `non_unique`, `seq_in_index` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? ORDER BY `index_name`, `seq_in_index`")). WithArgs("users"). - WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "non_unique", "seq_in_index"}). - AddRow("PRIMARY", "id", "0", "1")) + WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "sub_part", "non_unique", "seq_in_index"}). + AddRow("PRIMARY", "id", nil, "0", "1")) mock.ExpectQuery(escape("SELECT `CONSTRAINT_NAME` FROM `INFORMATION_SCHEMA`.`CHECK_CONSTRAINTS` WHERE `CONSTRAINT_SCHEMA` = (SELECT DATABASE()) AND `TABLE_NAME` = ? AND `CHECK_CLAUSE` LIKE ?")). WithArgs("users", "json_valid(%)"). WillReturnRows(sqlmock.NewRows([]string{"CONSTRAINT_NAME"}). diff --git a/dialect/sql/schema/schema.go b/dialect/sql/schema/schema.go index ae76f31e5..2681ab880 100644 --- a/dialect/sql/schema/schema.go +++ b/dialect/sql/schema/schema.go @@ -112,6 +112,15 @@ func (t *Table) column(name string) (*Column, bool) { return nil, false } +// Index returns a table index by its exact name. +func (t *Table) Index(name string) (*Index, bool) { + idx, ok := t.index(name) + if ok && idx.Name == name { + return idx, ok + } + return nil, false +} + // index returns a table index by its name. func (t *Table) index(name string) (*Index, bool) { for _, idx := range t.Indexes { @@ -407,12 +416,13 @@ func (r ReferenceOption) ConstName() string { // Index definition for table index. type Index struct { - Name string // index name. - Unique bool // uniqueness. - Columns []*Column // actual table columns. - columns []string // columns loaded from query scan. - primary bool // primary key index. - realname string // real name in the database (Postgres only). + Name string // index name. + Unique bool // uniqueness. + Columns []*Column // actual table columns. + Annotation *entsql.IndexAnnotation // index annotation. + columns []string // columns loaded from query scan. + primary bool // primary key index. + realname string // real name in the database (Postgres only). } // Builder returns the query builder for index creation. The DSL is identical in all dialects. diff --git a/entc/gen/graph.go b/entc/gen/graph.go index 11403d8aa..bbd37d8c7 100644 --- a/entc/gen/graph.go +++ b/entc/gen/graph.go @@ -507,6 +507,9 @@ func (g *Graph) Tables() (all []*schema.Table) { table := tables[n.Table()] for _, idx := range n.Indexes { table.AddIndex(idx.Name, idx.Unique, idx.Columns) + // Set the entsql.IndexAnnotation from the schema if exists. + index, _ := table.Index(idx.Name) + index.Annotation = entsqlIndexAnnotate(idx.Annotations) } } return diff --git a/entc/gen/internal/bindata.go b/entc/gen/internal/bindata.go index 4c586e01a..bd31f4ea8 100644 --- a/entc/gen/internal/bindata.go +++ b/entc/gen/internal/bindata.go @@ -1112,7 +1112,7 @@ func templateMigrateMigrateTmpl() (*asset, error) { return a, nil } -var _templateMigrateSchemaTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x58\x4d\x6f\xdb\x38\x13\x3e\x5b\xbf\x62\x20\xf8\x2d\x92\xc0\x91\xda\xdc\x5e\x03\x3e\x04\x69\xbb\x08\xba\x48\x8b\x6d\x7a\x0a\x82\x05\x23\x8d\x6c\xc2\x34\xa9\x50\x74\x1a\xaf\x56\xff\x7d\xc1\x2f\x89\x92\xe5\x38\x29\x1a\x20\x88\x48\xce\x07\xe7\x99\x79\x86\x64\xea\x3a\x3d\x8b\xae\x44\xb9\x93\x74\xb9\x52\x70\xf1\xfe\xc3\xff\xcf\x4b\x89\x15\x72\x05\x9f\x49\x86\x0f\x42\xac\xe1\x9a\x67\x09\x5c\x32\x06\x46\xa8\x02\xbd\x2e\x9f\x30\x4f\xa2\xdb\x15\xad\xa0\x12\x5b\x99\x21\x64\x22\x47\xa0\x15\x30\x9a\x21\xaf\x30\x87\x2d\xcf\x51\x82\x5a\x21\x5c\x96\x24\x5b\x21\x5c\x24\xef\xfd\x2a\x14\x62\xcb\xf3\x88\x72\xb3\xfe\xe7\xf5\xd5\xa7\x9b\xef\x9f\xa0\xa0\x0c\xc1\xcd\x49\x21\x14\xe4\x54\x62\xa6\x84\xdc\x81\x28\x40\x05\xce\x94\x44\x4c\xa2\xb3\xb4\x69\xa2\x48\xc7\x00\x4b\xa1\x76\x25\xce\x01\xb9\x5a\x8a\x84\x8a\x14\xb9\xd2\xbf\x59\xba\x44\x9e\xfc\x21\x49\xb9\x02\x2f\x0e\x39\x16\x94\x23\xc4\x55\xb6\xc2\x0d\x89\xc1\x4e\x9f\xc3\x4f\xaa\x56\x80\xcf\x0a\x79\x0e\x53\x88\xbf\x91\x6c\x4d\x96\x18\x43\xbc\xa1\x4b\x49\x14\xc6\x70\xde\x34\xd1\xa4\xae\x41\xe1\xa6\x64\x44\x21\xc4\x2b\x24\x39\xca\x18\x12\x6d\xa5\xae\x41\xeb\x6a\x7b\x74\x53\x0a\xa9\xe0\xc4\x88\x4b\xc2\x97\x08\xd3\xbf\x67\x30\xe5\x30\x5f\xc0\x34\xb9\x11\x39\x56\x5a\x70\x32\x89\xeb\x1a\xa6\xc9\x95\xe0\x05\x5d\x26\xce\x27\x34\x4d\xaa\xa7\x79\x30\x11\x6b\x53\xe7\xad\x83\x49\xdc\x8b\x35\xa7\x84\x61\x66\x62\xae\x1e\x59\x7c\x68\xb9\x7a\x64\xa9\x0b\x7b\x28\x62\xa7\xd3\x82\x22\xcb\xe3\xe8\x34\x8a\x9e\x88\xb4\xfb\x3f\x0f\x03\x50\x36\x80\x5b\xf2\xc0\x7c\x04\x5a\x22\x3d\x83\x82\xf2\x1c\x74\x1a\x80\x9b\x5a\xb0\x89\x5c\x1a\xec\x7d\xfe\x94\x56\x9b\x01\x2d\x00\x9f\x69\xa5\x2a\x9b\x14\x6b\x62\x6a\xd4\xe6\x0b\xa0\x3c\xc7\xe7\x16\xa4\xf7\x9d\x93\xc3\x38\xd6\xb5\xb1\xf9\x08\x53\x95\xdc\x90\x0d\x6a\xe8\xcc\x16\xed\x9a\x35\xbd\xd0\x6a\x66\x6c\x41\xec\xd2\xe5\x36\x90\x09\xb6\xdd\xf0\x4a\x9b\x2e\x49\x95\x11\xd6\x9a\xfb\x17\x4a\x49\xb9\x2a\x20\xfe\x5f\x75\x65\xa5\x62\xab\x98\xa6\xa0\x1d\x78\xd5\xa6\x81\x95\x60\x79\x65\x62\xf7\x93\x85\xb0\x44\x30\xa9\x76\x16\x9b\x26\xb6\x68\x24\xc6\x7b\xcf\xc2\x02\xee\xee\xcf\x6c\x3e\x12\xeb\xad\x8e\x26\x3d\x08\x32\x13\xbe\x72\xab\x2e\x0f\x93\x49\x0d\xda\xf6\xdc\x3a\xca\x5a\x47\x33\xb8\x35\xec\x30\xb9\x4d\xec\x9a\x9e\xd1\x55\x57\x29\x27\x35\xb3\x16\xea\x73\x8d\xe4\x34\x4b\x7e\x70\xfa\xb8\xd5\x0b\x60\xbf\xe6\xa0\xe4\x16\x67\x21\x68\xa1\xf8\x35\xcf\x24\x6e\x74\xe3\x68\x1a\x68\x07\x47\x94\x6e\xb6\x8c\xb9\x2c\x81\xff\x9e\x83\xdb\x7c\xb7\x36\xa2\x6f\xb8\x3a\xcd\x92\xef\xf4\x1f\xa3\xad\xff\x1a\xcd\xe4\x65\xf9\x4b\xa5\xa4\x96\xd7\x7f\x2d\x4e\x89\x41\xe8\xb0\xc6\x27\xbe\xdd\x98\xac\x98\x8f\x39\xdc\xdd\x57\x4a\x52\xbe\xac\xa1\x63\xb6\x29\x5b\x63\x48\xef\x1d\xfb\x16\x61\x6c\x3f\xb4\x00\x2e\x14\x9c\xd0\xea\x86\x32\xed\xe6\x23\x16\x64\xcb\xd4\xa9\x56\x70\xdf\x1e\x09\x37\x1c\x0f\x4c\x1b\x42\x38\x61\xc8\xb5\xe8\x95\x60\x8c\x28\x2a\xf8\xa9\xe1\x0d\xb4\x63\x6f\xab\x9d\x38\x02\xab\x29\x3e\x5d\x23\x06\xdc\x76\x34\x87\x0d\x29\xef\x2c\x00\x23\x38\xac\x67\x30\x7d\xea\x61\xb1\xd6\x1f\xae\x20\x9f\xfa\xb8\x74\xfc\xb3\xb5\x17\x74\xb7\xc9\xa4\xe5\xa4\xe1\xc8\x11\x46\x1a\xa6\xf7\xf9\xa8\x7c\x59\x75\x6c\xb4\x84\x02\xca\x0b\x21\x37\x16\x83\x57\x11\xb3\x35\xb5\x80\x77\x8e\x94\xc6\xa1\xe1\x64\xc0\xb7\x4e\xdf\x84\xe3\xa8\x39\x1f\xb4\x07\xb3\xf6\x4d\xd2\x0d\x91\xbb\x2f\xb8\x9b\x8f\x53\x7d\xd8\xee\xca\xb5\x23\x7c\xa7\xe9\xd3\x16\x8a\xd2\xd9\xc1\xd6\xd0\x56\x8b\x6e\x92\xe5\xda\x75\xc9\xb6\x47\xf4\x37\x79\xa7\x87\x14\x9a\xe6\x7e\x50\x23\xfd\x24\x0d\x87\x36\xb8\xcf\x42\x22\x5d\xf2\x2f\xb8\xab\xc2\xe8\xba\xe9\xbd\x08\x0b\x1f\x5d\xa0\xda\x79\x74\xdb\xff\xbe\xdb\x3c\x08\xe6\xb0\x2e\xd6\x89\x1d\xb7\x70\x87\x88\x8f\x43\x3a\x01\xe8\xf7\xd0\x0f\xc6\x6b\xb1\xde\x87\x6a\x1f\xd4\x8b\x43\xa8\xf6\x81\xcd\x3e\x78\x60\x2f\xde\x8a\xec\x3e\xb8\x63\x33\xcd\x2c\xc8\x66\x7a\x06\xa5\xa8\x54\x29\x38\x82\xc4\x42\x22\xcf\x28\x5f\x82\x12\x40\x9e\x04\xb5\x87\x71\xb6\xc2\x6c\xad\x67\x99\x10\x65\x7b\xde\xea\x9f\xbf\xb0\xf8\x65\xc4\x3a\xdd\xe3\xa0\x59\x71\x43\x99\x5f\x83\xcf\x33\x3f\x34\xf4\xd2\xa9\xfc\x5b\x31\xb6\x1d\xb1\x58\x27\x5f\xf9\x8f\x32\x27\xaa\x7f\x68\x7a\x1b\x7e\x71\xee\xba\x4c\xe2\x4f\xa2\xe8\x80\x8f\x81\xe9\x8f\xc8\xf0\xa0\x69\xbb\xf8\x5a\xd3\xc1\x41\x3e\x64\xa6\x3f\x78\x55\x72\xad\xaf\x58\xd8\xe6\xc1\x0d\xc3\x3a\x30\x53\xf5\x5e\x87\xd1\xcd\x88\xe6\xcf\x8e\x0d\x03\x33\x1d\x59\xc3\xbe\x48\xf3\xe7\x7e\x67\xd4\x3f\xfe\x4e\xe1\x05\xda\xdb\x46\x2b\x71\xac\x36\xf7\xf7\xe5\xca\x53\x9b\x3b\x54\x67\xaf\xa5\xf4\xef\xe3\xf4\x48\xc1\x8d\x4c\xb5\x61\xfb\x8f\x81\xc8\xf8\x09\x19\x8e\xd3\x14\xdc\x9d\xdc\x9e\x78\x84\x31\x73\xb4\x29\x3b\xe9\x6e\xe3\x0e\xc8\x68\xe2\x64\xc3\x9b\x66\x7b\xa8\x1d\xbf\xf1\x4f\x02\x56\xbe\x74\x1e\xcf\xa2\xfe\xa6\x1b\xfd\xae\x28\xb6\x3c\x03\xca\xa9\x3a\x39\x85\xba\xf7\xbe\x38\xf0\xb6\x78\xf3\x1d\x60\x90\xe9\x17\x8e\x97\xf0\x7c\x0f\x97\xbb\x94\xb6\x2d\x07\x16\xf0\xda\x5e\x34\xdc\x4b\xef\x95\x61\x59\x4f\xb8\x72\x9b\xba\xe4\x5c\x28\x7f\x25\xdb\xdb\x53\xb0\xba\x80\x77\xf6\x75\x17\x4c\xd6\x83\x9b\x1b\xe1\xaa\x7d\xf7\xd8\x42\xba\xb5\x77\xea\xee\xa6\x3b\xd2\x1d\x06\x06\xae\x56\x44\x56\xa8\x5a\x13\x6e\xfc\x46\x23\xc1\x45\x33\xf2\x84\xf6\x77\xd1\xb7\x18\xfa\x5a\x6a\x9d\x8e\x9e\x6e\x7c\xc4\x48\x13\xed\x19\x6a\x1f\x25\x84\x75\x9e\x46\xa1\xee\x89\x2e\x80\xe3\xcf\x93\x07\x21\xd8\xa9\xd1\x39\x7b\x9d\x52\x5d\x5b\xd7\x94\xdb\xff\x62\x98\xad\xea\xc7\x90\x6e\x11\xac\xd2\xca\x05\x61\x15\xf6\x3a\xc6\x5e\xb1\xf8\x41\xf0\x6d\xff\x87\xe1\x06\xff\x05\x00\x00\xff\xff\x20\xde\x7a\x38\xc1\x11\x00\x00") +var _templateMigrateSchemaTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x58\x4d\x6f\xdb\x38\x13\x3e\x5b\xbf\x62\x20\xf8\x2d\x92\xc0\x91\xdb\xdc\x5e\x03\x3e\x04\x69\xbb\x08\xba\x48\x8b\x6d\x7a\x0a\x8a\x05\x23\x8d\x6c\xc2\x34\xa9\x50\x74\x9a\xac\x56\xff\x7d\xc1\x0f\x51\xa4\x2c\xe7\xa3\xdb\xcb\x16\x28\x2c\x92\x33\xcf\x90\xcf\x7c\x90\x93\xa6\x99\x9f\x24\x17\xa2\x7a\x94\x74\xb5\x56\x70\xf6\xf6\xdd\xff\x4f\x2b\x89\x35\x72\x05\x1f\x49\x8e\xb7\x42\x6c\xe0\x92\xe7\x19\x9c\x33\x06\x46\xa8\x06\xbd\x2e\xef\xb1\xc8\x92\xeb\x35\xad\xa1\x16\x3b\x99\x23\xe4\xa2\x40\xa0\x35\x30\x9a\x23\xaf\xb1\x80\x1d\x2f\x50\x82\x5a\x23\x9c\x57\x24\x5f\x23\x9c\x65\x6f\xbb\x55\x28\xc5\x8e\x17\x09\xe5\x66\xfd\xf7\xcb\x8b\x0f\x57\x5f\x3f\x40\x49\x19\x82\x9b\x93\x42\x28\x28\xa8\xc4\x5c\x09\xf9\x08\xa2\x04\x15\x18\x53\x12\x31\x4b\x4e\xe6\x6d\x9b\x24\xfa\x0c\xb0\x12\xea\xb1\xc2\x05\x20\x57\x2b\x91\x51\x31\x47\xae\xf4\xff\x7c\xbe\x42\x9e\xfd\x26\x49\xb5\x86\x4e\x1c\x0a\x2c\x29\x47\x48\xeb\x7c\x8d\x5b\x92\x82\x9d\x3e\x85\x1f\x54\xad\x01\x1f\x14\xf2\x02\xa6\x90\x7e\x21\xf9\x86\xac\x30\x85\x74\x4b\x57\x92\x28\x4c\xe1\xb4\x6d\x93\x49\xd3\x80\xc2\x6d\xc5\x88\x42\x48\xd7\x48\x0a\x94\x29\x64\x1a\xa5\x69\x40\xeb\x6a\x3c\xba\xad\x84\x54\x70\x64\xc4\x25\xe1\x2b\x84\xe9\x9f\x33\x98\x72\x58\x2c\x61\x9a\x5d\x89\x02\x6b\x2d\x38\x99\xa4\x4d\x03\xd3\xec\x42\xf0\x92\xae\x32\x67\x13\xda\x76\xae\xa7\x79\x30\x91\x6a\xa8\x53\x6f\x60\x92\x46\x67\x2d\x28\x61\x98\x9b\x33\xd7\x77\x2c\x3d\xb4\x5c\xdf\xb1\xb9\x3b\xf6\x50\xc4\x4e\xcf\x4b\x8a\xac\x48\x93\xe3\x24\xb9\x27\xd2\xee\xff\x34\x3c\x80\xb2\x07\xb8\x26\xb7\xac\x3b\x81\x96\x98\x9f\x40\x49\x79\x01\xda\x0d\xc0\x4d\x2c\x58\x47\xae\x0c\xf7\x9d\xff\x94\x56\x9b\x01\x2d\x01\x1f\x68\xad\x6a\xeb\x14\x0b\x31\x35\x6a\x8b\x25\x50\x5e\xe0\x83\x27\xe9\x6d\x6f\xe4\x30\x8f\x4d\x63\x30\xef\x60\xaa\xb2\x2b\xb2\x45\x4d\x9d\xd9\xa2\x5d\xb3\xd0\x4b\xad\x66\xc6\x96\xc4\xde\x5d\x6e\x03\xb9\x60\xbb\x2d\xaf\x35\x74\x45\xea\x9c\x30\x0f\xf7\x37\x54\x92\x72\x55\x42\xfa\xbf\xfa\xc2\x4a\xa5\x56\x71\x3e\x07\x6d\xa0\x53\x6d\x5b\x58\x0b\x56\xd4\xe6\xec\xdd\x64\x29\x6c\x22\x18\x57\x3b\xc4\xb6\x4d\x2d\x1b\x99\xb1\x1e\x21\x2c\xe1\xe6\xfb\x89\xf5\x47\x66\xad\x35\xc9\x24\xa2\x20\x37\xc7\x57\x6e\xd5\xf9\x61\x32\x69\x40\x63\x2f\xac\xa1\xdc\x1b\x9a\xc1\xb5\xc9\x0e\xe3\xdb\xcc\xae\xe9\x19\x1d\x75\xb5\x72\x52\x33\x8b\xd0\x9c\x6a\x26\xa7\x79\xf6\x8d\xd3\xbb\x9d\x5e\x00\xfb\xb5\x00\x25\x77\x38\x0b\x49\x0b\xc5\x2f\x79\x2e\x71\xab\x0b\x47\xdb\x82\x1f\x3c\xa3\x74\xb5\x63\xcc\x79\x09\xba\xef\x05\xb8\xcd\xf7\x6b\x23\xfa\x26\x57\xa7\x79\xf6\x95\xfe\x65\xb4\xf5\xaf\xd1\xcc\x9e\x96\x3f\x57\x4a\x6a\x79\xfd\x6b\x79\xca\x0c\x43\x87\x35\x3e\xf0\xdd\xd6\x78\xc5\x7c\x2c\xe0\xe6\x7b\xad\x24\xe5\xab\x06\xfa\xcc\x36\x61\x6b\x80\xf4\xde\x31\x46\x84\xb1\xfd\xd0\x12\xb8\x50\x70\x44\xeb\x2b\xca\xb4\x99\xf7\x58\x92\x1d\x53\xc7\x5a\xc1\x7d\x77\x4c\xb8\xe1\xf8\xc1\x34\x10\xc2\x11\x43\xae\x45\x2f\x04\x63\x44\x51\xc1\x8f\x4d\xde\x80\x1f\x77\x58\x7e\xe2\x19\x5a\x4d\xf0\xe9\x18\x31\xe4\xfa\xd1\x02\xb6\xa4\xba\xb1\x04\x8c\xf0\xb0\x99\xc1\xf4\x3e\xe2\x62\xa3\x3f\x5c\x40\xde\xc7\xbc\xf4\xf9\x67\x63\x2f\xa8\x6e\x93\x89\xcf\x49\x93\x23\xcf\x64\xa4\xc9\xf4\x38\x1f\x55\x17\x56\x7d\x36\xda\x84\x02\xca\x4b\x21\xb7\x96\x83\x17\x25\xa6\x87\x5a\xc2\x1b\x97\x94\xc6\xa0\xc9\xc9\x20\xdf\x7a\x7d\x73\x1c\x97\x9a\x8b\x41\x79\x30\x6b\x5f\x24\xdd\x12\xf9\xf8\x09\x1f\x17\xe3\xa9\x1e\xe6\x7a\xb5\x71\xc9\xde\x6b\x75\x2e\x0b\xc5\xe8\xec\x60\x59\xf0\x91\xa2\x0b\x64\xb5\x71\x15\xd2\xd7\x87\x78\x83\x37\x7a\x48\xa1\x6d\xbf\x0f\xe2\x23\x76\xd0\x70\xd8\xfb\xd0\xc6\x50\xb9\xa9\xdd\x66\x3e\x0a\x89\x74\xc5\x3f\xe1\xa3\xdf\x50\x30\x15\x12\xd0\x4f\x37\x7b\xc7\x2b\x2d\x0b\x1a\xb6\x3f\x95\xfb\x9d\x7c\x7d\xdc\xde\x0a\xe6\xfc\x50\x6e\x32\x3b\xf6\xae\x98\x84\xee\x18\xe7\x7b\x60\x2d\x7f\xe7\xac\xed\x53\x39\xc2\xfa\xd9\x21\xda\x07\xd4\xe7\xef\x3a\xea\xcf\x5e\xcb\xfd\x08\xff\xe3\x53\xad\x3f\xb1\xbb\x96\x2b\x51\xab\x4a\x70\x04\x89\xa5\x44\x9e\x53\xbe\x02\x25\x80\xdc\x0b\x6a\xaf\xeb\x7c\x8d\xf9\x46\xcf\x32\x21\x2a\x7f\x23\x9b\x7f\x7f\x60\xf9\xb3\xbc\xf5\xaa\x2f\xa0\xce\xca\x9b\xac\xfa\x49\x12\xbb\xea\x10\x22\x3d\x75\x73\xff\x72\xa6\xbb\xa8\xcf\x3e\xf3\x6f\x55\x41\x54\x7c\xb9\x7a\x98\x6e\x75\xe1\xca\x51\xd6\x5d\x59\xc9\x41\x3b\x03\xf4\xf7\xc8\xf0\x30\xba\x5d\x7d\x39\x7a\xb7\x34\x58\x18\xa9\xc8\xfe\xda\x56\xd9\xa5\x7e\xa0\xa1\x77\x91\x1b\x86\x21\x62\xa6\xf6\x93\x98\x16\x0f\x2e\x55\x06\x10\x41\x2e\x07\x15\x95\x16\x0f\x71\x4d\xd5\xff\xba\xd7\x48\x27\xe0\xdf\x29\xff\x2e\xd5\x35\xd4\x7f\x3b\xd7\x6d\x8c\x10\xae\xfc\x79\xce\x39\x17\xaa\xbb\xed\x3d\x4e\x3f\xbb\x80\x37\xb6\x5f\xb0\xee\xe8\x17\x9a\x78\x23\x1e\x39\xfb\x22\xb1\xa4\x0f\xf1\xa1\xed\x5c\xff\xf8\x7a\xf2\x10\x01\xde\x46\x5f\x08\x8b\x25\x98\xdf\x00\x7d\x94\xd9\x68\x29\x7a\x85\xec\x28\x57\xc1\x7e\x23\x8f\xd9\x3b\x63\x13\xdc\x3c\xa1\xd0\xfc\x04\xbe\xd5\x18\xbc\xd4\x75\x89\x44\x5d\x23\x75\xf7\x52\x2b\x24\x85\x6e\x5c\x76\xb5\x2e\x8e\x92\xfc\x00\x6b\x31\x8b\x4a\xe4\x68\x90\x3c\x15\x23\x71\x98\x6c\x82\x7b\x38\x16\x9a\x1c\x0a\x97\xcc\x66\x88\x6e\x79\x6c\xa3\xb4\x4f\x9d\x79\x76\xcd\x86\x46\xf7\x7c\x71\xc0\x45\x07\x66\x9f\xf1\xec\x2f\x29\x32\x6d\xd4\xe4\xea\xc7\x9c\x6b\x34\xed\x33\x8e\x30\x66\xdc\xa5\xec\xa4\x6b\x31\x5d\x8e\x27\x13\x27\x1b\xb6\x4f\xfe\xa5\xf6\x7c\x1b\x3b\x09\xae\x91\xa7\x1e\x99\xb3\x24\xde\x74\xab\x9b\xe5\x72\xc7\x73\xa0\x9c\xaa\xa3\x63\x68\xa2\xa6\xf9\x40\xc3\xfc\xea\x87\xed\x20\xc6\xca\xcd\xc1\xe7\x55\xf8\x68\x0d\x97\x83\x10\xea\xee\x48\x58\xc2\x4b\x2f\xcf\xe1\x5e\xa2\xd6\x39\xae\x3d\x6a\xbf\xf2\x44\x7b\x0a\x56\x97\xbe\x04\x0d\xab\x4f\x5c\x78\xba\x66\xde\x06\xd2\xb5\x6d\x14\xfb\xf6\x6d\xe4\x41\x3a\x00\xb8\x58\x13\x59\xa3\xf2\x10\x6e\xfc\x4a\x90\xa0\x7b\x72\x30\x7d\x83\xf5\x1a\xa0\xcf\x95\xd6\xe9\x2b\x83\x1b\x3f\x03\xd2\x26\x7b\x40\xbe\xd3\x26\xac\xb7\x34\x4a\x75\x24\xba\x04\x8e\x3f\x8e\x6e\x85\x60\xc7\x46\xe7\xe4\x65\x4a\x4d\x63\x4d\x53\x6e\xff\x34\x67\xb6\xaa\x3b\x7c\x5d\x5c\x58\xad\x95\x4b\xc2\x6a\x8c\x6a\xcd\x5e\xb0\x74\x83\xe0\xdb\xfe\x61\xce\x0d\xfe\x09\x00\x00\xff\xff\x3c\xe2\x97\xd3\x96\x14\x00\x00") func templateMigrateSchemaTmplBytes() ([]byte, error) { return bindataRead( @@ -1127,7 +1127,7 @@ func templateMigrateSchemaTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/migrate/schema.tmpl", size: 4545, mode: os.FileMode(420), modTime: time.Unix(1, 0)} + info := bindataFileInfo{name: "template/migrate/schema.tmpl", size: 5270, mode: os.FileMode(420), modTime: time.Unix(1, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/entc/gen/template/migrate/schema.tmpl b/entc/gen/template/migrate/schema.tmpl index aa27b2029..1e50e08e7 100644 --- a/entc/gen/template/migrate/schema.tmpl +++ b/entc/gen/template/migrate/schema.tmpl @@ -49,53 +49,74 @@ var ( Name: "{{ $t.Name }}", Columns: {{ $columns }}, PrimaryKey: []*schema.Column{ - {{- range $_, $pk := $t.PrimaryKey }} + {{- range $pk := $t.PrimaryKey }} {{- range $i, $c := $t.Columns }} {{- if eq $pk.Name $c.Name }}{{ $columns }}[{{ $i }}],{{ end }} {{- end }} {{- end }} }, - ForeignKeys: []*schema.ForeignKey{ - {{- range $fk := $t.ForeignKeys }} - { - Symbol: "{{ $fk.Symbol }}", - Columns: []*schema.Column{ - {{- range $c1 := $fk.Columns }} - {{- range $i, $c2 := $t.Columns }} - {{- if eq $c1.Name $c2.Name }}{{ $columns }}[{{ $i }}],{{ end }} - {{- end }} - {{- end }} - }, - {{- /* postpone refrencing to avoid typechecking loops */}} - RefColumns: []*schema.Column{ - {{- range $c1 := $fk.RefColumns }} - {{- range $i, $c2 := $fk.RefTable.Columns }} - {{- if eq $c1.Name $c2.Name }}{{ pascal $fk.RefTable.Name | printf "%sColumns" }}[{{ $i }}],{{ end }} - {{- end }} - {{- end }} - }, - {{- with $fk.OnUpdate.ConstName }} - OnUpdate: schema.{{ . }}, - {{- end }} - {{- with $fk.OnDelete.ConstName }} - OnDelete: schema.{{ . }}, - {{- end }} - }, - {{- end }} - }, - {{- if $t.Indexes }} - Indexes: []*schema.Index{ - {{- range $_, $idx := $t.Indexes }} + {{- with $fks := $t.ForeignKeys }} + ForeignKeys: []*schema.ForeignKey{ + {{- range $fk := $fks }} { - Name: "{{ $idx.Name }}", - Unique: {{ $idx.Unique }}, + Symbol: "{{ $fk.Symbol }}", Columns: []*schema.Column{ - {{- range $_, $c1 := $idx.Columns }} + {{- range $c1 := $fk.Columns }} {{- range $i, $c2 := $t.Columns }} {{- if eq $c1.Name $c2.Name }}{{ $columns }}[{{ $i }}],{{ end }} {{- end }} {{- end }} }, + {{- /* postpone refrencing to avoid typechecking loops */}} + RefColumns: []*schema.Column{ + {{- range $c1 := $fk.RefColumns }} + {{- range $i, $c2 := $fk.RefTable.Columns }} + {{- if eq $c1.Name $c2.Name }}{{ pascal $fk.RefTable.Name | printf "%sColumns" }}[{{ $i }}],{{ end }} + {{- end }} + {{- end }} + }, + {{- with $fk.OnUpdate.ConstName }} + OnUpdate: schema.{{ . }}, + {{- end }} + {{- with $fk.OnDelete.ConstName }} + OnDelete: schema.{{ . }}, + {{- end }} + }, + {{- end }} + }, + {{- end }} + {{- if $t.Indexes }} + Indexes: []*schema.Index{ + {{- range $idx := $t.Indexes }} + { + Name: "{{ $idx.Name }}", + Unique: {{ $idx.Unique }}, + Columns: []*schema.Column{ + {{- range $c1 := $idx.Columns }} + {{- range $i, $c2 := $t.Columns }} + {{- if eq $c1.Name $c2.Name }}{{ $columns }}[{{ $i }}],{{ end }} + {{- end }} + {{- end }} + }, + {{- with $ant := $idx.Annotation }} + Annotation: &entsql.IndexAnnotation{ + {{- with $ant.Prefix }} + Prefix: {{ . }}, + {{- end }} + {{- with $keys := keys $ant.PrefixColumns }} + PrefixColumns: map[string]uint{ + {{- range $k := $keys }} + {{- /* Use the column reference instead of using raw string. */}} + {{- range $i, $c := $t.Columns }} + {{- if eq $k $c.Name }} + {{ $columns }}[{{ $i }}].Name: {{ index $ant.PrefixColumns $k }}, + {{ end }} + {{- end }} + {{- end }} + }, + {{- end }} + }, + {{- end }} }, {{- end }} }, diff --git a/entc/gen/type.go b/entc/gen/type.go index dcb5de2f5..06cd270aa 100644 --- a/entc/gen/type.go +++ b/entc/gen/type.go @@ -152,6 +152,9 @@ type ( Unique bool // Columns are the table columns. Columns []string + // Annotations that were defined for the index in the schema. + // The mapping is from the Annotation.Name() to a JSON decoded object. + Annotations Annotations } // ForeignKey holds the information for foreign-key columns of types. @@ -525,10 +528,19 @@ func (t Type) TagTypes() []string { // AddIndex adds a new index for the type. // It fails if the schema index is invalid. func (t *Type) AddIndex(idx *load.Index) error { - index := &Index{Name: idx.StorageKey, Unique: idx.Unique} + index := &Index{Name: idx.StorageKey, Unique: idx.Unique, Annotations: idx.Annotations} if len(idx.Fields) == 0 && len(idx.Edges) == 0 { return fmt.Errorf("missing fields or edges") } + switch ant := entsqlIndexAnnotate(idx.Annotations); { + case ant == nil: + case len(ant.PrefixColumns) != 0 && ant.Prefix != 0: + return fmt.Errorf("index %q cannot contain both entsql.Prefix and entsql.PrefixColumn in annotation", index.Name) + case ant.Prefix != 0 && len(idx.Fields)+len(idx.Edges) != 1: + return fmt.Errorf("entsql.Prefix is used in a multicolumn index %q. Use entsql.PrefixColumn instead", index.Name) + case len(ant.PrefixColumns) > len(idx.Fields)+len(idx.Fields): + return fmt.Errorf("index %q has more entsql.PrefixColumn than column in its definitions", index.Name) + } for _, name := range idx.Fields { var f *Field if name == t.ID.Name { @@ -540,9 +552,6 @@ func (t *Type) AddIndex(idx *load.Index) error { return fmt.Errorf("unknown index field %q", name) } } - if f.def.Size != nil && *f.def.Size > schema.DefaultStringLen { - return fmt.Errorf("field %q exceeds the index size limit (%d)", name, schema.DefaultStringLen) - } index.Columns = append(index.Columns, f.StorageKey()) } for _, name := range idx.Edges { @@ -1634,6 +1643,18 @@ func entsqlAnnotate(annotation map[string]interface{}) *entsql.Annotation { return annotate } +// entsqlIndexAnnotate extracts the entsql annotation from a loaded annotation format. +func entsqlIndexAnnotate(annotation map[string]interface{}) *entsql.IndexAnnotation { + annotate := &entsql.IndexAnnotation{} + if annotation == nil || annotation[annotate.Name()] == nil { + return nil + } + if buf, err := json.Marshal(annotation[annotate.Name()]); err == nil { + _ = json.Unmarshal(buf, &annotate) + } + return annotate +} + var ( // global identifiers used by the generated package. globalIdent = names( diff --git a/entc/gen/type_test.go b/entc/gen/type_test.go index 901fe3022..53e916d9c 100644 --- a/entc/gen/type_test.go +++ b/entc/gen/type_test.go @@ -224,9 +224,6 @@ func TestType_AddIndex(t *testing.T) { err = typ.AddIndex(&load.Index{Unique: true, Fields: []string{"id"}}) require.NoError(t, err, "valid index for ID field") - err = typ.AddIndex(&load.Index{Unique: true, Fields: []string{"text"}}) - require.Error(t, err, "index size exceeded") - err = typ.AddIndex(&load.Index{Unique: true, Fields: []string{"name"}, Edges: []string{"parent"}}) require.Error(t, err, "missing edge") diff --git a/entc/integration/cascadelete/ent/migrate/schema.go b/entc/integration/cascadelete/ent/migrate/schema.go index 5cad25c3b..18e8f5419 100644 --- a/entc/integration/cascadelete/ent/migrate/schema.go +++ b/entc/integration/cascadelete/ent/migrate/schema.go @@ -59,10 +59,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/entc/integration/config/ent/migrate/schema.go b/entc/integration/config/ent/migrate/schema.go index e5fd9fa3d..5cb2de59e 100644 --- a/entc/integration/config/ent/migrate/schema.go +++ b/entc/integration/config/ent/migrate/schema.go @@ -21,10 +21,9 @@ var ( } // UsersTable holds the schema information for the "Users" table. UsersTable = &schema.Table{ - Name: "Users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "Users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/entc/integration/customid/ent/migrate/schema.go b/entc/integration/customid/ent/migrate/schema.go index 58627e297..8a88607f3 100644 --- a/entc/integration/customid/ent/migrate/schema.go +++ b/entc/integration/customid/ent/migrate/schema.go @@ -80,10 +80,9 @@ var ( } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ - Name: "groups", - Columns: GroupsColumns, - PrimaryKey: []*schema.Column{GroupsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "groups", + Columns: GroupsColumns, + PrimaryKey: []*schema.Column{GroupsColumns[0]}, } // MixinIdsColumns holds the columns for the "mixin_ids" table. MixinIdsColumns = []*schema.Column{ @@ -93,10 +92,9 @@ var ( } // MixinIdsTable holds the schema information for the "mixin_ids" table. MixinIdsTable = &schema.Table{ - Name: "mixin_ids", - Columns: MixinIdsColumns, - PrimaryKey: []*schema.Column{MixinIdsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "mixin_ids", + Columns: MixinIdsColumns, + PrimaryKey: []*schema.Column{MixinIdsColumns[0]}, Indexes: []*schema.Index{ { Name: "mixinid_id", diff --git a/entc/integration/edgefield/ent/migrate/schema.go b/entc/integration/edgefield/ent/migrate/schema.go index f4b20c815..22fba04aa 100644 --- a/entc/integration/edgefield/ent/migrate/schema.go +++ b/entc/integration/edgefield/ent/migrate/schema.go @@ -19,10 +19,9 @@ var ( } // CarsTable holds the schema information for the "cars" table. CarsTable = &schema.Table{ - Name: "cars", - Columns: CarsColumns, - PrimaryKey: []*schema.Column{CarsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "cars", + Columns: CarsColumns, + PrimaryKey: []*schema.Column{CarsColumns[0]}, } // CardsColumns holds the columns for the "cards" table. CardsColumns = []*schema.Column{ diff --git a/entc/integration/ent/migrate/schema.go b/entc/integration/ent/migrate/schema.go index dfe69e5ac..ddc38e3e6 100644 --- a/entc/integration/ent/migrate/schema.go +++ b/entc/integration/ent/migrate/schema.go @@ -63,10 +63,9 @@ var ( } // CommentsTable holds the schema information for the "comments" table. CommentsTable = &schema.Table{ - Name: "comments", - Columns: CommentsColumns, - PrimaryKey: []*schema.Column{CommentsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "comments", + Columns: CommentsColumns, + PrimaryKey: []*schema.Column{CommentsColumns[0]}, } // FieldTypesColumns holds the columns for the "field_types" table. FieldTypesColumns = []*schema.Column{ @@ -219,10 +218,9 @@ var ( } // FileTypesTable holds the schema information for the "file_types" table. FileTypesTable = &schema.Table{ - Name: "file_types", - Columns: FileTypesColumns, - PrimaryKey: []*schema.Column{FileTypesColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "file_types", + Columns: FileTypesColumns, + PrimaryKey: []*schema.Column{FileTypesColumns[0]}, } // GoodsColumns holds the columns for the "goods" table. GoodsColumns = []*schema.Column{ @@ -230,10 +228,9 @@ var ( } // GoodsTable holds the schema information for the "goods" table. GoodsTable = &schema.Table{ - Name: "goods", - Columns: GoodsColumns, - PrimaryKey: []*schema.Column{GoodsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "goods", + Columns: GoodsColumns, + PrimaryKey: []*schema.Column{GoodsColumns[0]}, } // GroupsColumns holds the columns for the "groups" table. GroupsColumns = []*schema.Column{ @@ -267,10 +264,9 @@ var ( } // GroupInfosTable holds the schema information for the "group_infos" table. GroupInfosTable = &schema.Table{ - Name: "group_infos", - Columns: GroupInfosColumns, - PrimaryKey: []*schema.Column{GroupInfosColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "group_infos", + Columns: GroupInfosColumns, + PrimaryKey: []*schema.Column{GroupInfosColumns[0]}, } // ItemsColumns holds the columns for the "items" table. ItemsColumns = []*schema.Column{ @@ -278,10 +274,9 @@ var ( } // ItemsTable holds the schema information for the "items" table. ItemsTable = &schema.Table{ - Name: "items", - Columns: ItemsColumns, - PrimaryKey: []*schema.Column{ItemsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "items", + Columns: ItemsColumns, + PrimaryKey: []*schema.Column{ItemsColumns[0]}, } // NodesColumns holds the columns for the "nodes" table. NodesColumns = []*schema.Column{ @@ -345,10 +340,9 @@ var ( } // SpecsTable holds the schema information for the "specs" table. SpecsTable = &schema.Table{ - Name: "specs", - Columns: SpecsColumns, - PrimaryKey: []*schema.Column{SpecsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "specs", + Columns: SpecsColumns, + PrimaryKey: []*schema.Column{SpecsColumns[0]}, } // TasksColumns holds the columns for the "tasks" table. TasksColumns = []*schema.Column{ @@ -357,10 +351,9 @@ var ( } // TasksTable holds the schema information for the "tasks" table. TasksTable = &schema.Table{ - Name: "tasks", - Columns: TasksColumns, - PrimaryKey: []*schema.Column{TasksColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "tasks", + Columns: TasksColumns, + PrimaryKey: []*schema.Column{TasksColumns[0]}, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ diff --git a/entc/integration/json/ent/migrate/schema.go b/entc/integration/json/ent/migrate/schema.go index 70b817cd3..ae0196d63 100644 --- a/entc/integration/json/ent/migrate/schema.go +++ b/entc/integration/json/ent/migrate/schema.go @@ -25,10 +25,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/entc/integration/migrate/entv1/migrate/schema.go b/entc/integration/migrate/entv1/migrate/schema.go index ecc8252ca..aafe9c888 100644 --- a/entc/integration/migrate/entv1/migrate/schema.go +++ b/entc/integration/migrate/entv1/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" ) @@ -46,10 +47,9 @@ var ( } // ConversionsTable holds the schema information for the "conversions" table. ConversionsTable = &schema.Table{ - Name: "conversions", - Columns: ConversionsColumns, - PrimaryKey: []*schema.Column{ConversionsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "conversions", + Columns: ConversionsColumns, + PrimaryKey: []*schema.Column{ConversionsColumns[0]}, } // CustomTypesColumns holds the columns for the "custom_types" table. CustomTypesColumns = []*schema.Column{ @@ -58,16 +58,16 @@ var ( } // CustomTypesTable holds the schema information for the "custom_types" table. CustomTypesTable = &schema.Table{ - Name: "custom_types", - Columns: CustomTypesColumns, - PrimaryKey: []*schema.Column{CustomTypesColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "custom_types", + Columns: CustomTypesColumns, + PrimaryKey: []*schema.Column{CustomTypesColumns[0]}, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ {Name: "oid", Type: field.TypeInt, Increment: true}, {Name: "age", Type: field.TypeInt32}, {Name: "name", Type: field.TypeString, Size: 10}, + {Name: "description", Type: field.TypeString, Nullable: true, Size: 2147483647}, {Name: "nickname", Type: field.TypeString, Unique: true}, {Name: "address", Type: field.TypeString, Nullable: true}, {Name: "renamed", Type: field.TypeString, Nullable: true}, @@ -86,22 +86,30 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "users_users_children", - Columns: []*schema.Column{UsersColumns[10]}, + Columns: []*schema.Column{UsersColumns[11]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.SetNull, }, { Symbol: "users_users_spouse", - Columns: []*schema.Column{UsersColumns[11]}, + Columns: []*schema.Column{UsersColumns[12]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.SetNull, }, }, Indexes: []*schema.Index{ + { + Name: "user_description", + Unique: false, + Columns: []*schema.Column{UsersColumns[3]}, + Annotation: &entsql.IndexAnnotation{ + Prefix: 50, + }, + }, { Name: "user_name_address", Unique: true, - Columns: []*schema.Column{UsersColumns[2], UsersColumns[4]}, + Columns: []*schema.Column{UsersColumns[2], UsersColumns[5]}, }, }, } diff --git a/entc/integration/migrate/entv1/mutation.go b/entc/integration/migrate/entv1/mutation.go index 864e2377a..eade5d241 100644 --- a/entc/integration/migrate/entv1/mutation.go +++ b/entc/integration/migrate/entv1/mutation.go @@ -1815,6 +1815,7 @@ type UserMutation struct { age *int32 addage *int32 name *string + description *string nickname *string address *string renamed *string @@ -2014,6 +2015,55 @@ func (m *UserMutation) ResetName() { m.name = nil } +// SetDescription sets the "description" field. +func (m *UserMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *UserMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" 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) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ClearDescription clears the value of the "description" field. +func (m *UserMutation) ClearDescription() { + m.description = nil + m.clearedFields[user.FieldDescription] = struct{}{} +} + +// DescriptionCleared returns if the "description" field was cleared in this mutation. +func (m *UserMutation) DescriptionCleared() bool { + _, ok := m.clearedFields[user.FieldDescription] + return ok +} + +// ResetDescription resets all changes to the "description" field. +func (m *UserMutation) ResetDescription() { + m.description = nil + delete(m.clearedFields, user.FieldDescription) +} + // SetNickname sets the "nickname" field. func (m *UserMutation) SetNickname(s string) { m.nickname = &s @@ -2528,13 +2578,16 @@ 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, 9) + fields := make([]string, 0, 10) if m.age != nil { fields = append(fields, user.FieldAge) } if m.name != nil { fields = append(fields, user.FieldName) } + if m.description != nil { + fields = append(fields, user.FieldDescription) + } if m.nickname != nil { fields = append(fields, user.FieldNickname) } @@ -2568,6 +2621,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { return m.Age() case user.FieldName: return m.Name() + case user.FieldDescription: + return m.Description() case user.FieldNickname: return m.Nickname() case user.FieldAddress: @@ -2595,6 +2650,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldAge(ctx) case user.FieldName: return m.OldName(ctx) + case user.FieldDescription: + return m.OldDescription(ctx) case user.FieldNickname: return m.OldNickname(ctx) case user.FieldAddress: @@ -2632,6 +2689,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetName(v) return nil + case user.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) + return nil case user.FieldNickname: v, ok := value.(string) if !ok { @@ -2726,6 +2790,9 @@ func (m *UserMutation) AddField(name string, value ent.Value) error { // mutation. func (m *UserMutation) ClearedFields() []string { var fields []string + if m.FieldCleared(user.FieldDescription) { + fields = append(fields, user.FieldDescription) + } if m.FieldCleared(user.FieldAddress) { fields = append(fields, user.FieldAddress) } @@ -2758,6 +2825,9 @@ func (m *UserMutation) FieldCleared(name string) bool { // error if the field is not defined in the schema. func (m *UserMutation) ClearField(name string) error { switch name { + case user.FieldDescription: + m.ClearDescription() + return nil case user.FieldAddress: m.ClearAddress() return nil @@ -2790,6 +2860,9 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldName: m.ResetName() return nil + case user.FieldDescription: + m.ResetDescription() + return nil case user.FieldNickname: m.ResetNickname() return nil diff --git a/entc/integration/migrate/entv1/runtime.go b/entc/integration/migrate/entv1/runtime.go index 3d8501742..aae39bdf4 100644 --- a/entc/integration/migrate/entv1/runtime.go +++ b/entc/integration/migrate/entv1/runtime.go @@ -22,7 +22,7 @@ func init() { // user.NameValidator is a validator for the "name" field. It is called by the builders before save. user.NameValidator = userDescName.Validators[0].(func(string) error) // userDescWorkplace is the schema descriptor for workplace field. - userDescWorkplace := userFields[9].Descriptor() + userDescWorkplace := userFields[10].Descriptor() // user.WorkplaceValidator is a validator for the "workplace" field. It is called by the builders before save. user.WorkplaceValidator = userDescWorkplace.Validators[0].(func(string) error) } diff --git a/entc/integration/migrate/entv1/schema/user.go b/entc/integration/migrate/entv1/schema/user.go index c694882f8..1e3777679 100644 --- a/entc/integration/migrate/entv1/schema/user.go +++ b/entc/integration/migrate/entv1/schema/user.go @@ -6,6 +6,7 @@ package schema import ( "entgo.io/ent" + "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" @@ -24,6 +25,8 @@ func (User) Fields() []ent.Field { field.Int32("age"), field.String("name"). MaxLen(10), + field.Text("description"). + Optional(), field.String("nickname"). Unique(), field.String("address"). @@ -58,6 +61,8 @@ func (User) Edges() []ent.Edge { func (User) Indexes() []ent.Index { return []ent.Index{ + index.Fields("description"). + Annotations(entsql.Prefix(50)), index.Fields("name", "address"). Unique(), } diff --git a/entc/integration/migrate/entv1/user.go b/entc/integration/migrate/entv1/user.go index b8e7cf770..642e072a0 100644 --- a/entc/integration/migrate/entv1/user.go +++ b/entc/integration/migrate/entv1/user.go @@ -24,6 +24,8 @@ type User struct { Age int32 `json:"age,omitempty"` // Name holds the value of the "name" field. Name string `json:"name,omitempty"` + // Description holds the value of the "description" field. + Description string `json:"description,omitempty"` // Nickname holds the value of the "nickname" field. Nickname string `json:"nickname,omitempty"` // Address holds the value of the "address" field. @@ -120,7 +122,7 @@ func (*User) scanValues(columns []string) ([]interface{}, error) { values[i] = new([]byte) case user.FieldID, user.FieldAge: values[i] = new(sql.NullInt64) - case user.FieldName, user.FieldNickname, user.FieldAddress, user.FieldRenamed, user.FieldState, user.FieldStatus, user.FieldWorkplace: + case user.FieldName, user.FieldDescription, user.FieldNickname, user.FieldAddress, user.FieldRenamed, user.FieldState, user.FieldStatus, user.FieldWorkplace: values[i] = new(sql.NullString) case user.ForeignKeys[0]: // user_children values[i] = new(sql.NullInt64) @@ -159,6 +161,12 @@ func (u *User) assignValues(columns []string, values []interface{}) error { } else if value.Valid { u.Name = value.String } + case user.FieldDescription: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field description", values[i]) + } else if value.Valid { + u.Description = value.String + } case user.FieldNickname: if value, ok := values[i].(*sql.NullString); !ok { return fmt.Errorf("unexpected type %T for field nickname", values[i]) @@ -267,6 +275,8 @@ func (u *User) String() string { builder.WriteString(fmt.Sprintf("%v", u.Age)) builder.WriteString(", name=") builder.WriteString(u.Name) + builder.WriteString(", description=") + builder.WriteString(u.Description) builder.WriteString(", nickname=") builder.WriteString(u.Nickname) builder.WriteString(", address=") diff --git a/entc/integration/migrate/entv1/user/user.go b/entc/integration/migrate/entv1/user/user.go index c93cd5a9d..78f51efc9 100644 --- a/entc/integration/migrate/entv1/user/user.go +++ b/entc/integration/migrate/entv1/user/user.go @@ -19,6 +19,8 @@ const ( FieldAge = "age" // FieldName holds the string denoting the name field in the database. FieldName = "name" + // FieldDescription holds the string denoting the description field in the database. + FieldDescription = "description" // FieldNickname holds the string denoting the nickname field in the database. FieldNickname = "nickname" // FieldAddress holds the string denoting the address field in the database. @@ -71,6 +73,7 @@ var Columns = []string{ FieldID, FieldAge, FieldName, + FieldDescription, FieldNickname, FieldAddress, FieldRenamed, diff --git a/entc/integration/migrate/entv1/user/where.go b/entc/integration/migrate/entv1/user/where.go index 0c87c8fa8..4fb1e81fb 100644 --- a/entc/integration/migrate/entv1/user/where.go +++ b/entc/integration/migrate/entv1/user/where.go @@ -109,6 +109,13 @@ func Name(v string) predicate.User { }) } +// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ. +func Description(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldDescription), v)) + }) +} + // Nickname applies equality check predicate on the "nickname" field. It's identical to NicknameEQ. func Nickname(v string) predicate.User { return predicate.User(func(s *sql.Selector) { @@ -338,6 +345,131 @@ func NameContainsFold(v string) predicate.User { }) } +// DescriptionEQ applies the EQ predicate on the "description" field. +func DescriptionEQ(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldDescription), v)) + }) +} + +// DescriptionNEQ applies the NEQ predicate on the "description" field. +func DescriptionNEQ(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldDescription), v)) + }) +} + +// DescriptionIn applies the In predicate on the "description" field. +func DescriptionIn(vs ...string) predicate.User { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(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(FieldDescription), v...)) + }) +} + +// DescriptionNotIn applies the NotIn predicate on the "description" field. +func DescriptionNotIn(vs ...string) predicate.User { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(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(FieldDescription), v...)) + }) +} + +// DescriptionGT applies the GT predicate on the "description" field. +func DescriptionGT(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldDescription), v)) + }) +} + +// DescriptionGTE applies the GTE predicate on the "description" field. +func DescriptionGTE(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldDescription), v)) + }) +} + +// DescriptionLT applies the LT predicate on the "description" field. +func DescriptionLT(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldDescription), v)) + }) +} + +// DescriptionLTE applies the LTE predicate on the "description" field. +func DescriptionLTE(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldDescription), v)) + }) +} + +// DescriptionContains applies the Contains predicate on the "description" field. +func DescriptionContains(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldDescription), v)) + }) +} + +// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field. +func DescriptionHasPrefix(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldDescription), v)) + }) +} + +// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field. +func DescriptionHasSuffix(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldDescription), v)) + }) +} + +// DescriptionIsNil applies the IsNil predicate on the "description" field. +func DescriptionIsNil() predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldDescription))) + }) +} + +// DescriptionNotNil applies the NotNil predicate on the "description" field. +func DescriptionNotNil() predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldDescription))) + }) +} + +// DescriptionEqualFold applies the EqualFold predicate on the "description" field. +func DescriptionEqualFold(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldDescription), v)) + }) +} + +// DescriptionContainsFold applies the ContainsFold predicate on the "description" field. +func DescriptionContainsFold(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldDescription), v)) + }) +} + // NicknameEQ applies the EQ predicate on the "nickname" field. func NicknameEQ(v string) predicate.User { return predicate.User(func(s *sql.Selector) { diff --git a/entc/integration/migrate/entv1/user_create.go b/entc/integration/migrate/entv1/user_create.go index 230cd3835..b1638fae2 100644 --- a/entc/integration/migrate/entv1/user_create.go +++ b/entc/integration/migrate/entv1/user_create.go @@ -36,6 +36,20 @@ func (uc *UserCreate) SetName(s string) *UserCreate { return uc } +// SetDescription sets the "description" field. +func (uc *UserCreate) SetDescription(s string) *UserCreate { + uc.mutation.SetDescription(s) + return uc +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (uc *UserCreate) SetNillableDescription(s *string) *UserCreate { + if s != nil { + uc.SetDescription(*s) + } + return uc +} + // SetNickname sets the "nickname" field. func (uc *UserCreate) SetNickname(s string) *UserCreate { uc.mutation.SetNickname(s) @@ -323,6 +337,14 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { }) _node.Name = value } + if value, ok := uc.mutation.Description(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: user.FieldDescription, + }) + _node.Description = value + } if value, ok := uc.mutation.Nickname(); ok { _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ Type: field.TypeString, diff --git a/entc/integration/migrate/entv1/user_update.go b/entc/integration/migrate/entv1/user_update.go index 86479b1a4..002ec1ae7 100644 --- a/entc/integration/migrate/entv1/user_update.go +++ b/entc/integration/migrate/entv1/user_update.go @@ -50,6 +50,26 @@ func (uu *UserUpdate) SetName(s string) *UserUpdate { return uu } +// SetDescription sets the "description" field. +func (uu *UserUpdate) SetDescription(s string) *UserUpdate { + uu.mutation.SetDescription(s) + return uu +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (uu *UserUpdate) SetNillableDescription(s *string) *UserUpdate { + if s != nil { + uu.SetDescription(*s) + } + return uu +} + +// ClearDescription clears the value of the "description" field. +func (uu *UserUpdate) ClearDescription() *UserUpdate { + uu.mutation.ClearDescription() + return uu +} + // SetNickname sets the "nickname" field. func (uu *UserUpdate) SetNickname(s string) *UserUpdate { uu.mutation.SetNickname(s) @@ -400,6 +420,19 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: user.FieldName, }) } + if value, ok := uu.mutation.Description(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: user.FieldDescription, + }) + } + if uu.mutation.DescriptionCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: user.FieldDescription, + }) + } if value, ok := uu.mutation.Nickname(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeString, @@ -682,6 +715,26 @@ func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { return uuo } +// SetDescription sets the "description" field. +func (uuo *UserUpdateOne) SetDescription(s string) *UserUpdateOne { + uuo.mutation.SetDescription(s) + return uuo +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (uuo *UserUpdateOne) SetNillableDescription(s *string) *UserUpdateOne { + if s != nil { + uuo.SetDescription(*s) + } + return uuo +} + +// ClearDescription clears the value of the "description" field. +func (uuo *UserUpdateOne) ClearDescription() *UserUpdateOne { + uuo.mutation.ClearDescription() + return uuo +} + // SetNickname sets the "nickname" field. func (uuo *UserUpdateOne) SetNickname(s string) *UserUpdateOne { uuo.mutation.SetNickname(s) @@ -1056,6 +1109,19 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) Column: user.FieldName, }) } + if value, ok := uuo.mutation.Description(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: user.FieldDescription, + }) + } + if uuo.mutation.DescriptionCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: user.FieldDescription, + }) + } if value, ok := uuo.mutation.Nickname(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeString, diff --git a/entc/integration/migrate/entv2/media.go b/entc/integration/migrate/entv2/media.go index 1de218ad9..748dd4110 100644 --- a/entc/integration/migrate/entv2/media.go +++ b/entc/integration/migrate/entv2/media.go @@ -23,6 +23,8 @@ type Media struct { Source string `json:"source,omitempty"` // SourceURI holds the value of the "source_uri" field. SourceURI string `json:"source_uri,omitempty"` + // Text holds the value of the "text" field. + Text string `json:"text,omitempty"` } // scanValues returns the types for scanning values from sql.Rows. @@ -32,7 +34,7 @@ func (*Media) scanValues(columns []string) ([]interface{}, error) { switch columns[i] { case media.FieldID: values[i] = new(sql.NullInt64) - case media.FieldSource, media.FieldSourceURI: + case media.FieldSource, media.FieldSourceURI, media.FieldText: values[i] = new(sql.NullString) default: return nil, fmt.Errorf("unexpected column %q for type Media", columns[i]) @@ -67,6 +69,12 @@ func (m *Media) assignValues(columns []string, values []interface{}) error { } else if value.Valid { m.SourceURI = value.String } + case media.FieldText: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field text", values[i]) + } else if value.Valid { + m.Text = value.String + } } } return nil @@ -99,6 +107,8 @@ func (m *Media) String() string { builder.WriteString(m.Source) builder.WriteString(", source_uri=") builder.WriteString(m.SourceURI) + builder.WriteString(", text=") + builder.WriteString(m.Text) builder.WriteByte(')') return builder.String() } diff --git a/entc/integration/migrate/entv2/media/media.go b/entc/integration/migrate/entv2/media/media.go index a44ac25f1..e6aa5df25 100644 --- a/entc/integration/migrate/entv2/media/media.go +++ b/entc/integration/migrate/entv2/media/media.go @@ -15,6 +15,8 @@ const ( FieldSource = "source" // FieldSourceURI holds the string denoting the source_uri field in the database. FieldSourceURI = "source_uri" + // FieldText holds the string denoting the text field in the database. + FieldText = "text" // Table holds the table name of the media in the database. Table = "media" ) @@ -24,6 +26,7 @@ var Columns = []string{ FieldID, FieldSource, FieldSourceURI, + FieldText, } // ValidColumn reports if the column name is valid (part of the table columns). diff --git a/entc/integration/migrate/entv2/media/where.go b/entc/integration/migrate/entv2/media/where.go index 3bca6e9c1..0077391da 100644 --- a/entc/integration/migrate/entv2/media/where.go +++ b/entc/integration/migrate/entv2/media/where.go @@ -108,6 +108,13 @@ func SourceURI(v string) predicate.Media { }) } +// Text applies equality check predicate on the "text" field. It's identical to TextEQ. +func Text(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldText), v)) + }) +} + // SourceEQ applies the EQ predicate on the "source" field. func SourceEQ(v string) predicate.Media { return predicate.Media(func(s *sql.Selector) { @@ -358,6 +365,131 @@ func SourceURIContainsFold(v string) predicate.Media { }) } +// TextEQ applies the EQ predicate on the "text" field. +func TextEQ(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldText), v)) + }) +} + +// TextNEQ applies the NEQ predicate on the "text" field. +func TextNEQ(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldText), v)) + }) +} + +// TextIn applies the In predicate on the "text" field. +func TextIn(vs ...string) predicate.Media { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Media(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(FieldText), v...)) + }) +} + +// TextNotIn applies the NotIn predicate on the "text" field. +func TextNotIn(vs ...string) predicate.Media { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Media(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(FieldText), v...)) + }) +} + +// TextGT applies the GT predicate on the "text" field. +func TextGT(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldText), v)) + }) +} + +// TextGTE applies the GTE predicate on the "text" field. +func TextGTE(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldText), v)) + }) +} + +// TextLT applies the LT predicate on the "text" field. +func TextLT(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldText), v)) + }) +} + +// TextLTE applies the LTE predicate on the "text" field. +func TextLTE(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldText), v)) + }) +} + +// TextContains applies the Contains predicate on the "text" field. +func TextContains(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldText), v)) + }) +} + +// TextHasPrefix applies the HasPrefix predicate on the "text" field. +func TextHasPrefix(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldText), v)) + }) +} + +// TextHasSuffix applies the HasSuffix predicate on the "text" field. +func TextHasSuffix(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldText), v)) + }) +} + +// TextIsNil applies the IsNil predicate on the "text" field. +func TextIsNil() predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldText))) + }) +} + +// TextNotNil applies the NotNil predicate on the "text" field. +func TextNotNil() predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldText))) + }) +} + +// TextEqualFold applies the EqualFold predicate on the "text" field. +func TextEqualFold(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldText), v)) + }) +} + +// TextContainsFold applies the ContainsFold predicate on the "text" field. +func TextContainsFold(v string) predicate.Media { + return predicate.Media(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldText), v)) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.Media) predicate.Media { return predicate.Media(func(s *sql.Selector) { diff --git a/entc/integration/migrate/entv2/media_create.go b/entc/integration/migrate/entv2/media_create.go index da31792a5..4e344c054 100644 --- a/entc/integration/migrate/entv2/media_create.go +++ b/entc/integration/migrate/entv2/media_create.go @@ -50,6 +50,20 @@ func (mc *MediaCreate) SetNillableSourceURI(s *string) *MediaCreate { return mc } +// SetText sets the "text" field. +func (mc *MediaCreate) SetText(s string) *MediaCreate { + mc.mutation.SetText(s) + return mc +} + +// SetNillableText sets the "text" field if the given value is not nil. +func (mc *MediaCreate) SetNillableText(s *string) *MediaCreate { + if s != nil { + mc.SetText(*s) + } + return mc +} + // Mutation returns the MediaMutation object of the builder. func (mc *MediaCreate) Mutation() *MediaMutation { return mc.mutation @@ -147,6 +161,14 @@ func (mc *MediaCreate) createSpec() (*Media, *sqlgraph.CreateSpec) { }) _node.SourceURI = value } + if value, ok := mc.mutation.Text(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: media.FieldText, + }) + _node.Text = value + } return _node, _spec } diff --git a/entc/integration/migrate/entv2/media_update.go b/entc/integration/migrate/entv2/media_update.go index af261bb0e..1e5be7867 100644 --- a/entc/integration/migrate/entv2/media_update.go +++ b/entc/integration/migrate/entv2/media_update.go @@ -70,6 +70,26 @@ func (mu *MediaUpdate) ClearSourceURI() *MediaUpdate { return mu } +// SetText sets the "text" field. +func (mu *MediaUpdate) SetText(s string) *MediaUpdate { + mu.mutation.SetText(s) + return mu +} + +// SetNillableText sets the "text" field if the given value is not nil. +func (mu *MediaUpdate) SetNillableText(s *string) *MediaUpdate { + if s != nil { + mu.SetText(*s) + } + return mu +} + +// ClearText clears the value of the "text" field. +func (mu *MediaUpdate) ClearText() *MediaUpdate { + mu.mutation.ClearText() + return mu +} + // Mutation returns the MediaMutation object of the builder. func (mu *MediaUpdate) Mutation() *MediaMutation { return mu.mutation @@ -170,6 +190,19 @@ func (mu *MediaUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: media.FieldSourceURI, }) } + if value, ok := mu.mutation.Text(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: media.FieldText, + }) + } + if mu.mutation.TextCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: media.FieldText, + }) + } if n, err = sqlgraph.UpdateNodes(ctx, mu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{media.Label} @@ -229,6 +262,26 @@ func (muo *MediaUpdateOne) ClearSourceURI() *MediaUpdateOne { return muo } +// SetText sets the "text" field. +func (muo *MediaUpdateOne) SetText(s string) *MediaUpdateOne { + muo.mutation.SetText(s) + return muo +} + +// SetNillableText sets the "text" field if the given value is not nil. +func (muo *MediaUpdateOne) SetNillableText(s *string) *MediaUpdateOne { + if s != nil { + muo.SetText(*s) + } + return muo +} + +// ClearText clears the value of the "text" field. +func (muo *MediaUpdateOne) ClearText() *MediaUpdateOne { + muo.mutation.ClearText() + return muo +} + // Mutation returns the MediaMutation object of the builder. func (muo *MediaUpdateOne) Mutation() *MediaMutation { return muo.mutation @@ -353,6 +406,19 @@ func (muo *MediaUpdateOne) sqlSave(ctx context.Context) (_node *Media, err error Column: media.FieldSourceURI, }) } + if value, ok := muo.mutation.Text(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: media.FieldText, + }) + } + if muo.mutation.TextCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: media.FieldText, + }) + } _node = &Media{config: muo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/entc/integration/migrate/entv2/migrate/schema.go b/entc/integration/migrate/entv2/migrate/schema.go index 0240e2172..aabf2ba4f 100644 --- a/entc/integration/migrate/entv2/migrate/schema.go +++ b/entc/integration/migrate/entv2/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" ) @@ -46,10 +47,9 @@ var ( } // ConversionsTable holds the schema information for the "conversions" table. ConversionsTable = &schema.Table{ - Name: "conversions", - Columns: ConversionsColumns, - PrimaryKey: []*schema.Column{ConversionsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "conversions", + Columns: ConversionsColumns, + PrimaryKey: []*schema.Column{ConversionsColumns[0]}, } // CustomTypesColumns holds the columns for the "custom_types" table. CustomTypesColumns = []*schema.Column{ @@ -58,10 +58,9 @@ var ( } // CustomTypesTable holds the schema information for the "custom_types" table. CustomTypesTable = &schema.Table{ - Name: "custom_types", - Columns: CustomTypesColumns, - PrimaryKey: []*schema.Column{CustomTypesColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "custom_types", + Columns: CustomTypesColumns, + PrimaryKey: []*schema.Column{CustomTypesColumns[0]}, } // GroupsColumns holds the columns for the "groups" table. GroupsColumns = []*schema.Column{ @@ -69,28 +68,40 @@ var ( } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ - Name: "groups", - Columns: GroupsColumns, - PrimaryKey: []*schema.Column{GroupsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "groups", + Columns: GroupsColumns, + PrimaryKey: []*schema.Column{GroupsColumns[0]}, } // MediaColumns holds the columns for the "media" table. MediaColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, {Name: "source", Type: field.TypeString, Nullable: true}, {Name: "source_uri", Type: field.TypeString, Nullable: true}, + {Name: "text", Type: field.TypeString, Nullable: true, Size: 2147483647}, } // MediaTable holds the schema information for the "media" table. MediaTable = &schema.Table{ - Name: "media", - Columns: MediaColumns, - PrimaryKey: []*schema.Column{MediaColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "media", + Columns: MediaColumns, + PrimaryKey: []*schema.Column{MediaColumns[0]}, Indexes: []*schema.Index{ { Name: "media_source_source_uri", Unique: true, Columns: []*schema.Column{MediaColumns[1], MediaColumns[2]}, + Annotation: &entsql.IndexAnnotation{ + PrefixColumns: map[string]uint{ + MediaColumns[1].Name: 100, + }, + }, + }, + { + Name: "media_text", + Unique: false, + Columns: []*schema.Column{MediaColumns[3]}, + Annotation: &entsql.IndexAnnotation{ + Prefix: 100, + }, }, }, } @@ -120,6 +131,7 @@ var ( {Name: "mixed_enum", Type: field.TypeEnum, Enums: []string{"on", "off"}, Default: "on"}, {Name: "age", Type: field.TypeInt}, {Name: "name", Type: field.TypeString, Size: 2147483647}, + {Name: "description", Type: field.TypeString, Nullable: true, Size: 2147483647}, {Name: "nickname", Type: field.TypeString, Size: 255}, {Name: "phone", Type: field.TypeString, Default: "unknown"}, {Name: "buffer", Type: field.TypeBytes, Nullable: true}, @@ -133,15 +145,22 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, Indexes: []*schema.Index{ + { + Name: "user_description", + Unique: false, + Columns: []*schema.Column{UsersColumns[5]}, + Annotation: &entsql.IndexAnnotation{ + Prefix: 100, + }, + }, { Name: "user_phone_age", Unique: true, - Columns: []*schema.Column{UsersColumns[6], UsersColumns[3]}, + Columns: []*schema.Column{UsersColumns[7], UsersColumns[3]}, }, }, } diff --git a/entc/integration/migrate/entv2/mutation.go b/entc/integration/migrate/entv2/mutation.go index 54db0b62a..8e5f8eb36 100644 --- a/entc/integration/migrate/entv2/mutation.go +++ b/entc/integration/migrate/entv2/mutation.go @@ -1770,6 +1770,7 @@ type MediaMutation struct { id *int source *string source_uri *string + text *string clearedFields map[string]struct{} done bool oldValue func(context.Context) (*Media, error) @@ -1953,6 +1954,55 @@ func (m *MediaMutation) ResetSourceURI() { delete(m.clearedFields, media.FieldSourceURI) } +// SetText sets the "text" field. +func (m *MediaMutation) SetText(s string) { + m.text = &s +} + +// Text returns the value of the "text" field in the mutation. +func (m *MediaMutation) Text() (r string, exists bool) { + v := m.text + if v == nil { + return + } + return *v, true +} + +// OldText returns the old "text" field's value of the Media entity. +// If the Media 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 *MediaMutation) OldText(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldText is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldText requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldText: %w", err) + } + return oldValue.Text, nil +} + +// ClearText clears the value of the "text" field. +func (m *MediaMutation) ClearText() { + m.text = nil + m.clearedFields[media.FieldText] = struct{}{} +} + +// TextCleared returns if the "text" field was cleared in this mutation. +func (m *MediaMutation) TextCleared() bool { + _, ok := m.clearedFields[media.FieldText] + return ok +} + +// ResetText resets all changes to the "text" field. +func (m *MediaMutation) ResetText() { + m.text = nil + delete(m.clearedFields, media.FieldText) +} + // Op returns the operation name. func (m *MediaMutation) Op() Op { return m.op @@ -1967,13 +2017,16 @@ func (m *MediaMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *MediaMutation) Fields() []string { - fields := make([]string, 0, 2) + fields := make([]string, 0, 3) if m.source != nil { fields = append(fields, media.FieldSource) } if m.source_uri != nil { fields = append(fields, media.FieldSourceURI) } + if m.text != nil { + fields = append(fields, media.FieldText) + } return fields } @@ -1986,6 +2039,8 @@ func (m *MediaMutation) Field(name string) (ent.Value, bool) { return m.Source() case media.FieldSourceURI: return m.SourceURI() + case media.FieldText: + return m.Text() } return nil, false } @@ -1999,6 +2054,8 @@ func (m *MediaMutation) OldField(ctx context.Context, name string) (ent.Value, e return m.OldSource(ctx) case media.FieldSourceURI: return m.OldSourceURI(ctx) + case media.FieldText: + return m.OldText(ctx) } return nil, fmt.Errorf("unknown Media field %s", name) } @@ -2022,6 +2079,13 @@ func (m *MediaMutation) SetField(name string, value ent.Value) error { } m.SetSourceURI(v) return nil + case media.FieldText: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetText(v) + return nil } return fmt.Errorf("unknown Media field %s", name) } @@ -2058,6 +2122,9 @@ func (m *MediaMutation) ClearedFields() []string { if m.FieldCleared(media.FieldSourceURI) { fields = append(fields, media.FieldSourceURI) } + if m.FieldCleared(media.FieldText) { + fields = append(fields, media.FieldText) + } return fields } @@ -2078,6 +2145,9 @@ func (m *MediaMutation) ClearField(name string) error { case media.FieldSourceURI: m.ClearSourceURI() return nil + case media.FieldText: + m.ClearText() + return nil } return fmt.Errorf("unknown Media nullable field %s", name) } @@ -2092,6 +2162,9 @@ func (m *MediaMutation) ResetField(name string) error { case media.FieldSourceURI: m.ResetSourceURI() return nil + case media.FieldText: + m.ResetText() + return nil } return fmt.Errorf("unknown Media field %s", name) } @@ -2449,6 +2522,7 @@ type UserMutation struct { age *int addage *int name *string + description *string nickname *string phone *string buffer *[]byte @@ -2722,6 +2796,55 @@ func (m *UserMutation) ResetName() { m.name = nil } +// SetDescription sets the "description" field. +func (m *UserMutation) SetDescription(s string) { + m.description = &s +} + +// Description returns the value of the "description" field in the mutation. +func (m *UserMutation) Description() (r string, exists bool) { + v := m.description + if v == nil { + return + } + return *v, true +} + +// OldDescription returns the old "description" 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) OldDescription(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldDescription is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldDescription requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDescription: %w", err) + } + return oldValue.Description, nil +} + +// ClearDescription clears the value of the "description" field. +func (m *UserMutation) ClearDescription() { + m.description = nil + m.clearedFields[user.FieldDescription] = struct{}{} +} + +// DescriptionCleared returns if the "description" field was cleared in this mutation. +func (m *UserMutation) DescriptionCleared() bool { + _, ok := m.clearedFields[user.FieldDescription] + return ok +} + +// ResetDescription resets all changes to the "description" field. +func (m *UserMutation) ResetDescription() { + m.description = nil + delete(m.clearedFields, user.FieldDescription) +} + // SetNickname sets the "nickname" field. func (m *UserMutation) SetNickname(s string) { m.nickname = &s @@ -3319,7 +3442,7 @@ 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, 14) + fields := make([]string, 0, 15) if m.mixed_string != nil { fields = append(fields, user.FieldMixedString) } @@ -3332,6 +3455,9 @@ func (m *UserMutation) Fields() []string { if m.name != nil { fields = append(fields, user.FieldName) } + if m.description != nil { + fields = append(fields, user.FieldDescription) + } if m.nickname != nil { fields = append(fields, user.FieldNickname) } @@ -3378,6 +3504,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { return m.Age() case user.FieldName: return m.Name() + case user.FieldDescription: + return m.Description() case user.FieldNickname: return m.Nickname() case user.FieldPhone: @@ -3415,6 +3543,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldAge(ctx) case user.FieldName: return m.OldName(ctx) + case user.FieldDescription: + return m.OldDescription(ctx) case user.FieldNickname: return m.OldNickname(ctx) case user.FieldPhone: @@ -3472,6 +3602,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetName(v) return nil + case user.FieldDescription: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDescription(v) + return nil case user.FieldNickname: v, ok := value.(string) if !ok { @@ -3587,6 +3724,9 @@ func (m *UserMutation) AddField(name string, value ent.Value) error { // mutation. func (m *UserMutation) ClearedFields() []string { var fields []string + if m.FieldCleared(user.FieldDescription) { + fields = append(fields, user.FieldDescription) + } if m.FieldCleared(user.FieldBuffer) { fields = append(fields, user.FieldBuffer) } @@ -3619,6 +3759,9 @@ func (m *UserMutation) FieldCleared(name string) bool { // error if the field is not defined in the schema. func (m *UserMutation) ClearField(name string) error { switch name { + case user.FieldDescription: + m.ClearDescription() + return nil case user.FieldBuffer: m.ClearBuffer() return nil @@ -3657,6 +3800,9 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldName: m.ResetName() return nil + case user.FieldDescription: + m.ResetDescription() + return nil case user.FieldNickname: m.ResetNickname() return nil diff --git a/entc/integration/migrate/entv2/runtime.go b/entc/integration/migrate/entv2/runtime.go index fcf6b92bb..ad1131779 100644 --- a/entc/integration/migrate/entv2/runtime.go +++ b/entc/integration/migrate/entv2/runtime.go @@ -27,23 +27,23 @@ func init() { // user.DefaultMixedString holds the default value on creation for the mixed_string field. user.DefaultMixedString = userDescMixedString.Default.(string) // userDescNickname is the schema descriptor for nickname field. - userDescNickname := userFields[3].Descriptor() + userDescNickname := userFields[4].Descriptor() // user.NicknameValidator is a validator for the "nickname" field. It is called by the builders before save. user.NicknameValidator = userDescNickname.Validators[0].(func(string) error) // userDescPhone is the schema descriptor for phone field. - userDescPhone := userFields[4].Descriptor() + userDescPhone := userFields[5].Descriptor() // user.DefaultPhone holds the default value on creation for the phone field. user.DefaultPhone = userDescPhone.Default.(string) // userDescBuffer is the schema descriptor for buffer field. - userDescBuffer := userFields[5].Descriptor() + userDescBuffer := userFields[6].Descriptor() // user.DefaultBuffer holds the default value on creation for the buffer field. user.DefaultBuffer = userDescBuffer.Default.(func() []byte) // userDescTitle is the schema descriptor for title field. - userDescTitle := userFields[6].Descriptor() + userDescTitle := userFields[7].Descriptor() // user.DefaultTitle holds the default value on creation for the title field. user.DefaultTitle = userDescTitle.Default.(string) // userDescCreatedAt is the schema descriptor for created_at field. - userDescCreatedAt := userFields[12].Descriptor() + userDescCreatedAt := userFields[13].Descriptor() // user.DefaultCreatedAt holds the default value on creation for the created_at field. user.DefaultCreatedAt = userDescCreatedAt.Default.(func() time.Time) } diff --git a/entc/integration/migrate/entv2/schema/media.go b/entc/integration/migrate/entv2/schema/media.go index d75b47c77..2a42712f6 100644 --- a/entc/integration/migrate/entv2/schema/media.go +++ b/entc/integration/migrate/entv2/schema/media.go @@ -6,6 +6,7 @@ package schema import ( "entgo.io/ent" + "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" ) @@ -22,6 +23,8 @@ func (Media) Fields() []ent.Field { Optional(), field.String("source_uri"). Optional(), + field.Text("text"). + Optional(), } } @@ -29,6 +32,10 @@ func (Media) Fields() []ent.Field { func (Media) Indexes() []ent.Index { return []ent.Index{ index.Fields("source", "source_uri"). + Annotations(entsql.PrefixColumn("source", 100)). Unique(), + // MySQL allow indexing text column prefix. + index.Fields("text"). + Annotations(entsql.Prefix(100)), } } diff --git a/entc/integration/migrate/entv2/schema/user.go b/entc/integration/migrate/entv2/schema/user.go index 72f41a4cb..0bf5ca2de 100644 --- a/entc/integration/migrate/entv2/schema/user.go +++ b/entc/integration/migrate/entv2/schema/user.go @@ -49,6 +49,9 @@ func (User) Fields() []ent.Field { field.Int("age"), // extending name field to longtext. field.Text("name"), + // extending the index prefix below (on MySQL). + field.Text("description"). + Optional(), // changing nickname from unique no non-unique. field.String("nickname"). MaxLen(255), @@ -113,6 +116,10 @@ func (User) Edges() []ent.Edge { func (User) Indexes() []ent.Index { return []ent.Index{ + // Extend the column prefix by drop and create + // this index on MySQL. + index.Fields("description"). + Annotations(entsql.Prefix(100)), // deleting old indexes (name, address), // and defining a new one. index.Fields("phone", "age"). diff --git a/entc/integration/migrate/entv2/user.go b/entc/integration/migrate/entv2/user.go index d8dd0dd88..93d8ad004 100644 --- a/entc/integration/migrate/entv2/user.go +++ b/entc/integration/migrate/entv2/user.go @@ -29,6 +29,8 @@ type User struct { Age int `json:"age,omitempty"` // Name holds the value of the "name" field. Name string `json:"name,omitempty"` + // Description holds the value of the "description" field. + Description string `json:"description,omitempty"` // Nickname holds the value of the "nickname" field. Nickname string `json:"nickname,omitempty"` // Phone holds the value of the "phone" field. @@ -108,7 +110,7 @@ func (*User) scanValues(columns []string) ([]interface{}, error) { values[i] = new([]byte) case user.FieldID, user.FieldAge: values[i] = new(sql.NullInt64) - case user.FieldMixedString, user.FieldMixedEnum, user.FieldName, user.FieldNickname, user.FieldPhone, user.FieldTitle, user.FieldNewName, user.FieldState, user.FieldStatus, user.FieldWorkplace: + case user.FieldMixedString, user.FieldMixedEnum, user.FieldName, user.FieldDescription, user.FieldNickname, user.FieldPhone, user.FieldTitle, user.FieldNewName, user.FieldState, user.FieldStatus, user.FieldWorkplace: values[i] = new(sql.NullString) case user.FieldCreatedAt: values[i] = new(sql.NullTime) @@ -157,6 +159,12 @@ func (u *User) assignValues(columns []string, values []interface{}) error { } else if value.Valid { u.Name = value.String } + case user.FieldDescription: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field description", values[i]) + } else if value.Valid { + u.Description = value.String + } case user.FieldNickname: if value, ok := values[i].(*sql.NullString); !ok { return fmt.Errorf("unexpected type %T for field nickname", values[i]) @@ -268,6 +276,8 @@ func (u *User) String() string { builder.WriteString(fmt.Sprintf("%v", u.Age)) builder.WriteString(", name=") builder.WriteString(u.Name) + builder.WriteString(", description=") + builder.WriteString(u.Description) builder.WriteString(", nickname=") builder.WriteString(u.Nickname) builder.WriteString(", phone=") diff --git a/entc/integration/migrate/entv2/user/user.go b/entc/integration/migrate/entv2/user/user.go index 8e6d2d498..aaaf5b714 100644 --- a/entc/integration/migrate/entv2/user/user.go +++ b/entc/integration/migrate/entv2/user/user.go @@ -24,6 +24,8 @@ const ( FieldAge = "age" // FieldName holds the string denoting the name field in the database. FieldName = "name" + // FieldDescription holds the string denoting the description field in the database. + FieldDescription = "description" // FieldNickname holds the string denoting the nickname field in the database. FieldNickname = "nickname" // FieldPhone holds the string denoting the phone field in the database. @@ -81,6 +83,7 @@ var Columns = []string{ FieldMixedEnum, FieldAge, FieldName, + FieldDescription, FieldNickname, FieldPhone, FieldBuffer, diff --git a/entc/integration/migrate/entv2/user/where.go b/entc/integration/migrate/entv2/user/where.go index fc818305e..de8227f3c 100644 --- a/entc/integration/migrate/entv2/user/where.go +++ b/entc/integration/migrate/entv2/user/where.go @@ -118,6 +118,13 @@ func Name(v string) predicate.User { }) } +// Description applies equality check predicate on the "description" field. It's identical to DescriptionEQ. +func Description(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldDescription), v)) + }) +} + // Nickname applies equality check predicate on the "nickname" field. It's identical to NicknameEQ. func Nickname(v string) predicate.User { return predicate.User(func(s *sql.Selector) { @@ -520,6 +527,131 @@ func NameContainsFold(v string) predicate.User { }) } +// DescriptionEQ applies the EQ predicate on the "description" field. +func DescriptionEQ(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldDescription), v)) + }) +} + +// DescriptionNEQ applies the NEQ predicate on the "description" field. +func DescriptionNEQ(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldDescription), v)) + }) +} + +// DescriptionIn applies the In predicate on the "description" field. +func DescriptionIn(vs ...string) predicate.User { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(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(FieldDescription), v...)) + }) +} + +// DescriptionNotIn applies the NotIn predicate on the "description" field. +func DescriptionNotIn(vs ...string) predicate.User { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(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(FieldDescription), v...)) + }) +} + +// DescriptionGT applies the GT predicate on the "description" field. +func DescriptionGT(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldDescription), v)) + }) +} + +// DescriptionGTE applies the GTE predicate on the "description" field. +func DescriptionGTE(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldDescription), v)) + }) +} + +// DescriptionLT applies the LT predicate on the "description" field. +func DescriptionLT(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldDescription), v)) + }) +} + +// DescriptionLTE applies the LTE predicate on the "description" field. +func DescriptionLTE(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldDescription), v)) + }) +} + +// DescriptionContains applies the Contains predicate on the "description" field. +func DescriptionContains(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldDescription), v)) + }) +} + +// DescriptionHasPrefix applies the HasPrefix predicate on the "description" field. +func DescriptionHasPrefix(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldDescription), v)) + }) +} + +// DescriptionHasSuffix applies the HasSuffix predicate on the "description" field. +func DescriptionHasSuffix(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldDescription), v)) + }) +} + +// DescriptionIsNil applies the IsNil predicate on the "description" field. +func DescriptionIsNil() predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldDescription))) + }) +} + +// DescriptionNotNil applies the NotNil predicate on the "description" field. +func DescriptionNotNil() predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldDescription))) + }) +} + +// DescriptionEqualFold applies the EqualFold predicate on the "description" field. +func DescriptionEqualFold(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldDescription), v)) + }) +} + +// DescriptionContainsFold applies the ContainsFold predicate on the "description" field. +func DescriptionContainsFold(v string) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldDescription), v)) + }) +} + // NicknameEQ applies the EQ predicate on the "nickname" field. func NicknameEQ(v string) predicate.User { return predicate.User(func(s *sql.Selector) { diff --git a/entc/integration/migrate/entv2/user_create.go b/entc/integration/migrate/entv2/user_create.go index 4b6410e71..7ad60e30b 100644 --- a/entc/integration/migrate/entv2/user_create.go +++ b/entc/integration/migrate/entv2/user_create.go @@ -66,6 +66,20 @@ func (uc *UserCreate) SetName(s string) *UserCreate { return uc } +// SetDescription sets the "description" field. +func (uc *UserCreate) SetDescription(s string) *UserCreate { + uc.mutation.SetDescription(s) + return uc +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (uc *UserCreate) SetNillableDescription(s *string) *UserCreate { + if s != nil { + uc.SetDescription(*s) + } + return uc +} + // SetNickname sets the "nickname" field. func (uc *UserCreate) SetNickname(s string) *UserCreate { uc.mutation.SetNickname(s) @@ -429,6 +443,14 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { }) _node.Name = value } + if value, ok := uc.mutation.Description(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: user.FieldDescription, + }) + _node.Description = value + } if value, ok := uc.mutation.Nickname(); ok { _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ Type: field.TypeString, diff --git a/entc/integration/migrate/entv2/user_update.go b/entc/integration/migrate/entv2/user_update.go index 942ba6760..94a91cfc6 100644 --- a/entc/integration/migrate/entv2/user_update.go +++ b/entc/integration/migrate/entv2/user_update.go @@ -80,6 +80,26 @@ func (uu *UserUpdate) SetName(s string) *UserUpdate { return uu } +// SetDescription sets the "description" field. +func (uu *UserUpdate) SetDescription(s string) *UserUpdate { + uu.mutation.SetDescription(s) + return uu +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (uu *UserUpdate) SetNillableDescription(s *string) *UserUpdate { + if s != nil { + uu.SetDescription(*s) + } + return uu +} + +// ClearDescription clears the value of the "description" field. +func (uu *UserUpdate) ClearDescription() *UserUpdate { + uu.mutation.ClearDescription() + return uu +} + // SetNickname sets the "nickname" field. func (uu *UserUpdate) SetNickname(s string) *UserUpdate { uu.mutation.SetNickname(s) @@ -469,6 +489,19 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: user.FieldName, }) } + if value, ok := uu.mutation.Description(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: user.FieldDescription, + }) + } + if uu.mutation.DescriptionCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: user.FieldDescription, + }) + } if value, ok := uu.mutation.Nickname(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeString, @@ -784,6 +817,26 @@ func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { return uuo } +// SetDescription sets the "description" field. +func (uuo *UserUpdateOne) SetDescription(s string) *UserUpdateOne { + uuo.mutation.SetDescription(s) + return uuo +} + +// SetNillableDescription sets the "description" field if the given value is not nil. +func (uuo *UserUpdateOne) SetNillableDescription(s *string) *UserUpdateOne { + if s != nil { + uuo.SetDescription(*s) + } + return uuo +} + +// ClearDescription clears the value of the "description" field. +func (uuo *UserUpdateOne) ClearDescription() *UserUpdateOne { + uuo.mutation.ClearDescription() + return uuo +} + // SetNickname sets the "nickname" field. func (uuo *UserUpdateOne) SetNickname(s string) *UserUpdateOne { uuo.mutation.SetNickname(s) @@ -1197,6 +1250,19 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) Column: user.FieldName, }) } + if value, ok := uuo.mutation.Description(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: user.FieldDescription, + }) + } + if uuo.mutation.DescriptionCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Column: user.FieldDescription, + }) + } if value, ok := uuo.mutation.Nickname(); ok { _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ Type: field.TypeString, diff --git a/entc/integration/multischema/ent/migrate/schema.go b/entc/integration/multischema/ent/migrate/schema.go index 9168acfab..8aceab15c 100644 --- a/entc/integration/multischema/ent/migrate/schema.go +++ b/entc/integration/multischema/ent/migrate/schema.go @@ -19,10 +19,9 @@ var ( } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ - Name: "groups", - Columns: GroupsColumns, - PrimaryKey: []*schema.Column{GroupsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "groups", + Columns: GroupsColumns, + PrimaryKey: []*schema.Column{GroupsColumns[0]}, } // PetsColumns holds the columns for the "pets" table. PetsColumns = []*schema.Column{ @@ -51,10 +50,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // GroupUsersColumns holds the columns for the "group_users" table. GroupUsersColumns = []*schema.Column{ diff --git a/entc/integration/privacy/ent/migrate/schema.go b/entc/integration/privacy/ent/migrate/schema.go index d1e99d03d..d16d966f8 100644 --- a/entc/integration/privacy/ent/migrate/schema.go +++ b/entc/integration/privacy/ent/migrate/schema.go @@ -42,10 +42,9 @@ var ( } // TeamsTable holds the schema information for the "teams" table. TeamsTable = &schema.Table{ - Name: "teams", - Columns: TeamsColumns, - PrimaryKey: []*schema.Column{TeamsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "teams", + Columns: TeamsColumns, + PrimaryKey: []*schema.Column{TeamsColumns[0]}, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ @@ -55,10 +54,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // TaskTeamsColumns holds the columns for the "task_teams" table. TaskTeamsColumns = []*schema.Column{ diff --git a/entc/integration/template/ent/migrate/schema.go b/entc/integration/template/ent/migrate/schema.go index 66508251b..ec8fc3817 100644 --- a/entc/integration/template/ent/migrate/schema.go +++ b/entc/integration/template/ent/migrate/schema.go @@ -19,10 +19,9 @@ var ( } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ - Name: "groups", - Columns: GroupsColumns, - PrimaryKey: []*schema.Column{GroupsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "groups", + Columns: GroupsColumns, + PrimaryKey: []*schema.Column{GroupsColumns[0]}, } // PetsColumns holds the columns for the "pets" table. PetsColumns = []*schema.Column{ @@ -52,10 +51,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // UserFriendsColumns holds the columns for the "user_friends" table. UserFriendsColumns = []*schema.Column{ diff --git a/examples/edgeindex/ent/migrate/schema.go b/examples/edgeindex/ent/migrate/schema.go index 74593cf9c..31cdacdc9 100644 --- a/examples/edgeindex/ent/migrate/schema.go +++ b/examples/edgeindex/ent/migrate/schema.go @@ -19,10 +19,9 @@ var ( } // CitiesTable holds the schema information for the "cities" table. CitiesTable = &schema.Table{ - Name: "cities", - Columns: CitiesColumns, - PrimaryKey: []*schema.Column{CitiesColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "cities", + Columns: CitiesColumns, + PrimaryKey: []*schema.Column{CitiesColumns[0]}, } // StreetsColumns holds the columns for the "streets" table. StreetsColumns = []*schema.Column{ diff --git a/examples/entcpkg/ent/migrate/schema.go b/examples/entcpkg/ent/migrate/schema.go index 5d4d05a27..14b12f6a9 100644 --- a/examples/entcpkg/ent/migrate/schema.go +++ b/examples/entcpkg/ent/migrate/schema.go @@ -20,10 +20,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/examples/m2m2types/ent/migrate/schema.go b/examples/m2m2types/ent/migrate/schema.go index c1667d106..418c1fa6c 100644 --- a/examples/m2m2types/ent/migrate/schema.go +++ b/examples/m2m2types/ent/migrate/schema.go @@ -19,10 +19,9 @@ var ( } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ - Name: "groups", - Columns: GroupsColumns, - PrimaryKey: []*schema.Column{GroupsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "groups", + Columns: GroupsColumns, + PrimaryKey: []*schema.Column{GroupsColumns[0]}, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ @@ -32,10 +31,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // GroupUsersColumns holds the columns for the "group_users" table. GroupUsersColumns = []*schema.Column{ diff --git a/examples/m2mbidi/ent/migrate/schema.go b/examples/m2mbidi/ent/migrate/schema.go index 8138c9aa6..47c6e12b6 100644 --- a/examples/m2mbidi/ent/migrate/schema.go +++ b/examples/m2mbidi/ent/migrate/schema.go @@ -20,10 +20,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // UserFriendsColumns holds the columns for the "user_friends" table. UserFriendsColumns = []*schema.Column{ diff --git a/examples/m2mrecur/ent/migrate/schema.go b/examples/m2mrecur/ent/migrate/schema.go index 7d355d2d5..426e820bb 100644 --- a/examples/m2mrecur/ent/migrate/schema.go +++ b/examples/m2mrecur/ent/migrate/schema.go @@ -20,10 +20,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // UserFollowingColumns holds the columns for the "user_following" table. UserFollowingColumns = []*schema.Column{ diff --git a/examples/o2m2types/ent/migrate/schema.go b/examples/o2m2types/ent/migrate/schema.go index 20e7fecdc..565e3b1c2 100644 --- a/examples/o2m2types/ent/migrate/schema.go +++ b/examples/o2m2types/ent/migrate/schema.go @@ -40,10 +40,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/examples/o2o2types/ent/migrate/schema.go b/examples/o2o2types/ent/migrate/schema.go index 6dab55734..0ee5027b7 100644 --- a/examples/o2o2types/ent/migrate/schema.go +++ b/examples/o2o2types/ent/migrate/schema.go @@ -41,10 +41,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/examples/privacyadmin/ent/migrate/schema.go b/examples/privacyadmin/ent/migrate/schema.go index 1e77a29d4..4cc56bb15 100644 --- a/examples/privacyadmin/ent/migrate/schema.go +++ b/examples/privacyadmin/ent/migrate/schema.go @@ -19,10 +19,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // Tables holds all the tables in the schema. Tables = []*schema.Table{ diff --git a/examples/privacytenant/ent/migrate/schema.go b/examples/privacytenant/ent/migrate/schema.go index 544f5f14b..a73850330 100644 --- a/examples/privacytenant/ent/migrate/schema.go +++ b/examples/privacytenant/ent/migrate/schema.go @@ -39,10 +39,9 @@ var ( } // TenantsTable holds the schema information for the "tenants" table. TenantsTable = &schema.Table{ - Name: "tenants", - Columns: TenantsColumns, - PrimaryKey: []*schema.Column{TenantsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "tenants", + Columns: TenantsColumns, + PrimaryKey: []*schema.Column{TenantsColumns[0]}, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ diff --git a/examples/start/ent/migrate/schema.go b/examples/start/ent/migrate/schema.go index 11454cc66..2587c9e3c 100644 --- a/examples/start/ent/migrate/schema.go +++ b/examples/start/ent/migrate/schema.go @@ -40,10 +40,9 @@ var ( } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ - Name: "groups", - Columns: GroupsColumns, - PrimaryKey: []*schema.Column{GroupsColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "groups", + Columns: GroupsColumns, + PrimaryKey: []*schema.Column{GroupsColumns[0]}, } // UsersColumns holds the columns for the "users" table. UsersColumns = []*schema.Column{ @@ -53,10 +52,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // GroupUsersColumns holds the columns for the "group_users" table. GroupUsersColumns = []*schema.Column{ diff --git a/examples/traversal/ent/migrate/schema.go b/examples/traversal/ent/migrate/schema.go index 01ef7f3be..7b595817f 100644 --- a/examples/traversal/ent/migrate/schema.go +++ b/examples/traversal/ent/migrate/schema.go @@ -60,10 +60,9 @@ var ( } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ - Name: "users", - Columns: UsersColumns, - PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{}, + Name: "users", + Columns: UsersColumns, + PrimaryKey: []*schema.Column{UsersColumns[0]}, } // GroupUsersColumns holds the columns for the "group_users" table. GroupUsersColumns = []*schema.Column{