mirror of
https://github.com/ent/ent.git
synced 2026-05-24 09:31:56 +03:00
entc/gen: ensure foreign-key constraints are unique in codegen (#3066)
This commit is contained in:
@@ -681,6 +681,9 @@ func (g *Graph) Tables() (all []*schema.Table, err error) {
|
||||
index.Annotation = entsqlIndexAnnotate(idx.Annotations)
|
||||
}
|
||||
}
|
||||
if err := ensureUniqueFKs(tables); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -733,6 +736,29 @@ func fkSymbols(e *Edge, c1, c2 *schema.Column) (string, string) {
|
||||
return s1, s2
|
||||
}
|
||||
|
||||
// ensureUniqueNames ensures constraint names are unique.
|
||||
func ensureUniqueFKs(tables map[string]*schema.Table) error {
|
||||
fks := make(map[string]*schema.Table)
|
||||
for _, t := range tables {
|
||||
for _, fk := range t.ForeignKeys {
|
||||
switch other, ok := fks[fk.Symbol]; {
|
||||
case !ok:
|
||||
fks[fk.Symbol] = t
|
||||
case ok && other.Name != t.Name:
|
||||
a, b := t.Name, other.Name
|
||||
// Keep reporting order consistent.
|
||||
if a > b {
|
||||
a, b = b, a
|
||||
}
|
||||
return fmt.Errorf("duplicate foreign-key symbol %q found in tables %q and %q", fk.Symbol, a, b)
|
||||
case ok:
|
||||
return fmt.Errorf("duplicate foreign-key symbol %q found in table %q", fk.Symbol, t.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteAction returns the referential action for DELETE operations of the given edge.
|
||||
func deleteAction(e *Edge, c *schema.Column) schema.ReferenceOption {
|
||||
action := schema.NoAction
|
||||
|
||||
@@ -344,6 +344,40 @@ func TestFKColumns(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbortDuplicateFK(t *testing.T) {
|
||||
var (
|
||||
user = &load.Schema{
|
||||
Name: "User",
|
||||
Edges: []*load.Edge{
|
||||
{Name: "pets", Type: "Pet", StorageKey: &edge.StorageKey{Symbols: []string{"owner_id"}}},
|
||||
{Name: "cars", Type: "Car", StorageKey: &edge.StorageKey{Symbols: []string{"owner_id"}}},
|
||||
},
|
||||
}
|
||||
pet = &load.Schema{
|
||||
Name: "Pet",
|
||||
Fields: []*load.Field{
|
||||
{Name: "owner_id", Info: &field.TypeInfo{Type: field.TypeInt}, Nillable: true, Optional: true},
|
||||
},
|
||||
Edges: []*load.Edge{
|
||||
{Name: "owner", Type: "User", RefName: "pets", Inverse: true, Unique: true},
|
||||
},
|
||||
}
|
||||
car = &load.Schema{
|
||||
Name: "Car",
|
||||
Fields: []*load.Field{
|
||||
{Name: "owner_id", Info: &field.TypeInfo{Type: field.TypeInt}, Nillable: true, Optional: true},
|
||||
},
|
||||
Edges: []*load.Edge{
|
||||
{Name: "owner", Type: "User", RefName: "cars", Inverse: true, Unique: true},
|
||||
},
|
||||
}
|
||||
)
|
||||
g, err := NewGraph(&Config{Package: "entc/gen", Storage: drivers[0]}, user, pet, car)
|
||||
require.NoError(t, err)
|
||||
_, err = g.Tables()
|
||||
require.EqualError(t, err, `duplicate foreign-key symbol "owner_id" found in tables "cars" and "pets"`)
|
||||
}
|
||||
|
||||
func TestEnsureCorrectFK(t *testing.T) {
|
||||
var (
|
||||
user = &load.Schema{
|
||||
|
||||
Reference in New Issue
Block a user