From 788bac6e4e7982d69a3e607b6cd4cbeb2fe1090d Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Fri, 1 Dec 2023 17:01:40 +0100 Subject: [PATCH] Add JSON schema struct generation (#210) All structs matched well except for `PrimaryKey` which we mapped differently, I've refactored it to `Pk` as it doesn't seem to support different names for go and JSON --------- Signed-off-by: Alexis Rico Co-authored-by: Andrew Farries --- Makefile | 8 + pkg/migrations/check.go | 5 - pkg/migrations/fk_reference.go | 6 - pkg/migrations/op_add_column.go | 8 +- pkg/migrations/op_add_column_test.go | 54 +-- pkg/migrations/op_alter_column.go | 13 - pkg/migrations/op_alter_column_test.go | 12 +- pkg/migrations/op_change_type_test.go | 12 +- pkg/migrations/op_create_index.go | 6 - pkg/migrations/op_create_index_test.go | 12 +- pkg/migrations/op_create_table.go | 18 +- pkg/migrations/op_create_table_test.go | 36 +- pkg/migrations/op_drop_column.go | 6 - pkg/migrations/op_drop_column_test.go | 6 +- pkg/migrations/op_drop_constraint.go | 8 - pkg/migrations/op_drop_constraint_test.go | 36 +- pkg/migrations/op_drop_index.go | 4 - pkg/migrations/op_drop_index_test.go | 6 +- pkg/migrations/op_drop_table.go | 4 - pkg/migrations/op_drop_table_test.go | 6 +- pkg/migrations/op_raw_sql.go | 5 - pkg/migrations/op_rename_column_test.go | 6 +- pkg/migrations/op_rename_table.go | 5 - pkg/migrations/op_set_check_test.go | 12 +- pkg/migrations/op_set_fk_test.go | 24 +- pkg/migrations/op_set_notnull_test.go | 24 +- pkg/migrations/op_set_replica_identity.go | 10 - .../op_set_replica_identity_test.go | 12 +- pkg/migrations/op_set_unique_test.go | 12 +- pkg/migrations/types.go | 211 +++++++++ pkg/migrations/unique.go | 4 - pkg/roll/execute_test.go | 6 +- schema.json | 407 ++++++++++++++++++ 33 files changed, 766 insertions(+), 238 deletions(-) create mode 100644 Makefile create mode 100644 pkg/migrations/types.go create mode 100644 schema.json diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c1c2c0d --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +.PHONY: generate +generate: + # Generate the types from the JSON schema + docker run -v $$PWD/schema.json:/mnt/schema.json omissis/go-jsonschema:0.14.1 --only-models -p migrations --tags json /mnt/schema.json > pkg/migrations/types.go + + # Add the license header + echo "// SPDX-License-Identifier: Apache-2.0" | cat - pkg/migrations/types.go > pkg/migrations/types.go.tmp + mv pkg/migrations/types.go.tmp pkg/migrations/types.go diff --git a/pkg/migrations/check.go b/pkg/migrations/check.go index ba50279..4143a22 100644 --- a/pkg/migrations/check.go +++ b/pkg/migrations/check.go @@ -2,11 +2,6 @@ package migrations -type CheckConstraint struct { - Name string `json:"name"` - Constraint string `json:"constraint"` -} - func (c *CheckConstraint) Validate() error { if c.Name == "" { return FieldRequiredError{Name: "name"} diff --git a/pkg/migrations/fk_reference.go b/pkg/migrations/fk_reference.go index d19203a..b4eb30f 100644 --- a/pkg/migrations/fk_reference.go +++ b/pkg/migrations/fk_reference.go @@ -4,12 +4,6 @@ package migrations import "github.com/xataio/pgroll/pkg/schema" -type ForeignKeyReference struct { - Name string `json:"name"` - Table string `json:"table"` - Column string `json:"column"` -} - func (f *ForeignKeyReference) Validate(s *schema.Schema) error { if f.Name == "" { return FieldRequiredError{Name: "name"} diff --git a/pkg/migrations/op_add_column.go b/pkg/migrations/op_add_column.go index bf0dbae..ef2c866 100644 --- a/pkg/migrations/op_add_column.go +++ b/pkg/migrations/op_add_column.go @@ -12,12 +12,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpAddColumn struct { - Table string `json:"table"` - Up *string `json:"up"` - Column Column `json:"column"` -} - var _ Operation = (*OpAddColumn)(nil) func (o *OpAddColumn) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { @@ -173,7 +167,7 @@ func (o *OpAddColumn) Validate(ctx context.Context, s *schema.Schema) error { return FieldRequiredError{Name: "up"} } - if o.Column.PrimaryKey { + if o.Column.Pk { return errors.New("adding primary key columns is not supported") } diff --git a/pkg/migrations/op_add_column_test.go b/pkg/migrations/op_add_column_test.go index 3761e10..466325b 100644 --- a/pkg/migrations/op_add_column_test.go +++ b/pkg/migrations/op_add_column_test.go @@ -24,9 +24,9 @@ func TestAddColumn(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -121,9 +121,9 @@ func TestAddForeignKeyColumn(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -136,9 +136,9 @@ func TestAddForeignKeyColumn(t *testing.T) { Name: "orders", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "quantity", @@ -223,9 +223,9 @@ func TestAddForeignKeyColumn(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -238,9 +238,9 @@ func TestAddForeignKeyColumn(t *testing.T) { Name: "orders", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "quantity", @@ -332,9 +332,9 @@ func TestAddColumnWithUpSql(t *testing.T) { Name: "products", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -419,9 +419,9 @@ func TestAddNotNullColumnWithNoDefault(t *testing.T) { Name: "products", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -485,9 +485,9 @@ func TestAddColumnValidation(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -604,9 +604,9 @@ func TestAddColumnWithCheckConstraint(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", diff --git a/pkg/migrations/op_alter_column.go b/pkg/migrations/op_alter_column.go index 2660f45..ef3a789 100644 --- a/pkg/migrations/op_alter_column.go +++ b/pkg/migrations/op_alter_column.go @@ -10,19 +10,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpAlterColumn struct { - Table string `json:"table"` - Column string `json:"column"` - Name string `json:"name"` - Type string `json:"type"` - Check *CheckConstraint `json:"check"` - References *ForeignKeyReference `json:"references"` - Nullable *bool `json:"nullable"` - Unique *UniqueConstraint `json:"unique"` - Up string `json:"up"` - Down string `json:"down"` -} - var _ Operation = (*OpAlterColumn)(nil) func (o *OpAlterColumn) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_alter_column_test.go b/pkg/migrations/op_alter_column_test.go index c251b52..74c33fc 100644 --- a/pkg/migrations/op_alter_column_test.go +++ b/pkg/migrations/op_alter_column_test.go @@ -18,9 +18,9 @@ func TestAlterColumnValidation(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -32,9 +32,9 @@ func TestAlterColumnValidation(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", diff --git a/pkg/migrations/op_change_type_test.go b/pkg/migrations/op_change_type_test.go index 5597a71..16df888 100644 --- a/pkg/migrations/op_change_type_test.go +++ b/pkg/migrations/op_change_type_test.go @@ -24,9 +24,9 @@ func TestChangeColumnType(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", @@ -157,9 +157,9 @@ func TestChangeColumnTypeValidation(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", diff --git a/pkg/migrations/op_create_index.go b/pkg/migrations/op_create_index.go index 3fa0f7b..aad9b84 100644 --- a/pkg/migrations/op_create_index.go +++ b/pkg/migrations/op_create_index.go @@ -12,12 +12,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpCreateIndex struct { - Name string `json:"name"` - Table string `json:"table"` - Columns []string `json:"columns"` -} - var _ Operation = (*OpCreateIndex)(nil) func (o *OpCreateIndex) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_create_index_test.go b/pkg/migrations/op_create_index_test.go index f9092fc..4fefb53 100644 --- a/pkg/migrations/op_create_index_test.go +++ b/pkg/migrations/op_create_index_test.go @@ -22,9 +22,9 @@ func TestCreateIndex(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -73,9 +73,9 @@ func TestCreateIndexOnMultipleColumns(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", diff --git a/pkg/migrations/op_create_table.go b/pkg/migrations/op_create_table.go index f0a86f5..d2b5561 100644 --- a/pkg/migrations/op_create_table.go +++ b/pkg/migrations/op_create_table.go @@ -13,22 +13,6 @@ import ( var _ Operation = (*OpCreateTable)(nil) -type OpCreateTable struct { - Name string `json:"name"` - Columns []Column `json:"columns"` -} - -type Column struct { - Name string `json:"name"` - Type string `json:"type"` - Nullable bool `json:"nullable"` - Unique bool `json:"unique"` - PrimaryKey bool `json:"pk"` - Default *string `json:"default"` - Check *CheckConstraint `json:"check"` - References *ForeignKeyReference `json:"references"` -} - func (o *OpCreateTable) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { tempName := TemporaryName(o.Name) _, err := conn.ExecContext(ctx, fmt.Sprintf("CREATE TABLE %s (%s)", @@ -117,7 +101,7 @@ func columnsToSQL(cols []Column) string { func ColumnToSQL(col Column) string { sql := fmt.Sprintf("%s %s", pq.QuoteIdentifier(col.Name), col.Type) - if col.PrimaryKey { + if col.Pk { sql += " PRIMARY KEY" } if col.Unique { diff --git a/pkg/migrations/op_create_table_test.go b/pkg/migrations/op_create_table_test.go index 9a8509a..ae7dc50 100644 --- a/pkg/migrations/op_create_table_test.go +++ b/pkg/migrations/op_create_table_test.go @@ -25,9 +25,9 @@ func TestCreateTable(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -84,9 +84,9 @@ func TestCreateTable(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -104,9 +104,9 @@ func TestCreateTable(t *testing.T) { Name: "orders", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "user_id", @@ -181,9 +181,9 @@ func TestCreateTable(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -246,9 +246,9 @@ func TestCreateTableValidation(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -266,9 +266,9 @@ func TestCreateTableValidation(t *testing.T) { Name: "orders", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "user_id", diff --git a/pkg/migrations/op_drop_column.go b/pkg/migrations/op_drop_column.go index 06a575c..17e6e25 100644 --- a/pkg/migrations/op_drop_column.go +++ b/pkg/migrations/op_drop_column.go @@ -11,12 +11,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpDropColumn struct { - Table string `json:"table"` - Column string `json:"column"` - Down *string `json:"down,omitempty"` -} - var _ Operation = (*OpDropColumn)(nil) func (o *OpDropColumn) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_drop_column_test.go b/pkg/migrations/op_drop_column_test.go index 3079de9..59aa9f4 100644 --- a/pkg/migrations/op_drop_column_test.go +++ b/pkg/migrations/op_drop_column_test.go @@ -24,9 +24,9 @@ func TestDropColumnWithDownSQL(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", diff --git a/pkg/migrations/op_drop_constraint.go b/pkg/migrations/op_drop_constraint.go index eb3ea80..1fd931b 100644 --- a/pkg/migrations/op_drop_constraint.go +++ b/pkg/migrations/op_drop_constraint.go @@ -11,14 +11,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpDropConstraint struct { - Table string `json:"table"` - Column string `json:"column"` - Name string `json:"name"` - Up string `json:"up"` - Down string `json:"down"` -} - var _ Operation = (*OpDropConstraint)(nil) func (o *OpDropConstraint) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_drop_constraint_test.go b/pkg/migrations/op_drop_constraint_test.go index 4ba8e9a..23637a1 100644 --- a/pkg/migrations/op_drop_constraint_test.go +++ b/pkg/migrations/op_drop_constraint_test.go @@ -24,9 +24,9 @@ func TestDropConstraint(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", @@ -153,9 +153,9 @@ func TestDropConstraint(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", @@ -219,9 +219,9 @@ func TestDropConstraint(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -233,9 +233,9 @@ func TestDropConstraint(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", @@ -384,9 +384,9 @@ func TestDropConstraint(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -466,9 +466,9 @@ func TestDropConstraintValidation(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", diff --git a/pkg/migrations/op_drop_index.go b/pkg/migrations/op_drop_index.go index c525fbe..dadc45b 100644 --- a/pkg/migrations/op_drop_index.go +++ b/pkg/migrations/op_drop_index.go @@ -10,10 +10,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpDropIndex struct { - Name string `json:"name"` -} - var _ Operation = (*OpDropIndex)(nil) func (o *OpDropIndex) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_drop_index_test.go b/pkg/migrations/op_drop_index_test.go index 4fb6c8e..cd1751a 100644 --- a/pkg/migrations/op_drop_index_test.go +++ b/pkg/migrations/op_drop_index_test.go @@ -22,9 +22,9 @@ func TestDropIndex(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", diff --git a/pkg/migrations/op_drop_table.go b/pkg/migrations/op_drop_table.go index eba2001..021babc 100644 --- a/pkg/migrations/op_drop_table.go +++ b/pkg/migrations/op_drop_table.go @@ -11,10 +11,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpDropTable struct { - Name string `json:"name"` -} - var _ Operation = (*OpDropTable)(nil) func (o *OpDropTable) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_drop_table_test.go b/pkg/migrations/op_drop_table_test.go index e84ac11..9f28ff0 100644 --- a/pkg/migrations/op_drop_table_test.go +++ b/pkg/migrations/op_drop_table_test.go @@ -22,9 +22,9 @@ func TestDropTable(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", diff --git a/pkg/migrations/op_raw_sql.go b/pkg/migrations/op_raw_sql.go index 3a79393..1cb8f1a 100644 --- a/pkg/migrations/op_raw_sql.go +++ b/pkg/migrations/op_raw_sql.go @@ -11,11 +11,6 @@ import ( var _ Operation = (*OpRawSQL)(nil) -type OpRawSQL struct { - Up string `json:"up"` - Down string `json:"down,omitempty"` -} - func (o *OpRawSQL) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { _, err := conn.ExecContext(ctx, o.Up) if err != nil { diff --git a/pkg/migrations/op_rename_column_test.go b/pkg/migrations/op_rename_column_test.go index 6700d48..eaac4e4 100644 --- a/pkg/migrations/op_rename_column_test.go +++ b/pkg/migrations/op_rename_column_test.go @@ -23,9 +23,9 @@ func TestRenameColumn(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", diff --git a/pkg/migrations/op_rename_table.go b/pkg/migrations/op_rename_table.go index ba2fb85..db7d450 100644 --- a/pkg/migrations/op_rename_table.go +++ b/pkg/migrations/op_rename_table.go @@ -13,11 +13,6 @@ import ( var _ Operation = (*OpRenameTable)(nil) -type OpRenameTable struct { - From string `json:"from"` - To string `json:"to"` -} - func (o *OpRenameTable) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { return s.RenameTable(o.From, o.To) } diff --git a/pkg/migrations/op_set_check_test.go b/pkg/migrations/op_set_check_test.go index b78dd00..7d745f4 100644 --- a/pkg/migrations/op_set_check_test.go +++ b/pkg/migrations/op_set_check_test.go @@ -23,9 +23,9 @@ func TestSetCheckConstraint(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", @@ -148,9 +148,9 @@ func TestSetCheckConstraintValidation(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", diff --git a/pkg/migrations/op_set_fk_test.go b/pkg/migrations/op_set_fk_test.go index 3397dda..96cf22e 100644 --- a/pkg/migrations/op_set_fk_test.go +++ b/pkg/migrations/op_set_fk_test.go @@ -23,9 +23,9 @@ func TestSetForeignKey(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -37,9 +37,9 @@ func TestSetForeignKey(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", @@ -183,9 +183,9 @@ func TestSetForeignKeyValidation(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -197,9 +197,9 @@ func TestSetForeignKeyValidation(t *testing.T) { Name: "posts", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "title", diff --git a/pkg/migrations/op_set_notnull_test.go b/pkg/migrations/op_set_notnull_test.go index 48b3f91..c78fcee 100644 --- a/pkg/migrations/op_set_notnull_test.go +++ b/pkg/migrations/op_set_notnull_test.go @@ -24,9 +24,9 @@ func TestSetNotNull(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", @@ -166,9 +166,9 @@ func TestSetNotNull(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", @@ -235,9 +235,9 @@ func TestSetNotNullValidation(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", @@ -288,9 +288,9 @@ func TestSetNotNullValidation(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", diff --git a/pkg/migrations/op_set_replica_identity.go b/pkg/migrations/op_set_replica_identity.go index bf8e8d8..6fa1192 100644 --- a/pkg/migrations/op_set_replica_identity.go +++ b/pkg/migrations/op_set_replica_identity.go @@ -13,16 +13,6 @@ import ( "github.com/xataio/pgroll/pkg/schema" ) -type OpSetReplicaIdentity struct { - Table string `json:"table"` - Identity ReplicaIdentity `json:"identity"` -} - -type ReplicaIdentity struct { - Type string `json:"type"` - Index string `json:"index"` -} - var _ Operation = (*OpSetReplicaIdentity)(nil) func (o *OpSetReplicaIdentity) Start(ctx context.Context, conn *sql.DB, stateSchema string, s *schema.Schema, cbs ...CallbackFn) error { diff --git a/pkg/migrations/op_set_replica_identity_test.go b/pkg/migrations/op_set_replica_identity_test.go index a9124b0..b680380 100644 --- a/pkg/migrations/op_set_replica_identity_test.go +++ b/pkg/migrations/op_set_replica_identity_test.go @@ -19,9 +19,9 @@ func TestSetReplicaIdentity(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", @@ -150,9 +150,9 @@ func TestSetReplicaIdentityValidation(t *testing.T) { Name: "users", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "name", diff --git a/pkg/migrations/op_set_unique_test.go b/pkg/migrations/op_set_unique_test.go index 4b6e3c7..4d483fd 100644 --- a/pkg/migrations/op_set_unique_test.go +++ b/pkg/migrations/op_set_unique_test.go @@ -24,9 +24,9 @@ func TestSetColumnUnique(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", @@ -125,9 +125,9 @@ func TestSetColumnUnique(t *testing.T) { Name: "reviews", Columns: []migrations.Column{ { - Name: "id", - Type: "serial", - PrimaryKey: true, + Name: "id", + Type: "serial", + Pk: true, }, { Name: "username", diff --git a/pkg/migrations/types.go b/pkg/migrations/types.go new file mode 100644 index 0000000..106d45a --- /dev/null +++ b/pkg/migrations/types.go @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: Apache-2.0 +// Code generated by github.com/atombender/go-jsonschema, DO NOT EDIT. + +package migrations + +// Check constraint definition +type CheckConstraint struct { + // Constraint expression + Constraint string `json:"constraint"` + + // Name of check constraint + Name string `json:"name"` +} + +// Column definition +type Column struct { + // Check constraint for the column + Check *CheckConstraint `json:"check,omitempty"` + + // Default value for the column + Default *string `json:"default,omitempty"` + + // Name of the column + Name string `json:"name"` + + // Indicates if the column is nullable + Nullable bool `json:"nullable"` + + // Indicates if the column is part of the primary key + Pk bool `json:"pk"` + + // Foreign key constraint for the column + References *ForeignKeyReference `json:"references,omitempty"` + + // Postgres type of the column + Type string `json:"type"` + + // Indicates if the column values must be unique + Unique bool `json:"unique"` +} + +// Foreign key reference definition +type ForeignKeyReference struct { + // Name of the referenced column + Column string `json:"column"` + + // Name of the foreign key constraint + Name string `json:"name"` + + // Name of the referenced table + Table string `json:"table"` +} + +// Add column operation +type OpAddColumn struct { + // Column to add + Column Column `json:"column"` + + // Name of the table + Table string `json:"table"` + + // SQL expression for up migration + Up *string `json:"up,omitempty"` +} + +// Alter column operation +type OpAlterColumn struct { + // Add check constraint to the column + Check *CheckConstraint `json:"check,omitempty"` + + // Name of the column + Column string `json:"column"` + + // SQL expression for down migration + Down string `json:"down"` + + // New name of the column (for rename column operation) + Name string `json:"name"` + + // Indicates if the column is nullable (for add not null constraint operation) + Nullable *bool `json:"nullable,omitempty"` + + // Add foreign key constraint to the column + References *ForeignKeyReference `json:"references,omitempty"` + + // Name of the table + Table string `json:"table"` + + // New type of the column (for change type operation) + Type string `json:"type"` + + // Add unique constraint to the column + Unique *UniqueConstraint `json:"unique,omitempty"` + + // SQL expression for up migration + Up string `json:"up"` +} + +// Create index operation +type OpCreateIndex struct { + // Names of columns on which to define the index + Columns []string `json:"columns"` + + // Index name + Name string `json:"name"` + + // Name of table on which to define the index + Table string `json:"table"` +} + +// Create table operation +type OpCreateTable struct { + // Columns corresponds to the JSON schema field "columns". + Columns []Column `json:"columns"` + + // Name of the table + Name string `json:"name"` +} + +// Drop column operation +type OpDropColumn struct { + // Name of the column + Column string `json:"column"` + + // SQL expression for down migration + Down *string `json:"down,omitempty"` + + // Name of the table + Table string `json:"table"` +} + +// Drop constraint operation +type OpDropConstraint struct { + // Name of the column + Column string `json:"column"` + + // SQL expression for down migration + Down string `json:"down"` + + // Name of the constraint + Name string `json:"name"` + + // Name of the table + Table string `json:"table"` + + // SQL expression for up migration + Up string `json:"up"` +} + +// Drop index operation +type OpDropIndex struct { + // Index name + Name string `json:"name"` +} + +// Drop table operation +type OpDropTable struct { + // Name of the table + Name string `json:"name"` +} + +// Raw SQL operation +type OpRawSQL struct { + // SQL expression for down migration + Down string `json:"down,omitempty"` + + // SQL expression for up migration + Up string `json:"up"` +} + +// Rename table operation +type OpRenameTable struct { + // Old name of the table + From string `json:"from"` + + // New name of the table + To string `json:"to"` +} + +// Set replica identity operation +type OpSetReplicaIdentity struct { + // Replica identity to set + Identity ReplicaIdentity `json:"identity"` + + // Name of the table + Table string `json:"table"` +} + +// PgRoll migration definition +type PgRollMigration struct { + // Name of the migration + Name string `json:"name"` + + // Operations corresponds to the JSON schema field "operations". + Operations []interface{} `json:"operations"` +} + +// Replica identity definition +type ReplicaIdentity struct { + // Name of the index to use as replica identity + Index string `json:"index"` + + // Type of replica identity + Type string `json:"type"` +} + +// Unique constraint definition +type UniqueConstraint struct { + // Name of unique constraint + Name string `json:"name"` +} diff --git a/pkg/migrations/unique.go b/pkg/migrations/unique.go index 59cdff8..66b1129 100644 --- a/pkg/migrations/unique.go +++ b/pkg/migrations/unique.go @@ -2,10 +2,6 @@ package migrations -type UniqueConstraint struct { - Name string `json:"name"` -} - func (c *UniqueConstraint) Validate() error { if c.Name == "" { return FieldRequiredError{Name: "name"} diff --git a/pkg/roll/execute_test.go b/pkg/roll/execute_test.go index 57bdbc2..3967d0e 100644 --- a/pkg/roll/execute_test.go +++ b/pkg/roll/execute_test.go @@ -466,9 +466,9 @@ func createTableOp(tableName string) *migrations.OpCreateTable { Name: tableName, Columns: []migrations.Column{ { - Name: "id", - Type: "integer", - PrimaryKey: true, + Name: "id", + Type: "integer", + Pk: true, }, { Name: "name", diff --git a/schema.json b/schema.json new file mode 100644 index 0000000..cd988fa --- /dev/null +++ b/schema.json @@ -0,0 +1,407 @@ +{ + "$id": "https://raw.githubusercontent.com/xataio/pgroll/main/schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "JSON Schema for pgroll migrations", + "description": "This JSON schema defines the structure and properties of pgroll migrations.", + "allOf": [{ "$ref": "#/$defs/PgRollMigration" }], + "$defs": { + "CheckConstraint": { + "additionalProperties": false, + "description": "Check constraint definition", + "properties": { + "constraint": { + "description": "Constraint expression", + "type": "string" + }, + "name": { + "description": "Name of check constraint", + "type": "string" + } + }, + "required": ["constraint", "name"], + "type": "object" + }, + "Column": { + "additionalProperties": false, + "description": "Column definition", + "properties": { + "check": { + "$ref": "#/$defs/CheckConstraint", + "description": "Check constraint for the column" + }, + "default": { + "description": "Default value for the column", + "type": "string" + }, + "name": { + "description": "Name of the column", + "type": "string" + }, + "nullable": { + "description": "Indicates if the column is nullable", + "type": "boolean" + }, + "pk": { + "description": "Indicates if the column is part of the primary key", + "type": "boolean" + }, + "references": { + "$ref": "#/$defs/ForeignKeyReference", + "description": "Foreign key constraint for the column" + }, + "type": { + "description": "Postgres type of the column", + "type": "string" + }, + "unique": { + "description": "Indicates if the column values must be unique", + "type": "boolean" + } + }, + "required": ["name", "nullable", "pk", "type", "unique"], + "type": "object" + }, + "ForeignKeyReference": { + "additionalProperties": false, + "description": "Foreign key reference definition", + "properties": { + "column": { + "description": "Name of the referenced column", + "type": "string" + }, + "name": { + "description": "Name of the foreign key constraint", + "type": "string" + }, + "table": { + "description": "Name of the referenced table", + "type": "string" + } + }, + "required": ["column", "name", "table"], + "type": "object" + }, + "OpAddColumn": { + "additionalProperties": false, + "description": "Add column operation", + "properties": { + "column": { + "$ref": "#/$defs/Column", + "description": "Column to add" + }, + "table": { + "description": "Name of the table", + "type": "string" + }, + "up": { + "description": "SQL expression for up migration", + "type": "string" + } + }, + "required": ["column", "table"], + "type": "object" + }, + "OpAlterColumn": { + "additionalProperties": false, + "description": "Alter column operation", + "properties": { + "check": { + "$ref": "#/$defs/CheckConstraint", + "description": "Add check constraint to the column" + }, + "column": { + "description": "Name of the column", + "type": "string" + }, + "down": { + "description": "SQL expression for down migration", + "type": "string" + }, + "name": { + "description": "New name of the column (for rename column operation)", + "type": "string" + }, + "nullable": { + "description": "Indicates if the column is nullable (for add not null constraint operation)", + "type": "boolean" + }, + "references": { + "$ref": "#/$defs/ForeignKeyReference", + "description": "Add foreign key constraint to the column" + }, + "table": { + "description": "Name of the table", + "type": "string" + }, + "type": { + "description": "New type of the column (for change type operation)", + "type": "string" + }, + "unique": { + "$ref": "#/$defs/UniqueConstraint", + "description": "Add unique constraint to the column" + }, + "up": { + "description": "SQL expression for up migration", + "type": "string" + } + }, + "required": ["column", "down", "name", "table", "type", "up"], + "type": "object" + }, + "OpCreateIndex": { + "additionalProperties": false, + "description": "Create index operation", + "properties": { + "columns": { + "description": "Names of columns on which to define the index", + "items": { + "type": "string" + }, + "type": "array" + }, + "name": { + "description": "Index name", + "type": "string" + }, + "table": { + "description": "Name of table on which to define the index", + "type": "string" + } + }, + "required": ["columns", "name", "table"], + "type": "object" + }, + "OpCreateTable": { + "additionalProperties": false, + "description": "Create table operation", + "properties": { + "columns": { + "items": { + "$ref": "#/$defs/Column", + "description": "Columns to add to the table" + }, + "type": "array" + }, + "name": { + "description": "Name of the table", + "type": "string" + } + }, + "required": ["columns", "name"], + "type": "object" + }, + "OpDropColumn": { + "additionalProperties": false, + "description": "Drop column operation", + "properties": { + "column": { + "description": "Name of the column", + "type": "string" + }, + "down": { + "description": "SQL expression for down migration", + "type": "string" + }, + "table": { + "description": "Name of the table", + "type": "string" + } + }, + "required": ["column", "table"], + "type": "object" + }, + "OpDropConstraint": { + "additionalProperties": false, + "description": "Drop constraint operation", + "properties": { + "column": { + "description": "Name of the column", + "type": "string" + }, + "down": { + "description": "SQL expression for down migration", + "type": "string" + }, + "name": { + "description": "Name of the constraint", + "type": "string" + }, + "table": { + "description": "Name of the table", + "type": "string" + }, + "up": { + "description": "SQL expression for up migration", + "type": "string" + } + }, + "required": ["column", "down", "name", "table", "up"], + "type": "object" + }, + "OpDropIndex": { + "additionalProperties": false, + "description": "Drop index operation", + "properties": { + "name": { + "description": "Index name", + "type": "string" + } + }, + "required": ["name"], + "type": "object" + }, + "OpDropTable": { + "additionalProperties": false, + "description": "Drop table operation", + "properties": { + "name": { + "description": "Name of the table", + "type": "string" + } + }, + "required": ["name"], + "type": "object" + }, + "OpRawSQL": { + "additionalProperties": false, + "description": "Raw SQL operation", + "properties": { + "down": { + "default": "", + "description": "SQL expression for down migration", + "type": "string" + }, + "up": { + "description": "SQL expression for up migration", + "type": "string" + } + }, + "required": ["up"], + "type": "object" + }, + "OpRenameTable": { + "additionalProperties": false, + "description": "Rename table operation", + "properties": { + "from": { + "description": "Old name of the table", + "type": "string" + }, + "to": { + "description": "New name of the table", + "type": "string" + } + }, + "required": ["from", "to"], + "type": "object" + }, + "OpSetReplicaIdentity": { + "additionalProperties": false, + "description": "Set replica identity operation", + "properties": { + "identity": { + "$ref": "#/$defs/ReplicaIdentity", + "description": "Replica identity to set" + }, + "table": { + "description": "Name of the table", + "type": "string" + } + }, + "required": ["identity", "table"], + "type": "object" + }, + "PgRollMigration": { + "additionalProperties": false, + "description": "PgRoll migration definition", + "properties": { + "name": { + "description": "Name of the migration", + "type": "string" + }, + "operations": { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/OpAddColumn", + "description": "Add column operation" + }, + { + "$ref": "#/$defs/OpAlterColumn", + "description": "Alter column operation" + }, + { + "$ref": "#/$defs/OpCreateIndex", + "description": "Create index operation" + }, + { + "$ref": "#/$defs/OpCreateTable", + "description": "Create table operation" + }, + { + "$ref": "#/$defs/OpDropColumn", + "description": "Drop column operation" + }, + { + "$ref": "#/$defs/OpDropConstraint", + "description": "Drop constraint operation" + }, + { + "$ref": "#/$defs/OpDropIndex", + "description": "Drop index operation" + }, + { + "$ref": "#/$defs/OpDropTable", + "description": "Drop table operation" + }, + { + "$ref": "#/$defs/OpRawSQL", + "description": "Raw SQL operation" + }, + { + "$ref": "#/$defs/OpRenameTable", + "description": "Rename table operation" + }, + { + "$ref": "#/$defs/OpSetReplicaIdentity", + "description": "Set replica identity operation" + } + ] + }, + "type": "array" + } + }, + "required": ["name", "operations"], + "type": "object" + }, + "ReplicaIdentity": { + "additionalProperties": false, + "description": "Replica identity definition", + "properties": { + "index": { + "description": "Name of the index to use as replica identity", + "type": "string" + }, + "type": { + "description": "Type of replica identity", + "type": "string" + } + }, + "required": ["index", "type"], + "type": "object" + }, + "UniqueConstraint": { + "additionalProperties": false, + "description": "Unique constraint definition", + "properties": { + "name": { + "description": "Name of unique constraint", + "type": "string" + } + }, + "required": ["name"], + "type": "object" + } + } +}