dialect/sql: remove all DDL builders that no longer used (#4369)

This commit is contained in:
Giau. Tran Minh
2025-04-08 19:44:03 +07:00
committed by GitHub
parent 1b6159ac6e
commit b1786895ce
3 changed files with 2 additions and 976 deletions

View File

@@ -38,12 +38,8 @@ type querierErr interface {
// ColumnBuilder is a builder for column definition in table creation.
type ColumnBuilder struct {
Builder
typ string // column type.
name string // column name.
attr string // extra attributes.
modify bool // modify existing.
fk *ForeignKeyBuilder // foreign-key constraint.
check func(*Builder) // column checks.
typ string // column type.
name string // column name.
}
// Column returns a new ColumnBuilder with the given name.
@@ -57,189 +53,15 @@ func (c *ColumnBuilder) Type(t string) *ColumnBuilder {
return c
}
// Attr sets an extra attribute for the column, like UNIQUE or AUTO_INCREMENT.
func (c *ColumnBuilder) Attr(attr string) *ColumnBuilder {
if c.attr != "" && attr != "" {
c.attr += " "
}
c.attr += attr
return c
}
// Constraint adds the CONSTRAINT clause to the ADD COLUMN statement in SQLite.
func (c *ColumnBuilder) Constraint(fk *ForeignKeyBuilder) *ColumnBuilder {
c.fk = fk
return c
}
// Check adds a CHECK clause to the ADD COLUMN statement.
func (c *ColumnBuilder) Check(check func(*Builder)) *ColumnBuilder {
c.check = check
return c
}
// Query returns query representation of a Column.
func (c *ColumnBuilder) Query() (string, []any) {
c.Ident(c.name)
if c.typ != "" {
if c.postgres() && c.modify {
c.WriteString(" TYPE")
}
c.Pad().WriteString(c.typ)
}
if c.attr != "" {
c.Pad().WriteString(c.attr)
}
if c.fk != nil {
c.WriteString(" CONSTRAINT " + c.fk.symbol)
c.Pad().Join(c.fk.ref)
for _, action := range c.fk.actions {
c.Pad().WriteString(action)
}
}
if c.check != nil {
c.WriteString(" CHECK ")
c.Wrap(c.check)
}
return c.String(), c.args
}
// TableBuilder is a query builder for `CREATE TABLE` statement.
type TableBuilder struct {
Builder
name string // table name.
exists bool // check existence.
charset string // table charset.
collation string // table collation.
options string // table options.
columns []Querier // table columns.
primary []string // primary key.
constraints []Querier // foreign keys and indices.
checks []func(*Builder) // check constraints.
}
// CreateTable returns a query builder for the `CREATE TABLE` statement.
//
// CreateTable("users").
// Columns(
// Column("id").Type("int").Attr("auto_increment"),
// Column("name").Type("varchar(255)"),
// ).
// PrimaryKey("id")
func CreateTable(name string) *TableBuilder { return &TableBuilder{name: name} }
// IfNotExists appends the `IF NOT EXISTS` clause to the `CREATE TABLE` statement.
func (t *TableBuilder) IfNotExists() *TableBuilder {
t.exists = true
return t
}
// Column appends the given column to the `CREATE TABLE` statement.
func (t *TableBuilder) Column(c *ColumnBuilder) *TableBuilder {
t.columns = append(t.columns, c)
return t
}
// Columns appends a list of columns to the builder.
func (t *TableBuilder) Columns(columns ...*ColumnBuilder) *TableBuilder {
t.columns = make([]Querier, 0, len(columns))
for i := range columns {
t.columns = append(t.columns, columns[i])
}
return t
}
// PrimaryKey adds a column to the primary-key constraint in the statement.
func (t *TableBuilder) PrimaryKey(column ...string) *TableBuilder {
t.primary = append(t.primary, column...)
return t
}
// ForeignKeys adds a list of foreign-keys to the statement (without constraints).
func (t *TableBuilder) ForeignKeys(fks ...*ForeignKeyBuilder) *TableBuilder {
queries := make([]Querier, len(fks))
for i := range fks {
// Erase the constraint symbol/name.
fks[i].symbol = ""
queries[i] = fks[i]
}
t.constraints = append(t.constraints, queries...)
return t
}
// Constraints adds a list of foreign-key constraints to the statement.
func (t *TableBuilder) Constraints(fks ...*ForeignKeyBuilder) *TableBuilder {
queries := make([]Querier, len(fks))
for i := range fks {
queries[i] = &Wrapper{"CONSTRAINT %s", fks[i]}
}
t.constraints = append(t.constraints, queries...)
return t
}
// Checks adds CHECK clauses to the CREATE TABLE statement.
func (t *TableBuilder) Checks(checks ...func(*Builder)) *TableBuilder {
t.checks = append(t.checks, checks...)
return t
}
// Charset appends the `CHARACTER SET` clause to the statement. MySQL only.
func (t *TableBuilder) Charset(s string) *TableBuilder {
t.charset = s
return t
}
// Collate appends the `COLLATE` clause to the statement. MySQL only.
func (t *TableBuilder) Collate(s string) *TableBuilder {
t.collation = s
return t
}
// Options appends additional options to the statement (MySQL only).
func (t *TableBuilder) Options(s string) *TableBuilder {
t.options = s
return t
}
// Query returns query representation of a `CREATE TABLE` statement.
//
// CREATE TABLE [IF NOT EXISTS] name
//
// (table definition)
// [charset and collation]
func (t *TableBuilder) Query() (string, []any) {
t.WriteString("CREATE TABLE ")
if t.exists {
t.WriteString("IF NOT EXISTS ")
}
t.Ident(t.name)
t.Wrap(func(b *Builder) {
b.JoinComma(t.columns...)
if len(t.primary) > 0 {
b.Comma().WriteString("PRIMARY KEY")
b.Wrap(func(b *Builder) {
b.IdentComma(t.primary...)
})
}
if len(t.constraints) > 0 {
b.Comma().JoinComma(t.constraints...)
}
for _, check := range t.checks {
check(b.Comma())
}
})
if t.charset != "" {
t.WriteString(" CHARACTER SET " + t.charset)
}
if t.collation != "" {
t.WriteString(" COLLATE " + t.collation)
}
if t.options != "" {
t.WriteString(" " + t.options)
}
return t.String(), t.args
}
// ViewBuilder is a query builder for `CREATE VIEW` statement.
type ViewBuilder struct {
Builder
@@ -314,417 +136,6 @@ func (v *ViewBuilder) Query() (string, []any) {
return v.String(), v.args
}
// DescribeBuilder is a query builder for `DESCRIBE` statement.
type DescribeBuilder struct {
Builder
name string // table name.
}
// Describe returns a query builder for the `DESCRIBE` statement.
//
// Describe("users")
func Describe(name string) *DescribeBuilder { return &DescribeBuilder{name: name} }
// Query returns query representation of a `DESCRIBE` statement.
func (t *DescribeBuilder) Query() (string, []any) {
t.WriteString("DESCRIBE ")
t.Ident(t.name)
return t.String(), nil
}
// TableAlter is a query builder for `ALTER TABLE` statement.
type TableAlter struct {
Builder
name string // table to alter.
Queries []Querier // columns and foreign-keys to add.
}
// AlterTable returns a query builder for the `ALTER TABLE` statement.
//
// AlterTable("users").
// AddColumn(Column("group_id").Type("int").Attr("UNIQUE")).
// AddForeignKey(ForeignKey().Columns("group_id").
// Reference(Reference().Table("groups").Columns("id")).OnDelete("CASCADE")),
// )
func AlterTable(name string) *TableAlter { return &TableAlter{name: name} }
// AddColumn appends the `ADD COLUMN` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) AddColumn(c *ColumnBuilder) *TableAlter {
t.Queries = append(t.Queries, &Wrapper{"ADD COLUMN %s", c})
return t
}
// ModifyColumn appends the `MODIFY/ALTER COLUMN` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) ModifyColumn(c *ColumnBuilder) *TableAlter {
switch {
case t.postgres():
c.modify = true
t.Queries = append(t.Queries, &Wrapper{"ALTER COLUMN %s", c})
default:
t.Queries = append(t.Queries, &Wrapper{"MODIFY COLUMN %s", c})
}
return t
}
// RenameColumn appends the `RENAME COLUMN` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) RenameColumn(old, new string) *TableAlter {
t.Queries = append(t.Queries, Raw(fmt.Sprintf("RENAME COLUMN %s TO %s", t.Quote(old), t.Quote(new))))
return t
}
// ModifyColumns calls ModifyColumn with each of the given builders.
func (t *TableAlter) ModifyColumns(cs ...*ColumnBuilder) *TableAlter {
for _, c := range cs {
t.ModifyColumn(c)
}
return t
}
// DropColumn appends the `DROP COLUMN` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) DropColumn(c *ColumnBuilder) *TableAlter {
t.Queries = append(t.Queries, &Wrapper{"DROP COLUMN %s", c})
return t
}
// ChangeColumn appends the `CHANGE COLUMN` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) ChangeColumn(name string, c *ColumnBuilder) *TableAlter {
prefix := fmt.Sprintf("CHANGE COLUMN %s", t.Quote(name))
t.Queries = append(t.Queries, &Wrapper{prefix + " %s", c})
return t
}
// RenameIndex appends the `RENAME INDEX` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) RenameIndex(curr, new string) *TableAlter {
t.Queries = append(t.Queries, Raw(fmt.Sprintf("RENAME INDEX %s TO %s", t.Quote(curr), t.Quote(new))))
return t
}
// DropIndex appends the `DROP INDEX` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) DropIndex(name string) *TableAlter {
t.Queries = append(t.Queries, Raw(fmt.Sprintf("DROP INDEX %s", t.Quote(name))))
return t
}
// AddIndex appends the `ADD INDEX` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) AddIndex(idx *IndexBuilder) *TableAlter {
b := &Builder{dialect: t.dialect}
b.WriteString("ADD ")
if idx.unique {
b.WriteString("UNIQUE ")
}
b.WriteString("INDEX ")
b.Ident(idx.name)
b.Wrap(func(b *Builder) {
b.IdentComma(idx.columns...)
})
t.Queries = append(t.Queries, b)
return t
}
// AddForeignKey adds a foreign key constraint to the `ALTER TABLE` statement.
func (t *TableAlter) AddForeignKey(fk *ForeignKeyBuilder) *TableAlter {
t.Queries = append(t.Queries, &Wrapper{"ADD CONSTRAINT %s", fk})
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
}
// DropForeignKey appends the `DROP FOREIGN KEY` clause to the given `ALTER TABLE` statement.
func (t *TableAlter) DropForeignKey(ident string) *TableAlter {
t.Queries = append(t.Queries, Raw(fmt.Sprintf("DROP FOREIGN KEY %s", t.Quote(ident))))
return t
}
// Query returns query representation of the `ALTER TABLE` statement.
//
// ALTER TABLE name
// [alter_specification]
func (t *TableAlter) Query() (string, []any) {
t.WriteString("ALTER TABLE ")
t.Ident(t.name)
t.Pad()
t.JoinComma(t.Queries...)
return t.String(), t.args
}
// IndexAlter is a query builder for `ALTER INDEX` statement.
type IndexAlter struct {
Builder
name string // index to alter.
Queries []Querier // alter options.
}
// AlterIndex returns a query builder for the `ALTER INDEX` statement.
//
// AlterIndex("old_key").
// Rename("new_key")
func AlterIndex(name string) *IndexAlter { return &IndexAlter{name: name} }
// Rename appends the `RENAME TO` clause to the `ALTER INDEX` statement.
func (i *IndexAlter) Rename(name string) *IndexAlter {
i.Queries = append(i.Queries, Raw(fmt.Sprintf("RENAME TO %s", i.Quote(name))))
return i
}
// Query returns query representation of the `ALTER INDEX` statement.
//
// ALTER INDEX name
// [alter_specification]
func (i *IndexAlter) Query() (string, []any) {
i.WriteString("ALTER INDEX ")
i.Ident(i.name)
i.Pad()
i.JoinComma(i.Queries...)
return i.String(), i.args
}
// ForeignKeyBuilder is the builder for the foreign-key constraint clause.
type ForeignKeyBuilder struct {
Builder
symbol string
columns []string
actions []string
ref *ReferenceBuilder
}
// ForeignKey returns a builder for the foreign-key constraint clause in create/alter table statements.
//
// ForeignKey().
// Columns("group_id").
// Reference(Reference().Table("groups").Columns("id")).
// OnDelete("CASCADE")
func ForeignKey(symbol ...string) *ForeignKeyBuilder {
fk := &ForeignKeyBuilder{}
if len(symbol) != 0 {
fk.symbol = symbol[0]
}
return fk
}
// Symbol sets the symbol of the foreign key.
func (fk *ForeignKeyBuilder) Symbol(s string) *ForeignKeyBuilder {
fk.symbol = s
return fk
}
// Columns sets the columns of the foreign key in the source table.
func (fk *ForeignKeyBuilder) Columns(s ...string) *ForeignKeyBuilder {
fk.columns = append(fk.columns, s...)
return fk
}
// Reference sets the reference clause.
func (fk *ForeignKeyBuilder) Reference(r *ReferenceBuilder) *ForeignKeyBuilder {
fk.ref = r
return fk
}
// OnDelete sets the on delete action for this constraint.
func (fk *ForeignKeyBuilder) OnDelete(action string) *ForeignKeyBuilder {
fk.actions = append(fk.actions, "ON DELETE "+action)
return fk
}
// OnUpdate sets the on delete action for this constraint.
func (fk *ForeignKeyBuilder) OnUpdate(action string) *ForeignKeyBuilder {
fk.actions = append(fk.actions, "ON UPDATE "+action)
return fk
}
// Query returns query representation of a foreign key constraint.
func (fk *ForeignKeyBuilder) Query() (string, []any) {
if fk.symbol != "" {
fk.Ident(fk.symbol).Pad()
}
fk.WriteString("FOREIGN KEY")
fk.Wrap(func(b *Builder) {
b.IdentComma(fk.columns...)
})
fk.Pad().Join(fk.ref)
for _, action := range fk.actions {
fk.Pad().WriteString(action)
}
return fk.String(), fk.args
}
// ReferenceBuilder is a builder for the reference clause in constraints. For example, in foreign key creation.
type ReferenceBuilder struct {
Builder
table string // referenced table.
columns []string // referenced columns.
}
// Reference creates a reference builder for the reference_option clause.
//
// Reference().Table("groups").Columns("id")
func Reference() *ReferenceBuilder { return &ReferenceBuilder{} }
// Table sets the referenced table.
func (r *ReferenceBuilder) Table(s string) *ReferenceBuilder {
r.table = s
return r
}
// Columns sets the columns of the referenced table.
func (r *ReferenceBuilder) Columns(s ...string) *ReferenceBuilder {
r.columns = append(r.columns, s...)
return r
}
// Query returns query representation of a reference clause.
func (r *ReferenceBuilder) Query() (string, []any) {
r.WriteString("REFERENCES ")
r.Ident(r.table)
r.Wrap(func(b *Builder) {
b.IdentComma(r.columns...)
})
return r.String(), r.args
}
// IndexBuilder is a builder for `CREATE INDEX` statement.
type IndexBuilder struct {
Builder
name string
unique bool
exists bool
table string
method string
columns []string
}
// CreateIndex creates a builder for the `CREATE INDEX` statement.
//
// CreateIndex("index_name").
// Unique().
// Table("users").
// Column("name")
//
// Or:
//
// CreateIndex("index_name").
// Unique().
// Table("users").
// Columns("name", "age")
func CreateIndex(name string) *IndexBuilder {
return &IndexBuilder{name: name}
}
// IfNotExists appends the `IF NOT EXISTS` clause to the `CREATE INDEX` statement.
func (i *IndexBuilder) IfNotExists() *IndexBuilder {
i.exists = true
return i
}
// Unique sets the index to be a unique index.
func (i *IndexBuilder) Unique() *IndexBuilder {
i.unique = true
return i
}
// Table defines the table for the index.
func (i *IndexBuilder) Table(table string) *IndexBuilder {
i.table = table
return i
}
// Using sets the method to create the index with.
func (i *IndexBuilder) Using(method string) *IndexBuilder {
i.method = method
return i
}
// Column appends a column to the column list for the index.
func (i *IndexBuilder) Column(column string) *IndexBuilder {
i.columns = append(i.columns, column)
return i
}
// Columns appends the given columns to the column list for the index.
func (i *IndexBuilder) Columns(columns ...string) *IndexBuilder {
i.columns = append(i.columns, columns...)
return i
}
// Query returns query representation of a reference clause.
func (i *IndexBuilder) Query() (string, []any) {
i.WriteString("CREATE ")
if i.unique {
i.WriteString("UNIQUE ")
}
i.WriteString("INDEX ")
if i.exists {
i.WriteString("IF NOT EXISTS ")
}
i.Ident(i.name)
i.WriteString(" ON ")
i.Ident(i.table)
switch i.dialect {
case dialect.Postgres:
if i.method != "" {
i.WriteString(" USING ").Ident(i.method)
}
i.Wrap(func(b *Builder) {
b.IdentComma(i.columns...)
})
case dialect.MySQL:
i.Wrap(func(b *Builder) {
b.IdentComma(i.columns...)
})
if i.method != "" {
i.WriteString(" USING " + i.method)
}
default:
i.Wrap(func(b *Builder) {
b.IdentComma(i.columns...)
})
}
return i.String(), nil
}
// DropIndexBuilder is a builder for `DROP INDEX` statement.
type DropIndexBuilder struct {
Builder
name string
table string
}
// DropIndex creates a builder for the `DROP INDEX` statement.
//
// MySQL:
//
// DropIndex("index_name").
// Table("users").
//
// SQLite/PostgreSQL:
//
// DropIndex("index_name")
func DropIndex(name string) *DropIndexBuilder {
return &DropIndexBuilder{name: name}
}
// Table defines the table for the index.
func (d *DropIndexBuilder) Table(table string) *DropIndexBuilder {
d.table = table
return d
}
// Query returns query representation of a reference clause.
//
// DROP INDEX index_name [ON table_name]
func (d *DropIndexBuilder) Query() (string, []any) {
d.WriteString("DROP INDEX ")
d.Ident(d.name)
if d.table != "" {
d.WriteString(" ON ")
d.Ident(d.table)
}
return d.String(), nil
}
// InsertBuilder is a builder for `INSERT INTO` statement.
type InsertBuilder struct {
Builder
@@ -3990,31 +3401,6 @@ func (d *DialectBuilder) Expr(f func(*Builder)) Querier {
return Expr(d.String(f))
}
// Describe creates a DescribeBuilder for the configured dialect.
//
// Dialect(dialect.Postgres).
// Describe("users")
func (d *DialectBuilder) Describe(name string) *DescribeBuilder {
b := Describe(name)
b.SetDialect(d.dialect)
return b
}
// CreateTable creates a TableBuilder for the configured dialect.
//
// Dialect(dialect.Postgres).
// CreateTable("users").
// Columns(
// Column("id").Type("int").Attr("auto_increment"),
// Column("name").Type("varchar(255)"),
// ).
// PrimaryKey("id")
func (d *DialectBuilder) CreateTable(name string) *TableBuilder {
b := CreateTable(name)
b.SetDialect(d.dialect)
return b
}
// CreateView creates a ViewBuilder for the configured dialect.
//
// t := Table("users")
@@ -4031,32 +3417,6 @@ func (d *DialectBuilder) CreateView(name string) *ViewBuilder {
return b
}
// AlterTable creates a TableAlter for the configured dialect.
//
// Dialect(dialect.Postgres).
// AlterTable("users").
// AddColumn(Column("group_id").Type("int").Attr("UNIQUE")).
// AddForeignKey(ForeignKey().Columns("group_id").
// Reference(Reference().Table("groups").Columns("id")).
// OnDelete("CASCADE"),
// )
func (d *DialectBuilder) AlterTable(name string) *TableAlter {
b := AlterTable(name)
b.SetDialect(d.dialect)
return b
}
// AlterIndex creates an IndexAlter for the configured dialect.
//
// Dialect(dialect.Postgres).
// AlterIndex("old").
// Rename("new")
func (d *DialectBuilder) AlterIndex(name string) *IndexAlter {
b := AlterIndex(name)
b.SetDialect(d.dialect)
return b
}
// Column creates a ColumnBuilder for the configured dialect.
//
// Dialect(dialect.Postgres)..
@@ -4140,29 +3500,6 @@ func (d *DialectBuilder) With(name string) *WithBuilder {
return b
}
// CreateIndex creates a IndexBuilder for the configured dialect.
//
// Dialect(dialect.Postgres).
// CreateIndex("unique_name").
// Unique().
// Table("users").
// Columns("first", "last")
func (d *DialectBuilder) CreateIndex(name string) *IndexBuilder {
b := CreateIndex(name)
b.SetDialect(d.dialect)
return b
}
// DropIndex creates a DropIndexBuilder for the configured dialect.
//
// Dialect(dialect.Postgres).
// DropIndex("name")
func (d *DialectBuilder) DropIndex(name string) *DropIndexBuilder {
b := DropIndex(name)
b.SetDialect(d.dialect)
return b
}
func isAlias(s string) bool {
return strings.Contains(s, " AS ") || strings.Contains(s, " as ")
}

View File

@@ -22,88 +22,6 @@ func TestBuilder(t *testing.T) {
wantQuery string
wantArgs []any
}{
{
input: Describe("users"),
wantQuery: "DESCRIBE `users`",
},
{
input: CreateTable("users").
Columns(
Column("id").Type("int").Attr("auto_increment"),
Column("name").Type("varchar(255)"),
).
PrimaryKey("id"),
wantQuery: "CREATE TABLE `users`(`id` int auto_increment, `name` varchar(255), PRIMARY KEY(`id`))",
},
{
input: Dialect(dialect.Postgres).CreateTable("users").
Columns(
Column("id").Type("serial").Attr("PRIMARY KEY"),
Column("name").Type("varchar"),
),
wantQuery: `CREATE TABLE "users"("id" serial PRIMARY KEY, "name" varchar)`,
},
{
input: CreateTable("users").
Columns(
Column("id").Type("int").Attr("auto_increment"),
Column("name").Type("varchar(255)"),
).
PrimaryKey("id").
Charset("utf8mb4"),
wantQuery: "CREATE TABLE `users`(`id` int auto_increment, `name` varchar(255), PRIMARY KEY(`id`)) CHARACTER SET utf8mb4",
},
{
input: CreateTable("users").
Columns(
Column("id").Type("int").Attr("auto_increment"),
Column("name").Type("varchar(255)"),
).
PrimaryKey("id").
Charset("utf8mb4").
Collate("utf8mb4_general_ci").
Options("ENGINE=InnoDB"),
wantQuery: "CREATE TABLE `users`(`id` int auto_increment, `name` varchar(255), PRIMARY KEY(`id`)) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ENGINE=InnoDB",
},
{
input: CreateTable("users").
IfNotExists().
Columns(
Column("id").Type("int").Attr("auto_increment"),
).
PrimaryKey("id", "name"),
wantQuery: "CREATE TABLE IF NOT EXISTS `users`(`id` int auto_increment, PRIMARY KEY(`id`, `name`))",
},
{
input: CreateTable("users").
IfNotExists().
Columns(
Column("id").Type("int").Attr("auto_increment"),
Column("card_id").Type("int"),
Column("doc").Type("longtext").Check(func(b *Builder) {
b.WriteString("JSON_VALID(").Ident("doc").WriteByte(')')
}),
).
PrimaryKey("id", "name").
ForeignKeys(ForeignKey().Columns("card_id").
Reference(Reference().Table("cards").Columns("id")).OnDelete("SET NULL")).
Checks(func(b *Builder) {
b.WriteString("CONSTRAINT ").Ident("valid_card").WriteString(" CHECK (").Ident("card_id").WriteString(" > 0)")
}),
wantQuery: "CREATE TABLE IF NOT EXISTS `users`(`id` int auto_increment, `card_id` int, `doc` longtext CHECK (JSON_VALID(`doc`)), PRIMARY KEY(`id`, `name`), FOREIGN KEY(`card_id`) REFERENCES `cards`(`id`) ON DELETE SET NULL, CONSTRAINT `valid_card` CHECK (`card_id` > 0))",
},
{
input: Dialect(dialect.Postgres).CreateTable("users").
IfNotExists().
Columns(
Column("id").Type("serial"),
Column("card_id").Type("int"),
).
PrimaryKey("id", "name").
ForeignKeys(ForeignKey().Columns("card_id").
Reference(Reference().Table("cards").Columns("id")).OnDelete("SET NULL")),
wantQuery: `CREATE TABLE IF NOT EXISTS "users"("id" serial, "card_id" int, PRIMARY KEY("id", "name"), FOREIGN KEY("card_id") REFERENCES "cards"("id") ON DELETE SET NULL)`,
},
{
input: CreateView("clean_users").
Columns(
@@ -129,125 +47,6 @@ func TestBuilder(t *testing.T) {
As(Select("id", "name").From(Table("users"))),
wantQuery: "CREATE VIEW `schema`.`clean_users` AS SELECT `id`, `name` FROM `users`",
},
{
input: AlterTable("users").
AddColumn(Column("group_id").Type("int").Attr("UNIQUE")).
AddForeignKey(ForeignKey().Columns("group_id").
Reference(Reference().Table("groups").Columns("id")).
OnDelete("CASCADE"),
),
wantQuery: "ALTER TABLE `users` ADD COLUMN `group_id` int UNIQUE, ADD CONSTRAINT FOREIGN KEY(`group_id`) REFERENCES `groups`(`id`) ON DELETE CASCADE",
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
AddColumn(Column("group_id").Type("int").Attr("UNIQUE")).
AddForeignKey(ForeignKey("constraint").Columns("group_id").
Reference(Reference().Table("groups").Columns("id")).
OnDelete("CASCADE"),
),
wantQuery: `ALTER TABLE "users" ADD COLUMN "group_id" int UNIQUE, ADD CONSTRAINT "constraint" FOREIGN KEY("group_id") REFERENCES "groups"("id") ON DELETE CASCADE`,
},
{
input: AlterTable("users").
AddColumn(Column("group_id").Type("int").Attr("UNIQUE")).
AddForeignKey(ForeignKey().Columns("group_id").
Reference(Reference().Table("groups").Columns("id")),
),
wantQuery: "ALTER TABLE `users` ADD COLUMN `group_id` int UNIQUE, ADD CONSTRAINT FOREIGN KEY(`group_id`) REFERENCES `groups`(`id`)",
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
AddColumn(Column("group_id").Type("int").Attr("UNIQUE")).
AddForeignKey(ForeignKey().Columns("group_id").
Reference(Reference().Table("groups").Columns("id")),
),
wantQuery: `ALTER TABLE "users" ADD COLUMN "group_id" int UNIQUE, ADD CONSTRAINT FOREIGN KEY("group_id") REFERENCES "groups"("id")`,
},
{
input: 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)",
},
{
input: AlterTable("users").
DropForeignKey("users_parent_id"),
wantQuery: "ALTER TABLE `users` DROP FOREIGN KEY `users_parent_id`",
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
AddColumn(Column("age").Type("int")).
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").
AddForeignKey(ForeignKey().Columns("group_id").
Reference(Reference().Table("groups").Columns("id")),
).
AddForeignKey(ForeignKey().Columns("location_id").
Reference(Reference().Table("locations").Columns("id")),
),
wantQuery: "ALTER TABLE `users` ADD CONSTRAINT FOREIGN KEY(`group_id`) REFERENCES `groups`(`id`), ADD CONSTRAINT FOREIGN KEY(`location_id`) REFERENCES `locations`(`id`)",
},
{
input: AlterTable("users").
ModifyColumn(Column("age").Type("int")),
wantQuery: "ALTER TABLE `users` MODIFY COLUMN `age` int",
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
ModifyColumn(Column("age").Type("int")),
wantQuery: `ALTER TABLE "users" ALTER COLUMN "age" TYPE int`,
},
{
input: AlterTable("users").
ModifyColumn(Column("age").Type("int")).
DropColumn(Column("name")),
wantQuery: "ALTER TABLE `users` MODIFY COLUMN `age` int, DROP COLUMN `name`",
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
ModifyColumn(Column("age").Type("int")).
DropColumn(Column("name")),
wantQuery: `ALTER TABLE "users" ALTER COLUMN "age" TYPE int, DROP COLUMN "name"`,
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
ModifyColumn(Column("age").Type("int")).
ModifyColumn(Column("age").Attr("SET NOT NULL")).
ModifyColumn(Column("name").Attr("DROP NOT NULL")),
wantQuery: `ALTER TABLE "users" ALTER COLUMN "age" TYPE int, ALTER COLUMN "age" SET NOT NULL, ALTER COLUMN "name" DROP NOT NULL`,
},
{
input: AlterTable("users").
ChangeColumn("old_age", Column("age").Type("int")),
wantQuery: "ALTER TABLE `users` CHANGE COLUMN `old_age` `age` int",
},
{
input: Dialect(dialect.Postgres).AlterTable("users").
AddColumn(Column("boring").Type("varchar")).
ModifyColumn(Column("age").Type("int")).
DropColumn(Column("name")),
wantQuery: `ALTER TABLE "users" ADD COLUMN "boring" varchar, ALTER COLUMN "age" TYPE int, DROP COLUMN "name"`,
},
{
input: AlterTable("users").RenameIndex("old", "new"),
wantQuery: "ALTER TABLE `users` RENAME INDEX `old` TO `new`",
},
{
input: AlterTable("users").
DropIndex("old").
AddIndex(CreateIndex("new1").Columns("c1", "c2")).
AddIndex(CreateIndex("new2").Columns("c1", "c2").Unique()),
wantQuery: "ALTER TABLE `users` DROP INDEX `old`, ADD INDEX `new1`(`c1`, `c2`), ADD UNIQUE INDEX `new2`(`c1`, `c2`)",
},
{
input: Dialect(dialect.Postgres).AlterIndex("old").
Rename("new"),
wantQuery: `ALTER INDEX "old" RENAME TO "new"`,
},
{
input: Insert("users").Columns("age").Values(1),
wantQuery: "INSERT INTO `users` (`age`) VALUES (?)",
@@ -1522,82 +1321,12 @@ func TestBuilder(t *testing.T) {
wantQuery: `SELECT * FROM "users" WHERE "name" = $1 AND ("users"."id", "users"."name") < ($2, $3)`,
wantArgs: []any{"Ariel", 1, "Ariel"},
},
{
input: CreateIndex("name_index").Table("users").Column("name"),
wantQuery: "CREATE INDEX `name_index` ON `users`(`name`)",
},
{
input: Dialect(dialect.Postgres).
CreateIndex("name_index").
Table("users").
Column("name"),
wantQuery: `CREATE INDEX "name_index" ON "users"("name")`,
},
{
input: Dialect(dialect.Postgres).
CreateIndex("name_index").
IfNotExists().
Table("users").
Column("name"),
wantQuery: `CREATE INDEX IF NOT EXISTS "name_index" ON "users"("name")`,
},
{
input: Dialect(dialect.Postgres).
CreateIndex("name_index").
IfNotExists().
Table("users").
Using("gin").
Column("name"),
wantQuery: `CREATE INDEX IF NOT EXISTS "name_index" ON "users" USING "gin"("name")`,
},
{
input: Dialect(dialect.MySQL).
CreateIndex("name_index").
IfNotExists().
Table("users").
Using("HASH").
Column("name"),
wantQuery: "CREATE INDEX IF NOT EXISTS `name_index` ON `users`(`name`) USING HASH",
},
{
input: CreateIndex("unique_name").Unique().Table("users").Columns("first", "last"),
wantQuery: "CREATE UNIQUE INDEX `unique_name` ON `users`(`first`, `last`)",
},
{
input: Dialect(dialect.Postgres).
CreateIndex("unique_name").
Unique().
Table("users").
Columns("first", "last"),
wantQuery: `CREATE UNIQUE INDEX "unique_name" ON "users"("first", "last")`,
},
{
input: DropIndex("name_index"),
wantQuery: "DROP INDEX `name_index`",
},
{
input: Dialect(dialect.Postgres).
DropIndex("name_index"),
wantQuery: `DROP INDEX "name_index"`,
},
{
input: DropIndex("name_index").Table("users"),
wantQuery: "DROP INDEX `name_index` ON `users`",
},
{
input: Select().
From(Table("pragma_table_info('t1')").Unquote()).
OrderBy("pk"),
wantQuery: "SELECT * FROM pragma_table_info('t1') ORDER BY `pk`",
},
{
input: AlterTable("users").
AddColumn(Column("spouse").Type("integer").
Constraint(ForeignKey("user_spouse").
Reference(Reference().Table("users").Columns("id")).
OnDelete("SET NULL"))),
wantQuery: "ALTER TABLE `users` ADD COLUMN `spouse` integer CONSTRAINT user_spouse REFERENCES `users`(`id`) ON DELETE SET NULL",
},
{
input: Dialect(dialect.Postgres).
Select("*").

View File

@@ -430,28 +430,6 @@ type ForeignKey struct {
OnDelete ReferenceOption // action on delete.
}
// DSL returns a default DSL query for a foreign-key.
func (fk ForeignKey) DSL() *sql.ForeignKeyBuilder {
cols := make([]string, len(fk.Columns))
refs := make([]string, len(fk.RefColumns))
for i, c := range fk.Columns {
cols[i] = c.Name
}
for i, c := range fk.RefColumns {
refs[i] = c.Name
}
dsl := sql.ForeignKey().Symbol(fk.Symbol).
Columns(cols...).
Reference(sql.Reference().Table(fk.RefTable.Name).Columns(refs...))
if action := string(fk.OnDelete); action != "" {
dsl.OnDelete(action)
}
if action := string(fk.OnUpdate); action != "" {
dsl.OnUpdate(action)
}
return dsl
}
// ReferenceOption for constraint actions.
type ReferenceOption string
@@ -479,24 +457,6 @@ type Index struct {
realname string // real name in the database (Postgres only).
}
// Builder returns the query builder for index creation. The DSL is identical in all dialects.
func (i *Index) Builder(table string) *sql.IndexBuilder {
idx := sql.CreateIndex(i.Name).Table(table)
if i.Unique {
idx.Unique()
}
for _, c := range i.Columns {
idx.Column(c.Name)
}
return idx
}
// DropBuilder returns the query builder for the drop index.
func (i *Index) DropBuilder(table string) *sql.DropIndexBuilder {
idx := sql.DropIndex(i.Name).Table(table)
return idx
}
// Indexes used for scanning all sql.Rows into a list of indexes, because
// multiple sql rows can represent the same index (multi-columns indexes).
type Indexes []*Index