Skip to content

Commit

Permalink
SQL instrumentation for specs
Browse files Browse the repository at this point in the history
  • Loading branch information
qbart committed Nov 1, 2021
1 parent a1facc1 commit 49221b7
Show file tree
Hide file tree
Showing 21 changed files with 442 additions and 61 deletions.
7 changes: 5 additions & 2 deletions krab/action_migrate_down.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package krab
import (
"context"
"fmt"
"strings"

"github.com/ohkrab/krab/cli"
"github.com/ohkrab/krab/cliargs"
Expand Down Expand Up @@ -140,7 +141,7 @@ func (a *ActionMigrateDown) Do(ctx context.Context, db krabdb.DB, tpl *tpls.Temp
}

// schema migration
tx, err := krabdb.NewTx(ctx, db, migration.ShouldRunInTransaction())
tx, err := db.NewTx(ctx, migration.ShouldRunInTransaction())
if err != nil {
return errors.Wrap(err, "Failed to start transaction")
}
Expand All @@ -166,7 +167,9 @@ func (a *ActionMigrateDown) Do(ctx context.Context, db krabdb.DB, tpl *tpls.Temp
}

func (a *ActionMigrateDown) migrateDown(ctx context.Context, tx krabdb.TransactionExecerContext, migration *Migration, versions SchemaMigrationTable) error {
_, err := tx.ExecContext(ctx, migration.Down.SQL)
sql := &strings.Builder{}
migration.Down.ToSQL(sql)
_, err := tx.ExecContext(ctx, sql.String())
if err != nil {
return errors.Wrap(err, "Failed to execute migration")
}
Expand Down
7 changes: 5 additions & 2 deletions krab/action_migrate_up.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package krab
import (
"context"
"fmt"
"strings"

"github.com/ohkrab/krab/cli"
"github.com/ohkrab/krab/cliargs"
Expand Down Expand Up @@ -112,7 +113,7 @@ func (a *ActionMigrateUp) Do(ctx context.Context, db krabdb.DB, tpl *tpls.Templa

for _, pending := range pendingMigrations {
ui.Output(fmt.Sprint(pending.RefName, " ", pending.Version))
tx, err := krabdb.NewTx(ctx, db, pending.ShouldRunInTransaction())
tx, err := db.NewTx(ctx, pending.ShouldRunInTransaction())
if err != nil {
return errors.Wrap(err, "Failed to start transaction")
}
Expand All @@ -137,7 +138,9 @@ func (a *ActionMigrateUp) Do(ctx context.Context, db krabdb.DB, tpl *tpls.Templa
}

func (a *ActionMigrateUp) migrateUp(ctx context.Context, tx krabdb.TransactionExecerContext, migration *Migration, versions SchemaMigrationTable) error {
_, err := tx.ExecContext(ctx, migration.Up.SQL)
sql := &strings.Builder{}
migration.Up.ToSQL(sql)
_, err := tx.ExecContext(ctx, sql.String())
if err != nil {
return errors.Wrap(err, "Failed to execute migration")
}
Expand Down
15 changes: 15 additions & 0 deletions krab/type_ddl_check.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
package krab

import (
"io"

"github.com/ohkrab/krab/krabdb"
)

// DDLCheck constraint DSL for table DDL.
type DDLCheck struct {
Name string `hcl:"name,label"`
Expression string `hcl:"expression"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLCheck) ToSQL(w io.StringWriter) {
w.WriteString("CONSTRAINT ")
w.WriteString(krabdb.QuoteIdent(d.Name))
w.WriteString(" CHECK (")
w.WriteString(d.Expression)
w.WriteString(")")
}
58 changes: 57 additions & 1 deletion krab/type_ddl_column.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
package krab

import "github.com/hashicorp/hcl/v2"
import (
"fmt"
"io"
"strconv"

"github.com/hashicorp/hcl/v2"
"github.com/ohkrab/krab/krabdb"
"github.com/wzshiming/ctc"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/gocty"
)

// DDLColumn constraint DSL for table DDL.
type DDLColumn struct {
Expand All @@ -11,3 +21,49 @@ type DDLColumn struct {
Default hcl.Expression `hcl:"default,optional"`
Generated *DDLGeneratedColumn `hcl:"generated,block"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLColumn) ToSQL(w io.StringWriter) {
w.WriteString(krabdb.QuoteIdent(d.Name))
w.WriteString(" ")
w.WriteString(d.Type)

if d.Null != nil {
w.WriteString(" ")
if *d.Null {
w.WriteString("NULL")
} else {
w.WriteString("NOT NULL")
}
}

if d.Identity != nil {
w.WriteString(" ")
d.Identity.ToSQL(w)
}

if d.Generated != nil {
w.WriteString(" ")
d.Generated.ToSQL(w)
}

val, _ := d.Default.Value(nil)
if val.IsWhollyKnown() && !val.IsNull() {
w.WriteString(" DEFAULT ")

switch val.Type() {
case cty.Bool:
var boolean bool
if err := gocty.FromCtyValue(val, &boolean); err == nil {
w.WriteString(strconv.FormatBool(boolean))
}

default:
panic(fmt.Sprint(
ctc.BackgroundRed|ctc.ForegroundYellow,
"Cannot map default type to SQL, if you see this error please report the issue with example",
ctc.Reset,
))
}
}
}
58 changes: 58 additions & 0 deletions krab/type_ddl_create_table.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package krab

import (
"io"

"github.com/ohkrab/krab/krabdb"
)

// DDLCreateTable contains DSL for creating tables.
type DDLCreateTable struct {
Name string `hcl:"name,label"`
Expand All @@ -10,3 +16,55 @@ type DDLCreateTable struct {
Uniques []*DDLUnique `hcl:"unique,block"`
Checks []*DDLCheck `hcl:"check,block"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLCreateTable) ToSQL(w io.StringWriter) {
w.WriteString("CREATE")
if d.Unlogged {
w.WriteString(" UNLOGGED")
}
w.WriteString(" TABLE ")
w.WriteString(krabdb.QuoteIdent(d.Name))
w.WriteString("(\n")

hasPK := len(d.PrimaryKeys) > 0
hasFK := len(d.ForeignKeys) > 0
hasUnique := len(d.Uniques) > 0
hasCheck := len(d.Checks) > 0

for i, col := range d.Columns {
w.WriteString(" ")
col.ToSQL(w)
if i < len(d.Columns)-1 {
w.WriteString(",")
w.WriteString("\n")
}
}

if hasPK {
for _, pk := range d.PrimaryKeys {
w.WriteString("\n, ")
pk.ToSQL(w)
}
}
if hasFK {
for _, fk := range d.ForeignKeys {
w.WriteString("\n, ")
fk.ToSQL(w)
}
}
if hasUnique {
for _, u := range d.Uniques {
w.WriteString("\n, ")
u.ToSQL(w)
}
}
if hasCheck {
for _, c := range d.Checks {
w.WriteString("\n, ")
c.ToSQL(w)
}
}

w.WriteString("\n)")
}
14 changes: 13 additions & 1 deletion krab/type_ddl_drop_table.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
package krab

import (
"io"

"github.com/ohkrab/krab/krabdb"
)

// DDLDropTable contains DSL for dropping tables.
type DDLDropTable struct {
Table string `hcl:"table,label"`
Name string `hcl:"name,label"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLDropTable) ToSQL(w io.StringWriter) {
w.WriteString("DROP TABLE ")
w.WriteString(krabdb.QuoteIdent(d.Name))
}
17 changes: 16 additions & 1 deletion krab/type_ddl_foreign_key.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
package krab

import (
"io"
"strings"

"github.com/ohkrab/krab/krabdb"
)

// DDLForeignKey constraint DSL for table DDL.
type DDLForeignKey struct {
Name string `hcl:"name,label"`
Columns []string `hcl:"columns"`
References DDLReferences `hcl:"references,block"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLForeignKey) ToSQL(w io.StringWriter) {
w.WriteString("FOREIGN KEY (")
cols := krabdb.QuoteIdentStrings(d.Columns)
w.WriteString(strings.Join(cols, ","))
w.WriteString(") ")
d.References.ToSQL(w)
}
9 changes: 9 additions & 0 deletions krab/type_ddl_generated_column.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
package krab

import "io"

// DDLGeneratedColumn DSL.
type DDLGeneratedColumn struct {
As string `hcl:"as"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLGeneratedColumn) ToSQL(w io.StringWriter) {
w.WriteString("GENERATED ALWAYS AS (")
w.WriteString(d.As)
w.WriteString(") STORED")
}
9 changes: 8 additions & 1 deletion krab/type_ddl_identity.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package krab

import "io"

// DDLIdentity DSL.
type DDLIdentity struct {
Generated string `hcl:"generated,label"`
// Generated string `hcl:"generated,optional"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLIdentity) ToSQL(w io.StringWriter) {
w.WriteString("GENERATED ALWAYS AS IDENTITY")
}
23 changes: 22 additions & 1 deletion krab/type_ddl_primary_key.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
package krab

import (
"io"
"strings"

"github.com/ohkrab/krab/krabdb"
)

// DDLPrimaryKey constraint DSL for table DDL.
type DDLPrimaryKey struct {
Name string `hcl:"name,label"`
Columns []string `hcl:"columns"`
Include []string `hcl:"include,optional"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLPrimaryKey) ToSQL(w io.StringWriter) {
w.WriteString("PRIMARY KEY (")
cols := krabdb.QuoteIdentStrings(d.Columns)
w.WriteString(strings.Join(cols, ","))
w.WriteString(")")

if len(d.Include) > 0 {
w.WriteString(" INCLUDE (")
include := krabdb.QuoteIdentStrings(d.Include)
w.WriteString(strings.Join(include, ","))
w.WriteString(")")
}
}
27 changes: 27 additions & 0 deletions krab/type_ddl_references.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
package krab

import (
"io"
"strings"

"github.com/ohkrab/krab/krabdb"
)

// DDLReferences DSL for ForeignKey.
type DDLReferences struct {
Table string `hcl:"table,label"`
Columns []string `hcl:"columns"`
OnDelete string `hcl:"on_delete,optional"`
OnUpdate string `hcl:"on_update,optional"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLReferences) ToSQL(w io.StringWriter) {
w.WriteString("REFERENCES ")
w.WriteString(krabdb.QuoteIdent(d.Table))
w.WriteString("(")
cols := krabdb.QuoteIdentStrings(d.Columns)
w.WriteString(strings.Join(cols, ","))
w.WriteString(")")

if d.OnDelete != "" {
w.WriteString(" ON DELETE ")
w.WriteString(d.OnDelete)
}

if d.OnUpdate != "" {
w.WriteString(" ON UPDATE ")
w.WriteString(d.OnUpdate)
}
}
23 changes: 22 additions & 1 deletion krab/type_ddl_unique.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
package krab

import (
"io"
"strings"

"github.com/ohkrab/krab/krabdb"
)

// DDLUnique constraint DSL for table DDL.
type DDLUnique struct {
Name string `hcl:"name,label"`
Columns []string `hcl:"columns"`
Include []string `hcl:"include,optional"`
}

// ToSQL converts migration definition to SQL.
func (d *DDLUnique) ToSQL(w io.StringWriter) {
w.WriteString("UNIQUE (")
cols := krabdb.QuoteIdentStrings(d.Columns)
w.WriteString(strings.Join(cols, ","))
w.WriteString(")")

if len(d.Include) > 0 {
w.WriteString(" INCLUDE (")
include := krabdb.QuoteIdentStrings(d.Include)
w.WriteString(strings.Join(include, ","))
w.WriteString(")")
}
}
Loading

0 comments on commit 49221b7

Please sign in to comment.