diff --git a/builder/table.go b/builder/table.go index 1777451..27713d0 100644 --- a/builder/table.go +++ b/builder/table.go @@ -7,8 +7,10 @@ import ( "github.com/go-rel/rel" ) -type ColumnMapper func(*rel.Column) (string, int, int) -type DefinitionFilter func(table rel.Table, def rel.TableDefinition) bool +type ( + ColumnMapper func(*rel.Column) (string, int, int) + DefinitionFilter func(table rel.Table, def rel.TableDefinition) bool +) // Table builder. type Table struct { @@ -19,9 +21,7 @@ type Table struct { // Build SQL query for table creation and modification. func (t Table) Build(table rel.Table) string { - var ( - buffer = t.BufferFactory.Create() - ) + buffer := t.BufferFactory.Create() switch table.Op { case rel.SchemaCreate: @@ -86,6 +86,10 @@ func (t Table) WriteAlterTable(buffer *Buffer, table rel.Table) { case rel.SchemaCreate: buffer.WriteString("ADD COLUMN ") t.WriteColumn(buffer, v) + case rel.SchemaAlter: + buffer.WriteString("ALTER COLUMN ") + buffer.WriteEscape(v.Name) + t.WriteAlterColumn(buffer, v) case rel.SchemaRename: // Add Change buffer.WriteString("RENAME COLUMN ") @@ -131,14 +135,10 @@ func (t Table) WriteDropTable(buffer *Buffer, table rel.Table) { buffer.WriteByte(';') } -// WriteColumn definition to buffer. -func (t Table) WriteColumn(buffer *Buffer, column rel.Column) { - var ( - typ, m, n = t.ColumnMapper(&column) - ) +// WriteColumnType definition to buffer. +func (t Table) WriteColumnType(buffer *Buffer, column rel.Column) { + typ, m, n := t.ColumnMapper(&column) - buffer.WriteEscape(column.Name) - buffer.WriteByte(' ') buffer.WriteString(typ) if m != 0 { @@ -156,6 +156,14 @@ func (t Table) WriteColumn(buffer *Buffer, column rel.Column) { if column.Unsigned { buffer.WriteString(" UNSIGNED") } +} + +// WriteColumn definition to buffer. +func (t Table) WriteColumn(buffer *Buffer, column rel.Column) { + buffer.WriteEscape(column.Name) + buffer.WriteByte(' ') + + t.WriteColumnType(buffer, column) if column.Unique { buffer.WriteString(" UNIQUE") @@ -177,11 +185,31 @@ func (t Table) WriteColumn(buffer *Buffer, column rel.Column) { t.WriteOptions(buffer, column.Options) } +// WriteAlterColumn definition to buffer. +func (t Table) WriteAlterColumn(buffer *Buffer, column rel.Column) { + switch column.Constr { + case rel.AlterColumnType: + buffer.WriteString(" TYPE ") + t.WriteColumnType(buffer, column) + case rel.AlterColumnDefault: + if column.Default != nil { + buffer.WriteString(" SET DEFAULT ") + buffer.WriteValue(column.Default) + } else { + buffer.WriteString(" DROP DEFAULT") + } + case rel.AlterColumnRequired: + if column.Required { + buffer.WriteString(" SET NOT NULL") + } else { + buffer.WriteString(" DROP NOT NULL") + } + } +} + // WriteKey definition to buffer. func (t Table) WriteKey(buffer *Buffer, key rel.Key) { - var ( - typ = string(key.Type) - ) + typ := string(key.Type) buffer.WriteString(typ) diff --git a/builder/table_test.go b/builder/table_test.go index 2cbf657..73c06b4 100644 --- a/builder/table_test.go +++ b/builder/table_test.go @@ -10,12 +10,10 @@ import ( ) func TestTable_Build(t *testing.T) { - var ( - tableBuilder = Table{ - BufferFactory: BufferFactory{InlineValues: true, BoolTrueValue: "true", BoolFalseValue: "false", Quoter: Quote{IDPrefix: "`", IDSuffix: "`", IDSuffixEscapeChar: "`", ValueQuote: "'", ValueQuoteEscapeChar: "'"}}, - ColumnMapper: sql.ColumnMapper, - } - ) + tableBuilder := Table{ + BufferFactory: BufferFactory{InlineValues: true, BoolTrueValue: "true", BoolFalseValue: "false", Quoter: Quote{IDPrefix: "`", IDSuffix: "`", IDSuffixEscapeChar: "`", ValueQuote: "'", ValueQuoteEscapeChar: "'"}}, + ColumnMapper: sql.ColumnMapper, + } tests := []struct { result string @@ -80,14 +78,13 @@ func TestTable_Build(t *testing.T) { }, }, { - result: "ALTER TABLE `columns` ADD COLUMN `verified` BOOL;ALTER TABLE `columns` RENAME COLUMN `string` TO `name`;ALTER TABLE `columns` ;ALTER TABLE `columns` DROP COLUMN `blob`;", + result: "ALTER TABLE `columns` ADD COLUMN `verified` BOOL;ALTER TABLE `columns` RENAME COLUMN `string` TO `name`;ALTER TABLE `columns` DROP COLUMN `blob`;", table: rel.Table{ Op: rel.SchemaAlter, Name: "columns", Definitions: []rel.TableDefinition{ rel.Column{Name: "verified", Type: rel.Bool, Op: rel.SchemaCreate}, rel.Column{Name: "string", Rename: "name", Op: rel.SchemaRename}, - rel.Column{Name: "bool", Type: rel.Int, Op: rel.SchemaAlter}, rel.Column{Name: "blob", Op: rel.SchemaDrop}, }, }, @@ -102,6 +99,29 @@ func TestTable_Build(t *testing.T) { }, }, }, + { + result: "ALTER TABLE `columns` ALTER COLUMN `name` TYPE VARCHAR(100);", + table: rel.Table{ + Op: rel.SchemaAlter, + Name: "columns", + Definitions: []rel.TableDefinition{ + rel.Column{Name: "name", Type: rel.String, Limit: 100, Op: rel.SchemaAlter, Constr: rel.AlterColumnType}, + }, + }, + }, + { + result: "ALTER TABLE `columns` ALTER COLUMN `bool` SET DEFAULT 1;ALTER TABLE `columns` ALTER COLUMN `bool` SET NOT NULL;ALTER TABLE `columns` ALTER COLUMN `verified` DROP DEFAULT;ALTER TABLE `columns` ALTER COLUMN `verified` DROP NOT NULL;", + table: rel.Table{ + Op: rel.SchemaAlter, + Name: "columns", + Definitions: []rel.TableDefinition{ + rel.Column{Name: "bool", Default: 1, Op: rel.SchemaAlter, Constr: rel.AlterColumnDefault}, + rel.Column{Name: "bool", Required: true, Op: rel.SchemaAlter, Constr: rel.AlterColumnRequired}, + rel.Column{Name: "verified", Default: nil, Op: rel.SchemaAlter, Constr: rel.AlterColumnDefault}, + rel.Column{Name: "verified", Op: rel.SchemaAlter, Constr: rel.AlterColumnRequired}, + }, + }, + }, { result: "ALTER TABLE `table` RENAME TO `table1`;", table: rel.Table{ @@ -143,6 +163,11 @@ func TestTable_BuildWithDefinitionFilter(t *testing.T) { if ok && table.Op == rel.SchemaAlter { return false } + // > Other kinds of ALTER TABLE operations such as ALTER COLUMN, ADD CONSTRAINT, and so forth are omitted. + col, ok := def.(rel.Column) + if ok && col.Op == rel.SchemaAlter { + return false + } return true } @@ -182,18 +207,40 @@ func TestTable_BuildWithDefinitionFilter(t *testing.T) { }, }, { - result: "ALTER TABLE `columns` ADD COLUMN `verified` BOOL;ALTER TABLE `columns` RENAME COLUMN `string` TO `name`;ALTER TABLE `columns` ;ALTER TABLE `columns` DROP COLUMN `blob`;", + result: "ALTER TABLE `columns` ADD COLUMN `verified` BOOL;ALTER TABLE `columns` RENAME COLUMN `string` TO `name`;ALTER TABLE `columns` DROP COLUMN `blob`;", table: rel.Table{ Op: rel.SchemaAlter, Name: "columns", Definitions: []rel.TableDefinition{ rel.Column{Name: "verified", Type: rel.Bool, Op: rel.SchemaCreate}, rel.Column{Name: "string", Rename: "name", Op: rel.SchemaRename}, - rel.Column{Name: "bool", Type: rel.Int, Op: rel.SchemaAlter}, rel.Column{Name: "blob", Op: rel.SchemaDrop}, }, }, }, + { + result: "", + table: rel.Table{ + Op: rel.SchemaAlter, + Name: "columns", + Definitions: []rel.TableDefinition{ + rel.Column{Name: "name", Type: rel.String, Limit: 100, Op: rel.SchemaAlter, Constr: rel.AlterColumnType}, + }, + }, + }, + { + result: "", + table: rel.Table{ + Op: rel.SchemaAlter, + Name: "columns", + Definitions: []rel.TableDefinition{ + rel.Column{Name: "bool", Default: 1, Op: rel.SchemaAlter, Constr: rel.AlterColumnDefault}, + rel.Column{Name: "bool", Required: true, Op: rel.SchemaAlter, Constr: rel.AlterColumnRequired}, + rel.Column{Name: "verified", Default: nil, Op: rel.SchemaAlter, Constr: rel.AlterColumnDefault}, + rel.Column{Name: "verified", Op: rel.SchemaAlter, Constr: rel.AlterColumnRequired}, + }, + }, + }, { result: "", table: rel.Table{ diff --git a/go.mod b/go.mod index 6bc4400..38b74f7 100644 --- a/go.mod +++ b/go.mod @@ -19,3 +19,5 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace github.com/go-rel/rel v0.39.0 => github.com/lafriks-fork/rel v0.39.1-0.20221108214643-1b07f1a5dddc diff --git a/go.sum b/go.sum index 307a430..1ec33bb 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-rel/rel v0.39.0 h1:2zmK8kazM82iRRfWX7+mm1MxDkGKDj2W+xJLjguli5U= -github.com/go-rel/rel v0.39.0/go.mod h1:yN6+aimHyRIzbuWFe5DaxiZPuVuPfd7GlLpy/YTqTUg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/lafriks-fork/rel v0.39.1-0.20221108214643-1b07f1a5dddc h1:DfFCMkOmGZw67NjY95zYLNLt13kW+P5+nM8pQUKR4c8= +github.com/lafriks-fork/rel v0.39.1-0.20221108214643-1b07f1a5dddc/go.mod h1:ZmXMIRDQHbw29qOfWtO6HSq1UqNxthlsjmt++3FZSDs= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4=