dialect/sql/schema: drop unique constraint on pg migration

Fixes #235
This commit is contained in:
Ariel Mashraki
2019-12-15 18:51:54 +02:00
parent dcb16c4ff6
commit 6bb834612c
24 changed files with 447 additions and 56 deletions

View File

@@ -258,6 +258,12 @@ func (t *TableAlter) AddForeignKey(fk *ForeignKeyBuilder) *TableAlter {
return t
}
// DropConstraint appends the `DROP CONSTRAINT` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) DropConstraint(ident string) *TableAlter {
t.Queries = append(t.Queries, Raw(fmt.Sprintf("DROP CONSTRAINT %s", t.Quote(ident))))
return t
}
// Query returns query representation of the `ALTER TABLE` statement.
//
// ALTER TABLE name

View File

@@ -136,8 +136,9 @@ func TestBuilder(t *testing.T) {
{
input: Dialect(dialect.Postgres).AlterTable("users").
AddColumn(Column("age").Type("int")).
AddColumn(Column("name").Type("varchar(255)")),
wantQuery: `ALTER TABLE "users" ADD COLUMN "age" int, ADD COLUMN "name" varchar(255)`,
AddColumn(Column("name").Type("varchar(255)")).
DropConstraint("users_nickname_key"),
wantQuery: `ALTER TABLE "users" ADD COLUMN "age" int, ADD COLUMN "name" varchar(255), DROP CONSTRAINT "users_nickname_key"`,
},
{
input: AlterTable("users").

View File

@@ -184,8 +184,7 @@ func (m *Migrate) apply(ctx context.Context, tx dialect.Tx, table string, change
// might fail if the intermediate state violates the constraints.
if m.dropIndexes {
for _, idx := range change.index.drop {
query, args := m.dropIndex(idx, table).Query()
if err := tx.Exec(ctx, query, args, new(sql.Result)); err != nil {
if err := m.dropIndex(ctx, tx, idx, table); err != nil {
return fmt.Errorf("drop index of table %q: %v", table, err)
}
}
@@ -437,11 +436,11 @@ type sqlDialect interface {
tableExist(context.Context, dialect.Tx, string) (bool, error)
fkExist(context.Context, dialect.Tx, string) (bool, error)
setRange(context.Context, dialect.Tx, string, int) error
dropIndex(context.Context, dialect.Tx, *Index, string) error
// table, column and index builder per dialect.
cType(*Column) string
tBuilder(*Table) *sql.TableBuilder
addColumn(*Column) *sql.ColumnBuilder
alterColumn(*Column) []*sql.ColumnBuilder
addIndex(*Index, string) *sql.IndexBuilder
dropIndex(*Index, string) *sql.DropIndexBuilder
}

View File

@@ -221,9 +221,10 @@ func (d *MySQL) addIndex(i *Index, table string) *sql.IndexBuilder {
return i.Builder(table)
}
// dropIndex returns the querying for dropping an index in MySQL.
func (d *MySQL) dropIndex(i *Index, table string) *sql.DropIndexBuilder {
return i.DropBuilder(table)
// dropIndex drops a MySQL index.
func (d *MySQL) dropIndex(ctx context.Context, tx dialect.Tx, idx *Index, table string) error {
query, args := idx.DropBuilder(table).Query()
return tx.Exec(ctx, query, args, new(sql.Result))
}
// scanColumn scans the column information from MySQL column description.

View File

@@ -168,7 +168,7 @@ func (d *Postgres) indexes(ctx context.Context, tx dialect.Tx, table string) (In
return nil, fmt.Errorf("scanning index description: %v", err)
}
// If the index is prefixed with the table, it's probably was
// added by this driver (and not entc) and it should be trimmed.
// added by `addIndex` (and not entc) and it should be trimmed.
name = strings.TrimPrefix(name, table+"_")
idx, ok := names[name]
if !ok {
@@ -327,8 +327,24 @@ func (d *Postgres) addIndex(i *Index, table string) *sql.IndexBuilder {
return idx
}
// dropIndex returns a DropIndexBuilder for the given table index.
func (d *Postgres) dropIndex(i *Index, table string) *sql.DropIndexBuilder {
name := fmt.Sprintf("%s_%s", table, i.Name)
return sql.Dialect(dialect.Postgres).DropIndex(name)
// dropIndex drops a Postgres index.
func (d *Postgres) dropIndex(ctx context.Context, tx dialect.Tx, idx *Index, table string) error {
name := idx.Name
build := sql.Dialect(dialect.Postgres)
if prefix := table + "_"; !strings.HasPrefix(name, prefix) {
name = prefix + name
}
query, args := sql.Dialect(dialect.Postgres).
Select(sql.Count("*")).From(sql.Table("INFORMATION_SCHEMA.TABLE_CONSTRAINTS").Unquote()).
Where(sql.EQ("table_schema", sql.Raw("CURRENT_SCHEMA()")).And().EQ("constraint_type", "UNIQUE").And().EQ("constraint_name", name)).
Query()
exists, err := exist(ctx, tx, query, args...)
if err != nil {
return err
}
query, args = build.DropIndex(name).Query()
if exists {
query, args = build.AlterTable(table).DropConstraint(name).Query()
}
return tx.Exec(ctx, query, args, new(sql.Result))
}

View File

@@ -515,7 +515,10 @@ func TestPostgres_Create(t *testing.T) {
WillReturnRows(sqlmock.NewRows([]string{"index_name", "column_name", "primary", "unique"}).
AddRow("users_pkey", "id", "t", "t").
AddRow("users_age_key", "age", "f", "t"))
mock.ExpectExec(escape(`DROP INDEX "users_age_key"`)).
mock.ExpectQuery(escape(`SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE "table_schema" = CURRENT_SCHEMA() AND "constraint_type" = $1 AND "constraint_name" = $2`)).
WithArgs("UNIQUE", "users_age_key").
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectExec(escape(`ALTER TABLE "users" DROP CONSTRAINT "users_age_key"`)).
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectCommit()
},

View File

@@ -141,9 +141,10 @@ func (d *SQLite) addIndex(i *Index, table string) *sql.IndexBuilder {
return i.Builder(table)
}
// dropIndex returns the querying for dropping an index in SQLite.
func (d *SQLite) dropIndex(i *Index, _ string) *sql.DropIndexBuilder {
return i.DropBuilder("")
// dropIndex drops a SQLite index.
func (d *SQLite) dropIndex(ctx context.Context, tx dialect.Tx, idx *Index, table string) error {
query, args := idx.DropBuilder("").Query()
return tx.Exec(ctx, query, args, new(sql.Result))
}
// fkExist returns always true to disable foreign-keys creation after the table was created.