feat: mark generated and identity columns across writers and DBML
- bun: scanonly+generated for GENERATED columns; scanonly+identity for ALWAYS identity (PK gets identity only) - gorm: <-:false+generated / identity, same primary key rule - dbml: write GENERATED/IDENTITY column notes and read them back into the model - pgsql: emit generation/identity clauses in migration create-table and add-column, no DEFAULT - readmes updated
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package pgsql
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
||||
"git.warky.dev/wdevs/relspecgo/pkg/writers"
|
||||
)
|
||||
|
||||
func generationTestTable(withColumns bool) *models.Table {
|
||||
table := models.InitTable("people", "public")
|
||||
|
||||
first := models.InitColumn("first", "people", "public")
|
||||
first.Type = "text"
|
||||
first.Sequence = 1
|
||||
table.Columns["first"] = first
|
||||
|
||||
if !withColumns {
|
||||
return table
|
||||
}
|
||||
|
||||
full := models.InitColumn("full_name", "people", "public")
|
||||
full.Type = "text"
|
||||
full.Sequence = 2
|
||||
full.Generated = true
|
||||
full.GenerationExpression = "first || ' ' || last"
|
||||
full.Default = "ignored"
|
||||
table.Columns["full_name"] = full
|
||||
|
||||
ident := models.InitColumn("seq", "people", "public")
|
||||
ident.Type = "bigint"
|
||||
ident.Sequence = 3
|
||||
ident.NotNull = true
|
||||
ident.Identity = true
|
||||
ident.IdentityGeneration = "ALWAYS"
|
||||
table.Columns["seq"] = ident
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
func generationTestDB(table *models.Table) *models.Database {
|
||||
db := models.InitDatabase("testdb")
|
||||
schema := models.InitSchema("public")
|
||||
schema.Tables = append(schema.Tables, table)
|
||||
db.Schemas = append(db.Schemas, schema)
|
||||
return db
|
||||
}
|
||||
|
||||
func TestGeneratedColumns_MigrationCreateAndAddColumn(t *testing.T) {
|
||||
want := []string{
|
||||
"GENERATED ALWAYS AS (first || ' ' || last) STORED",
|
||||
"GENERATED ALWAYS AS IDENTITY",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
current *models.Database
|
||||
}{
|
||||
{"new table", models.InitDatabase("testdb")},
|
||||
{"new columns on existing table", generationTestDB(generationTestTable(false))},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := NewWriter(&writers.WriterOptions{})
|
||||
stmts, err := w.diffStatements(generationTestDB(generationTestTable(true)), tt.current)
|
||||
if err != nil {
|
||||
t.Fatalf("diffStatements failed: %v", err)
|
||||
}
|
||||
out := diffJoin(stmts)
|
||||
for _, s := range want {
|
||||
if !strings.Contains(out, s) {
|
||||
t.Errorf("missing %q:\n%s", s, out)
|
||||
}
|
||||
}
|
||||
if strings.Contains(out, "DEFAULT ignored") || strings.Contains(out, "DEFAULT 'ignored'") {
|
||||
t.Errorf("generated column must not carry a DEFAULT:\n%s", out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratedColumns_FullDDL(t *testing.T) {
|
||||
w := NewWriter(&writers.WriterOptions{})
|
||||
stmts, err := w.GenerateDatabaseStatements(generationTestDB(generationTestTable(true)))
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateDatabaseStatements failed: %v", err)
|
||||
}
|
||||
out := diffJoin(stmts)
|
||||
for _, s := range []string{
|
||||
"full_name text GENERATED ALWAYS AS (first || ' ' || last) STORED",
|
||||
"seq bigint GENERATED ALWAYS AS IDENTITY NOT NULL",
|
||||
} {
|
||||
if !strings.Contains(out, s) {
|
||||
t.Errorf("missing %q:\n%s", s, out)
|
||||
}
|
||||
}
|
||||
if strings.Contains(out, "DEFAULT 'ignored'") {
|
||||
t.Errorf("generated column must not carry a DEFAULT:\n%s", out)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user