Skip to content

Commit

Permalink
Params for migration generator
Browse files Browse the repository at this point in the history
  • Loading branch information
qbart committed Feb 1, 2023
1 parent 6c836e6 commit 112b6d2
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 82 deletions.
103 changes: 51 additions & 52 deletions krab/cmd_gen_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,31 +55,10 @@ func (c *CmdGenMigration) Do(ctx context.Context, o CmdOpts) (interface{}, error
if err != nil {
return nil, err
}
kcls := []ToKCL{}
kclsAfter := []ToKCL{}
for _, v := range o.PositionalInputs {
splits := strings.Split(v, ":")
if len(splits) == 1 {
switch splits[0] {
case "id":
kcls = append(kcls, &DDLColumn{Name: "id", Type: "bigint", Null: true, Identity: &DDLIdentity{}})
kclsAfter = append(kclsAfter, &DDLPrimaryKey{Columns: []string{"id"}})
case "timestamps":
kcls = append(kcls, &DDLColumn{Name: "created_at", Type: "timestamptz", Null: false})
kcls = append(kcls, &DDLColumn{Name: "updated_at", Type: "timestamptz", Null: false})
default:
return nil, fmt.Errorf("Invalid column: %s", splits[0])
}
} else {
kcls = append(kcls, &DDLColumn{Name: splits[0], Type: splits[1], Null: true})
}
}

kcls = append(kcls, kclsAfter...)
return c.run(ctx, o.NamedInputs, kcls)
return c.run(ctx, o)
}

func (c *CmdGenMigration) run(ctx context.Context, inputs NamedInputs, columns []ToKCL) (ResponseGenMigration, error) {
func (c *CmdGenMigration) run(ctx context.Context, o CmdOpts) (ResponseGenMigration, error) {
result := ResponseGenMigration{}

dir, err := krabenv.ConfigDir()
Expand All @@ -92,40 +71,60 @@ func (c *CmdGenMigration) run(ctx context.Context, inputs NamedInputs, columns [
return result, err
}

columns := []*DDLColumn{}
pks := []*DDLPrimaryKey{}
for _, v := range o.PositionalInputs {
splits := strings.Split(v, ":")
if len(splits) == 1 {
switch splits[0] {
case "id":
columns = append(columns, &DDLColumn{Name: "id", Type: "bigint", Null: true, Identity: &DDLIdentity{}})
pks = append(pks, &DDLPrimaryKey{Columns: []string{"id"}})
case "timestamps":
columns = append(columns, &DDLColumn{Name: "created_at", Type: "timestamptz", Null: false})
columns = append(columns, &DDLColumn{Name: "updated_at", Type: "timestamptz", Null: false})
default:
return result, fmt.Errorf("Invalid column: %s", splits[0])
}
} else {
columns = append(columns, &DDLColumn{Name: splits[0], Type: splits[1], Null: true})
}
}

ref := o.NamedInputs["name"].(string)
table := ref
words := strings.SplitN(ref, "_", 2)
if len(words) == 2 && words[0] == "create" {
table = words[1]
}

version := c.VersionGenerator.Next()
ref := inputs["name"].(string)
migration := &Migration{
RefName: ref,
Version: version,
Up: MigrationUpOrDown{
CreateTables: []*DDLCreateTable{
{
Name: table,
Columns: columns,
PrimaryKeys: pks,
},
},
},
Down: MigrationUpOrDown{
DropTables: []*DDLDropTable{
{
Name: table,
},
},
},
}

result.Ref = fmt.Sprint("migration.", ref)
result.Path = filepath.Join(dir, fmt.Sprint(version, "_", ref, krabenv.Ext()))

buf := bytes.Buffer{}
buf.WriteString(`migration "`)
buf.WriteString(ref)
buf.WriteString(`" {`)
buf.WriteString("\n")
buf.WriteString(` version = "`)
buf.WriteString(version)
buf.WriteString(`"`)
buf.WriteString("\n\n")
buf.WriteString(` up {`)
buf.WriteString("\n")
for _, col := range columns {
sb := strings.Builder{}
col.ToKCL(&sb)
lines := strings.Split(sb.String(), "\n")
for _, line := range lines {
buf.WriteString(" ")
buf.WriteString(line)
buf.WriteString("\n")
}
}
buf.WriteString(` }`)
buf.WriteString("\n\n")
buf.WriteString(` down {`)
buf.WriteString("\n")
buf.WriteString(` }`)
buf.WriteString("\n")
buf.WriteString(`}`)
buf.WriteString("\n")
migration.ToKCL(&buf)

c.FS.WriteFile(result.Path, buf.Bytes(), 0644)

Expand Down
20 changes: 16 additions & 4 deletions krab/type_ddl_column.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,28 @@ func (d *DDLColumn) ToSQL(w io.StringWriter) {

// ToKCL converts migration definition to KCL.
func (d *DDLColumn) ToKCL(w io.StringWriter) {
w.WriteString("column ")
w.WriteString(" column ")
w.WriteString(krabdb.QuoteIdent(d.Name))
w.WriteString(" ")
w.WriteString(krabdb.QuoteIdent(d.Type))
w.WriteString(" {")
multiline := false
if d.Identity != nil {
w.WriteString("\n identity {}\n")
w.WriteString("\n")
d.Identity.ToKCL(w)
w.WriteString("\n")
multiline = true
}
if !d.Null {
w.WriteString("\n null = false\n")
w.WriteString("\n")
w.WriteString(" null = false")
w.WriteString("\n")
multiline = true
}
w.WriteString("}")
if multiline {
w.WriteString(" }")
} else {
w.WriteString("}")
}
w.WriteString("\n")
}
17 changes: 17 additions & 0 deletions krab/type_ddl_create_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,20 @@ func (d *DDLCreateTable) ToSQL(w io.StringWriter) {

w.WriteString("\n)")
}

// ToKCL converts migration definition to KCL.
func (d *DDLCreateTable) ToKCL(w io.StringWriter) {
w.WriteString(" create_table ")
w.WriteString(krabdb.QuoteIdent(d.Name))
w.WriteString(" {")
w.WriteString("\n")

for _, def := range d.Columns {
def.ToKCL(w)
}
for _, def := range d.PrimaryKeys {
def.ToKCL(w)
}
w.WriteString(" }")
w.WriteString("\n")
}
6 changes: 6 additions & 0 deletions krab/type_ddl_drop_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ func (d *DDLDropTable) ToSQL(w io.StringWriter) {
w.WriteString("DROP TABLE ")
w.WriteString(krabdb.QuoteIdent(d.Name))
}

func (d *DDLDropTable) ToKCL(w io.StringWriter) {
w.WriteString(" drop_table ")
w.WriteString(krabdb.QuoteIdent(d.Name))
w.WriteString(" {}\n")
}
5 changes: 5 additions & 0 deletions krab/type_ddl_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,8 @@ func (d *DDLIdentity) DecodeHCL(ctx *hcl.EvalContext, block *hcl.Block) error {
func (d *DDLIdentity) ToSQL(w io.StringWriter) {
w.WriteString("GENERATED ALWAYS AS IDENTITY")
}

// ToKCL converts migration definition to KCL.
func (d *DDLIdentity) ToKCL(w io.StringWriter) {
w.WriteString(" identity {}")
}
10 changes: 5 additions & 5 deletions krab/type_ddl_primary_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ func (d *DDLPrimaryKey) ToSQL(w io.StringWriter) {

// ToKCL converts migration definition to KCL.
func (d *DDLPrimaryKey) ToKCL(w io.StringWriter) {
w.WriteString("primary_key {\n")
w.WriteString(" columns = [")
w.WriteString(strings.Join(krabdb.QuoteIdentStrings(d.Columns), ", "))
w.WriteString("]")
w.WriteString("\n}")
w.WriteString(" primary_key {\n")
w.WriteString(" columns = [")
w.WriteString(strings.Join(krabdb.QuoteIdentStrings(d.Columns), ""))
w.WriteString("]\n")
w.WriteString(" }\n")
}
38 changes: 33 additions & 5 deletions krab/type_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"io"

"github.com/hashicorp/hcl/v2"
"github.com/ohkrab/krab/krabdb"
"github.com/ohkrab/krab/krabhcl"
)

// Migration represents single up/down migration pair.
//
type Migration struct {
krabhcl.Source

Expand Down Expand Up @@ -138,14 +138,33 @@ func (m *Migration) DecodeHCL(ctx *hcl.EvalContext, block *hcl.Block) error {
return nil
}

func (ms *Migration) Validate() error {
func (m *Migration) Validate() error {
return ErrorCoalesce(
ValidateRefName(ms.RefName),
ms.Up.Validate(),
ms.Down.Validate(),
ValidateRefName(m.RefName),
m.Up.Validate(),
m.Down.Validate(),
)
}

func (m *Migration) ToKCL(w io.StringWriter) {
w.WriteString("migration ")
w.WriteString(krabdb.QuoteIdent(m.RefName))
w.WriteString(" {\n")
w.WriteString(" version = ")
w.WriteString(krabdb.QuoteIdent(m.Version))
w.WriteString("\n\n")

w.WriteString(" up {\n")
m.Up.ToKCL(w)
w.WriteString(" }\n\n")

w.WriteString(" down {\n")
m.Down.ToKCL(w)
w.WriteString(" }\n")

w.WriteString("}")
}

// DecodeHCL parses HCL into struct.
func (m *MigrationUpOrDown) DecodeHCL(ctx *hcl.EvalContext, block *hcl.Block) error {
m.Source.Extract(block)
Expand Down Expand Up @@ -227,6 +246,15 @@ func (m *MigrationUpOrDown) ToSQL(w io.StringWriter) {
w.WriteString(m.SQL)
}

func (m *MigrationUpOrDown) ToKCL(w io.StringWriter) {
for _, t := range m.CreateTables {
t.ToKCL(w)
}
for _, t := range m.DropTables {
t.ToKCL(w)
}
}

// ToSQLStatements returns list of SQL statements to executre during the migration.
func (m *MigrationUpOrDown) ToSQLStatements() SQLStatements {
sorter := SQLStatementsSorter{Statements: SQLStatements{}, Bytes: []int{}}
Expand Down
26 changes: 10 additions & 16 deletions spec/action_gen_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ func TestActionGenMigration(t *testing.T) {
version = "20230101"
up {
create_table "maps" {
}
}
down {
drop_table "maps" {}
}
}`
ok, err := c.fs.FileContainsBytes(k, []byte(expected))
Expand All @@ -39,7 +42,7 @@ func TestActionGenMigrationWithParams(t *testing.T) {
defer c.Teardown()
c.AssertSuccessfulRun(t, []string{
"gen", "migration", "-name", "create_maps",
"id", "name:varchar", "project_id:bigint:fk=projects,id", "timestamps",
"id", "name:varchar", "project_id:bigint", "timestamps",
})
c.AssertOutputContains(t, "migration.create_maps")
files := c.FSFiles()
Expand All @@ -54,24 +57,15 @@ func TestActionGenMigrationWithParams(t *testing.T) {
identity {}
}
column "name" "varchar" {}
column "project_id" "bigint" {}
column "created_at" "timestamptz" {
null = false
}
null = false
}
column "updated_at" "timestamptz" {
null = false
}
null = false
}
primary_key {
columns = ["id"]
}
foreign_key {
columns = ["project_id"]
references "projects" {
columns = ["id"]
on_delete = "restrict"
on_update = "cascade"
}
columns = ["id"]
}
}
}
Expand Down

0 comments on commit 112b6d2

Please sign in to comment.