- 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
49 lines
1.5 KiB
Go
49 lines
1.5 KiB
Go
package models
|
|
|
|
// DeferralClause returns the SQL deferral clause for a foreign key constraint
|
|
// ("DEFERRABLE", "DEFERRABLE INITIALLY DEFERRED" or "NOT DEFERRABLE"), or ""
|
|
// when the model does not specify one. InitiallyDeferred without Deferrable
|
|
// implies DEFERRABLE; InitiallyDeferred=false alone specifies nothing.
|
|
func (d *Constraint) DeferralClause() string {
|
|
deferrable, initially, set := d.effectiveDeferral()
|
|
switch {
|
|
case !set:
|
|
return ""
|
|
case !deferrable:
|
|
return "NOT DEFERRABLE"
|
|
case initially != nil && *initially:
|
|
return "DEFERRABLE INITIALLY DEFERRED"
|
|
default:
|
|
return "DEFERRABLE"
|
|
}
|
|
}
|
|
|
|
// effectiveDeferral resolves the optional flags. set is false when the model says nothing
|
|
// about deferral; initially is nil when the initial mode is unspecified.
|
|
func (d *Constraint) effectiveDeferral() (deferrable bool, initially *bool, set bool) {
|
|
switch {
|
|
case d.Deferrable != nil:
|
|
return *d.Deferrable, d.InitiallyDeferred, true
|
|
case d.InitiallyDeferred != nil && *d.InitiallyDeferred:
|
|
return true, d.InitiallyDeferred, true
|
|
}
|
|
return false, nil, false
|
|
}
|
|
|
|
// DeferralMatches reports whether two constraints agree on deferral. An unspecified side
|
|
// matches anything, and the initial mode is only compared when both sides specify it.
|
|
func DeferralMatches(a, b *Constraint) bool {
|
|
da, ia, aSet := a.effectiveDeferral()
|
|
db, ib, bSet := b.effectiveDeferral()
|
|
if !aSet || !bSet {
|
|
return true
|
|
}
|
|
if da != db {
|
|
return false
|
|
}
|
|
if !da || ia == nil || ib == nil {
|
|
return true
|
|
}
|
|
return *ia == *ib
|
|
}
|