Skip to content

Commit

Permalink
migrate: supports INSERT Statement (#109)
Browse files Browse the repository at this point in the history
* migrate: supports INSERT Statement

* make the logic of inspectStatementsKind simpler
  • Loading branch information
knwoop authored Jul 9, 2024
1 parent cad1ab5 commit c49fe82
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 21 deletions.
7 changes: 7 additions & 0 deletions pkg/spanner/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,13 @@ func (c *Client) ExecuteMigrations(ctx context.Context, migrations Migrations, l
}
}
case statementKindDML:
if _, err := c.ApplyDML(ctx, m.Statements, PriorityTypeUnspecified); err != nil {
return &Error{
Code: ErrorCodeExecuteMigrations,
err: err,
}
}
case statementKindPartitionedDML:
if _, err := c.ApplyPartitionedDML(ctx, m.Statements, PriorityTypeUnspecified); err != nil {
return &Error{
Code: ErrorCodeExecuteMigrations,
Expand Down
6 changes: 3 additions & 3 deletions pkg/spanner/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,13 +237,13 @@ func TestExecuteMigrations(t *testing.T) {
t.Fatalf("failed to execute migration: %v", err)
}

// ensure that 000003.sql and 000004.sql have been applied.
// ensure that 000003.sql, 000004.sql and 000005.sql have been applied.
ensureMigrationColumn(t, ctx, client, "LastName", "STRING(MAX)", "NO")
ensureMigrationVersionRecord(t, ctx, client, 4, false)
ensureMigrationVersionRecord(t, ctx, client, 5, false)

// ensure that schema is not changed and ExecuteMigrate is safely finished even though no migrations should be applied.
ensureMigrationColumn(t, ctx, client, "LastName", "STRING(MAX)", "NO")
ensureMigrationVersionRecord(t, ctx, client, 4, false)
ensureMigrationVersionRecord(t, ctx, client, 5, false)
}

func ensureMigrationColumn(t *testing.T, ctx context.Context, client *Client, columnName, spannerType, isNullable string) {
Expand Down
44 changes: 27 additions & 17 deletions pkg/spanner/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ var (

MigrationNameRegex = regexp.MustCompile(`[a-zA-Z0-9_\-]+`)

dmlRegex = regexp.MustCompile("^(INSERT|UPDATE|DELETE)[\t\n\f\r ].*")
dmlRegex = regexp.MustCompile("^(INSERT)[\t\n\f\r ].*")
partitionedDmlRegex = regexp.MustCompile("^(UPDATE|DELETE)[\t\n\f\r ].*")
)

const (
statementKindDDL statementKind = "DDL"
statementKindDML statementKind = "DML"
statementKindDDL statementKind = "DDL"
statementKindDML statementKind = "DML"
statementKindPartitionedDML statementKind = "PartitionedDML"
)

type (
Expand Down Expand Up @@ -170,30 +172,38 @@ func dmlToStatements(filename string, data []byte) ([]string, error) {
}

func inspectStatementsKind(statements []string) (statementKind, error) {
kindMap := map[statementKind]uint64{
statementKindDDL: 0,
statementKindDML: 0,
if len(statements) == 0 { // Treat empty files as DDL.
return statementKindDDL, nil
}

var hasDDL, hasDML, hasPartitionedDML bool
for _, s := range statements {
if isDML(s) {
kindMap[statementKindDML]++
} else {
kindMap[statementKindDDL]++
switch {
case isDML(s):
hasDML = true
case isPartitionedDML(s):
hasPartitionedDML = true
default:
hasDDL = true
}
}

if kindMap[statementKindDML] > 0 {
if kindMap[statementKindDDL] > 0 {
return "", errors.New("cannot specify DDL and DML at same migration file")
}

switch {
case hasDDL && !hasDML && !hasPartitionedDML:
return statementKindDDL, nil
case !hasDDL && hasDML && !hasPartitionedDML:
return statementKindDML, nil
case !hasDDL && !hasDML && hasPartitionedDML:
return statementKindPartitionedDML, nil
default:
return "", errors.New("DDL, DML (INSERT), and partitioned DML (UPDATE or DELETE) must not be combined in the same migration file")
}

return statementKindDDL, nil
}

func isDML(statement string) bool {
return dmlRegex.Match([]byte(statement))
}

func isPartitionedDML(statement string) bool {
return partitionedDmlRegex.Match([]byte(statement))
}
2 changes: 1 addition & 1 deletion pkg/spanner/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestLoadMigrations(t *testing.T) {
t.Fatal(err)
}

if len(ms) != 3 {
if len(ms) != 4 {
t.Fatalf("migrations length want 3, but got %v", len(ms))
}

Expand Down
1 change: 1 addition & 0 deletions pkg/spanner/testdata/migrations/000005.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
INSERT INTO Singers (SingerID, FirstName, LastName) VALUES ("2", "Hoge", "Fuga");

0 comments on commit c49fe82

Please sign in to comment.