feat(pgsql): unique constraints on apply, matching unique index names, FK deferral

- migration writer now emits unique constraints (direct apply and live diff
  previously dropped them); idempotent via the existing DO block
- unique constraint adopts a same-named model unique index with
  ADD CONSTRAINT ... UNIQUE USING INDEX instead of building a second index
- dbml reader names unnamed unique indexes ukey_<table>_<cols> to match the
  unique constraint naming
- foreign key deferral: Constraint.Deferrable/InitiallyDeferred are *bool
  (nil = unspecified, never diffed); writers emit DEFERRABLE, DEFERRABLE
  INITIALLY DEFERRED and NOT DEFERRABLE; live reader reads condeferrable and
  condeferred; dbml reader/writer support deferrable and initially deferred
- tests and README/naming docs updated
This commit is contained in:
2026-10-08 00:07:49 +02:00
parent 20f8dd82b6
commit b4f18f088b
20 changed files with 756 additions and 36 deletions
+6 -4
View File
@@ -345,6 +345,7 @@ func (w *Writer) GenerateSchemaStatements(schema *models.Schema) ([]string, erro
TableName: table.Name,
ConstraintName: constraint.Name,
Columns: strings.Join(constraint.Columns, ", "),
UsingIndex: adoptableUniqueIndex(table, constraint),
}
stmt, err := w.executor.ExecuteCreateUniqueConstraint(data)
@@ -411,7 +412,7 @@ func (w *Writer) GenerateSchemaStatements(schema *models.Schema) ([]string, erro
TargetColumns: strings.Join(constraint.ReferencedColumns, ", "),
OnDelete: onDelete,
OnUpdate: onUpdate,
Deferrable: false,
Deferral: constraint.DeferralClause(),
}
stmt, err := w.executor.ExecuteCreateForeignKeyWithCheck(data)
@@ -1150,7 +1151,7 @@ func (w *Writer) writeIndexes(schema *models.Schema) error {
if indexName == "" {
indexType := "idx"
if index.Unique {
indexType = "uidx"
indexType = "ukey"
}
columnSuffix := strings.Join(index.Columns, "_")
indexName = fmt.Sprintf("%s_%s_%s", indexType, table.SQLName(), strings.ToLower(columnSuffix))
@@ -1236,6 +1237,7 @@ func (w *Writer) writeUniqueConstraints(schema *models.Schema) error {
TableName: table.Name,
ConstraintName: constraint.Name,
Columns: strings.Join(columnExprs, ", "),
UsingIndex: adoptableUniqueIndex(table, constraint),
})
if err != nil {
return fmt.Errorf("failed to generate unique constraint: %w", err)
@@ -1380,7 +1382,7 @@ func (w *Writer) writeForeignKeys(schema *models.Schema) error {
TargetColumns: strings.Join(targetColumns, ", "),
OnDelete: onDelete,
OnUpdate: onUpdate,
Deferrable: true,
Deferral: "DEFERRABLE",
}
sql, err := w.executor.ExecuteCreateForeignKeyWithCheck(data)
if err != nil {
@@ -1459,7 +1461,7 @@ func (w *Writer) writeForeignKeys(schema *models.Schema) error {
TargetColumns: strings.Join(targetColumns, ", "),
OnDelete: onDelete,
OnUpdate: onUpdate,
Deferrable: false,
Deferral: constraint.DeferralClause(),
}
sql, err := w.executor.ExecuteCreateForeignKeyWithCheck(data)
if err != nil {