Skip to content

Commit

Permalink
feat: add change column default, add table comment
Browse files Browse the repository at this point in the history
  • Loading branch information
alexisvisco committed May 24, 2024
1 parent db2ce9a commit f75abca
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 9 deletions.
2 changes: 2 additions & 0 deletions docs/docs/04-api/01-postgres/01-constructive.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ They are the operations that create, alter, or drop tables, columns, indexes, co

- [AddColumnComment(tableName schema.TableName, columnName string, comment *string, opts ...schema.ColumnCommentOptions)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.AddColumnComment)

- [AddTableComment(tableName schema.TableName, comment *string, opts ...schema.TableCommentOptions)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.AddTableComment)

- [AddCheckConstraint(tableName schema.TableName, constraintName string, expression string, opts ...schema.CheckConstraintOptions)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.AddCheckConstraint)

- [AddExtension(name string, option ...schema.ExtensionOptions)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.AddExtension)
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/04-api/01-postgres/04-transformative.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ They are the operations that change the data in the database.
- [RenameTable(tableName schema.TableName, newTableName string)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.RenameTable)

- [ChangeColumnType(tableName schema.TableName, columnName string, columnType schema.ColumnType, opts ...schema.ChangeColumnTypeOptions)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.ChangeColumnType)

- [ChangeColumnDefault(tableName schema.TableName, columnName string, defaultValue string, opts ...schema.ChangeColumnDefaultOptions)](https://pkg.go.dev/github.com/alexisvisco/amigo/pkg/schema/pg#Schema.ChangeColumnDefault)
2 changes: 1 addition & 1 deletion docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sidebar_position: 1
---

[![Go Report Card](https://goreportcard.com/badge/github.com/alexisvisco/amigo)](https://goreportcard.com/report/github.com/alexisvisco/amigo)
[![GoDoc](https://pkg.go.dev/badge/alexisvisco/mig)](https://pkg.go.dev/alexisvisco/mig)
[![GoDoc](https://pkg.go.dev/badge/alexisvisco/amigo)](https://pkg.go.dev/alexisvisco/mig)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![GitHub release](https://img.shields.io/github/v/release/alexisvisco/amigo.svg)](https://github.com/alexisvisco/amigo/releases)
[![Tests](https://github.com/alexisvisco/amigo/actions/workflows/tests.yml/badge.svg)](https://github.com/alexisvisco/amigo/actions/workflows/tests.yml)
Expand Down
20 changes: 16 additions & 4 deletions pkg/schema/migrator_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ type MigrationEvents struct {
tablesCreated []TableOptions
versionCreated []string

columnsRenamed []RenameColumnOptions
tablesRenamed []RenameTableOptions
changeColumnTypes []ChangeColumnTypeOptions
columnComments []ColumnCommentOptions
columnsRenamed []RenameColumnOptions
tablesRenamed []RenameTableOptions
changeColumnTypes []ChangeColumnTypeOptions
columnComments []ColumnCommentOptions
tableComments []TableCommentOptions
changeColumnDefaults []ChangeColumnDefaultOptions

extensionsDropped []DropExtensionOptions
tablesDropped []DropTableOptions
Expand Down Expand Up @@ -183,3 +185,13 @@ func (m *MigratorContext) AddChangeColumnType(options ChangeColumnTypeOptions) {
m.MigrationEvents.changeColumnTypes = append(m.MigrationEvents.changeColumnTypes, options)
logger.Info(options)
}

func (m *MigratorContext) AddChangeColumnDefault(options ChangeColumnDefaultOptions) {
m.MigrationEvents.changeColumnDefaults = append(m.MigrationEvents.changeColumnDefaults, options)
logger.Info(options)
}

func (m *MigratorContext) AddTableComment(options TableCommentOptions) {
m.MigrationEvents.tableComments = append(m.MigrationEvents.tableComments, options)
logger.Info(options)
}
39 changes: 38 additions & 1 deletion pkg/schema/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ func (c ColumnCommentOptions) EventName() string {
}

func (c ColumnCommentOptions) String() string {
cmt := "nil"
cmt := "NULL"
if c.Comment != nil {
cmt = fmt.Sprintf("%q", *c.Comment)
}
Expand Down Expand Up @@ -580,6 +580,41 @@ func (c *ChangeColumnTypeOptions) IsArray() bool {
return c.Array
}

type ChangeColumnDefaultOptions struct {
Table TableName
ColumnName string
Value string

Reversible *ChangeColumnDefaultOptions
}

func (c *ChangeColumnDefaultOptions) EventName() string {
return "ChangeColumnDefaultEvent"
}

func (c *ChangeColumnDefaultOptions) String() string {
return fmt.Sprintf("-- change_column_default(table: %s, column: %s, value: %s)", c.Table, c.ColumnName, c.Value)
}

type TableCommentOptions struct {
Table TableName
Comment *string

Reversible *TableCommentOptions
}

func (t TableCommentOptions) EventName() string {
return "TableCommentEvent"
}

func (t TableCommentOptions) String() string {
cmt := "NULL"
if t.Comment != nil {
cmt = fmt.Sprintf("%q", *t.Comment)
}
return fmt.Sprintf("-- comment_table(table: %s, comment: %s)", t.Table, cmt)
}

type PrimaryKeyConstraintOptions struct {
Table TableName

Expand Down Expand Up @@ -661,6 +696,8 @@ type TableOptions struct {
// Option is at the end of the table creation.
Option string

Comment *string

// TableDefinition is the definition of the table. Usually a struct that implements TableDef will allow you to
// define the columns and other options.
TableDefinition TableDef
Expand Down
48 changes: 47 additions & 1 deletion pkg/schema/pg/postgres_column.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (p *Schema) AddTimestamps(tableName schema.TableName) {
//
// Example:
//
// p.AddColumnComment("users", "name", schema.utils.Ptr("The name of the User"))
// p.AddColumnComment("users", "name", utils.Ptr("The name of the User"))
//
// Generates:
//
Expand Down Expand Up @@ -397,6 +397,52 @@ func (p *Schema) ChangeColumnType(tableName schema.TableName, columnName string,
p.Context.AddChangeColumnType(options)
}

// ChangeColumnDefault changes the default value of a column.
//
// Example:
//
// p.ChangeColumnDefault("users", "status", "'draft'")
//
// Generates:
//
// ALTER TABLE "users" ALTER COLUMN "status" SET DEFAULT 'draft'
func (p *Schema) ChangeColumnDefault(tableName schema.TableName, columnName, defaultValue string, opts ...schema.ChangeColumnDefaultOptions) {
options := schema.ChangeColumnDefaultOptions{}
if len(opts) > 0 {
options = opts[0]
}

options.Table = tableName
options.ColumnName = columnName
options.Value = defaultValue

if p.Context.MigrationDirection == types.MigrationDirectionDown {
if options.Reversible != nil {
p.rollbackMode().ChangeColumnDefault(tableName, columnName, options.Reversible.Value, *options.Reversible)
} else {
logger.Warn(events.MessageEvent{
Message: fmt.Sprintf("unable to recreate the column %s.%s", tableName, columnName),
})
}
return
}

query := "ALTER TABLE {table_name} ALTER COLUMN {column_name} SET DEFAULT {default}"
replacer := utils.Replacer{
"table_name": utils.StrFunc(options.Table.String()),
"column_name": utils.StrFunc(options.ColumnName),
"default": utils.StrFunc(options.Value),
}

_, err := p.DB.ExecContext(p.Context.Context, replacer.Replace(query))
if err != nil {
p.Context.RaiseError(fmt.Errorf("error while changing column default: %w", err))
return
}

p.Context.AddChangeColumnDefault(options)
}

func (p *Schema) toType(c schema.ColumnType, co schema.ColumnData) string {
p.modifyColumnOptionFromType(c, co)

Expand Down
26 changes: 26 additions & 0 deletions pkg/schema/pg/postgres_column_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,32 @@ CREATE TABLE IF NOT EXISTS {schema}.articles()

}

func TestPostgres_ChangeColumnDefault(t *testing.T) {
t.Parallel()

sc := "tst_pg_add_column_with_default"

base := `create table {schema}.articles(id integer);`

t.Run("simple change", func(t *testing.T) {
t.Parallel()
p, r, sc := baseTest(t, base, sc, 0)

p.ChangeColumnDefault(schema.Table("articles", sc), "id", "4")

testutils.AssertSnapshotDiff(t, r.FormatRecords(), true)
})

t.Run("null change", func(t *testing.T) {
t.Parallel()
p, r, sc := baseTest(t, base, sc, 1)

p.ChangeColumnDefault(schema.Table("articles", sc), "id", "null")

testutils.AssertSnapshotDiff(t, r.FormatRecords(), true)
})
}

func TestPostgres_DropColumn(t *testing.T) {
t.Parallel()

Expand Down
56 changes: 56 additions & 0 deletions pkg/schema/pg/postgres_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ func (p *Schema) CreateTable(tableName schema.TableName, f func(*PostgresTableDe
return
}

if options.Comment != nil {
p.AddTableComment(tableName, options.Comment)
}

p.Context.AddTableCreated(options)

for _, afterCreate := range td.deferCreationAction {
Expand Down Expand Up @@ -470,3 +474,55 @@ func (p *Schema) RenameTable(oldTableName, newTableName schema.TableName) {

p.Context.AddTableRenamed(schema.RenameTableOptions{OldTable: oldTableName, NewTable: newTableName})
}

// AddTableComment adds a comment to a table in the database.
//
// Example:
//
// p.AddTableComment("users", utils.Ptr("This table contains the users"))
//
// Generates:
//
// COMMENT ON TABLE "users" IS 'This table contains the users'
//
// To remove a comment from a table:
//
// p.AddTableComment("users", nil)
//
// Generates:
//
// COMMENT ON TABLE "users" IS NULL
func (p *Schema) AddTableComment(tableName schema.TableName, comment *string, opts ...schema.TableCommentOptions) {
options := schema.TableCommentOptions{}
if len(opts) > 0 {
options = opts[0]
}

options.Table = tableName
options.Comment = comment

if p.Context.MigrationDirection == types.MigrationDirectionDown && options.Reversible != nil {
p.rollbackMode().AddTableComment(tableName, options.Reversible.Comment)
return
}

sql := `COMMENT ON TABLE {table_name} IS {comment}`

replacer := utils.Replacer{
"table_name": utils.StrFunc(options.Table.String()),
"comment": func() string {
if options.Comment == nil {
return "NULL"
}
return fmt.Sprintf("'%s'", *options.Comment)
},
}

_, err := p.DB.ExecContext(p.Context.Context, replacer.Replace(sql))
if err != nil {
p.Context.RaiseError(fmt.Errorf("error while adding column comment: %w", err))
return
}

p.Context.AddTableComment(options)
}
36 changes: 35 additions & 1 deletion pkg/schema/pg/postgres_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pg

import (
"github.com/alexisvisco/amigo/pkg/schema"
"github.com/alexisvisco/amigo/pkg/utils"
"github.com/alexisvisco/amigo/pkg/utils/testutils"
"github.com/stretchr/testify/require"
"testing"
Expand Down Expand Up @@ -118,6 +119,7 @@ func TestPostgres_CreateTable(t *testing.T) {
t.Serial("id")
t.String("title")
}, schema.TableOptions{
Comment: utils.Ptr("This is a table without primary key"),
WithoutPrimaryKey: true,
})

Expand All @@ -126,7 +128,7 @@ func TestPostgres_CreateTable(t *testing.T) {
t.String("title")
})

testutils.AssertSnapshotDiff(t, r.FormatRecords(), true)
testutils.AssertSnapshotDiff(t, r.FormatRecords())
assertTableExist(t, p, schema.Table("articles", sc))
assertTableExist(t, p, schema.Table("articles_without_id", sc))
})
Expand Down Expand Up @@ -176,6 +178,38 @@ func TestPostgres_DropTable(t *testing.T) {
})
}

func TestPostgres_AddTableComment(t *testing.T) {
t.Parallel()

sc := "tst_pg_add_table_comment"

t.Run("add table comment", func(t *testing.T) {
t.Parallel()
p, r, sc := baseTest(t, "select 1;", sc, 0)

p.CreateTable(schema.Table("articles", sc), func(t *PostgresTableDef) {
t.Serial("id")
})

p.AddTableComment(schema.Table("articles", sc), utils.Ptr("This is a table of articles"))

testutils.AssertSnapshotDiff(t, r.FormatRecords())
})

t.Run("add table comment null", func(t *testing.T) {
t.Parallel()
p, r, sc := baseTest(t, "select 1;", sc, 1)

p.CreateTable(schema.Table("articles", sc), func(t *PostgresTableDef) {
t.Serial("id")
})

p.AddTableComment(schema.Table("articles", sc), nil)

testutils.AssertSnapshotDiff(t, r.FormatRecords())
})
}

func TestPostgres_RenameTable(t *testing.T) {
t.Parallel()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE tst_pg_add_table_comment_0.articles (
"id" SERIAL NOT NULL PRIMARY KEY
)
COMMENT ON TABLE tst_pg_add_table_comment_0.articles IS 'This is a table of articles'
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE tst_pg_add_table_comment_1.articles (
"id" SERIAL NOT NULL PRIMARY KEY
)
COMMENT ON TABLE tst_pg_add_table_comment_1.articles IS NULL
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE tst_pg_add_column_with_default_1.articles ALTER COLUMN id SET DEFAULT null
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE tst_pg_add_column_with_default_0.articles ALTER COLUMN id SET DEFAULT 4
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ CREATE TABLE tst_pg_create_table_5.articles (
"id" SERIAL,
"title" TEXT
)
COMMENT ON TABLE tst_pg_create_table_5.articles IS 'This is a table without primary key'
CREATE TABLE tst_pg_create_table_5.articles_without_id (
"title" TEXT
)
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![AMIGO Logo](docs/static/img/logo.svg)](https://amigo.alexisvis.co)

[![Go Report Card](https://goreportcard.com/badge/github.com/alexisvisco/amigo)](https://goreportcard.com/report/github.com/alexisvisco/amigo)
[![GoDoc](https://pkg.go.dev/badge/alexisvisco/mig)](https://pkg.go.dev/alexisvisco/mig)
[![GoDoc](https://pkg.go.dev/badge/alexisvisco/amigo)](https://pkg.go.dev/alexisvisco/mig)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![GitHub release](https://img.shields.io/github/v/release/alexisvisco/amigo.svg)](https://github.com/alexisvisco/amigo/releases)
[![Tests](https://github.com/alexisvisco/amigo/actions/workflows/tests.yml/badge.svg)](https://github.com/alexisvisco/amigo/actions/workflows/tests.yml)
Expand Down

0 comments on commit f75abca

Please sign in to comment.