Skip to content

Commit cb22fc2

Browse files
author
Miguel Molina
authored
Merge pull request #173 from erizocosmico/fix/no-circular-deps
allow circular dependencies in the schema migration to some extent
2 parents ffb0288 + edfdbb0 commit cb22fc2

File tree

2 files changed

+75
-30
lines changed

2 files changed

+75
-30
lines changed

generator/migration.go

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,18 @@ type TableSchema struct {
8989
Columns []*ColumnSchema
9090
}
9191

92-
func (s *TableSchema) relationships() []string {
92+
type relationship struct {
93+
name string
94+
inverse bool
95+
}
96+
97+
func (s *TableSchema) relationships() []relationship {
9398
var rels = make(map[string]struct{})
94-
var result []string
99+
var result []relationship
95100
for _, c := range s.Columns {
96101
if c.Reference != nil {
97102
if _, ok := rels[c.Reference.Table]; !ok {
98-
result = append(result, c.Reference.Table)
103+
result = append(result, relationship{c.Reference.Table, c.Reference.inverse})
99104
rels[c.Reference.Table] = struct{}{}
100105
}
101106
}
@@ -228,7 +233,8 @@ type Reference struct {
228233
// Table is the referenced table.
229234
Table string
230235
// Column is the referenced column.
231-
Column string
236+
Column string
237+
inverse bool
232238
}
233239

234240
func (r *Reference) Equals(r2 *Reference) bool {
@@ -275,7 +281,15 @@ func (cs ChangeSet) sorted(dropIndex, createIndex map[string]*TableSchema) (Chan
275281
createTables[c.Name] = c
276282
if rels := createIndex[c.Name].relationships(); len(rels) > 0 {
277283
for _, r := range rels {
278-
createGraph.dependsOn(r, c.Name)
284+
if r.name == c.Name {
285+
continue
286+
}
287+
288+
if r.inverse {
289+
createGraph.dependsOn(c.Name, r.name)
290+
} else {
291+
createGraph.dependsOn(r.name, c.Name)
292+
}
279293
}
280294
} else {
281295
createGraph.add(c.Name)
@@ -284,7 +298,15 @@ func (cs ChangeSet) sorted(dropIndex, createIndex map[string]*TableSchema) (Chan
284298
dropTables[c.Name] = c
285299
if rels := dropIndex[c.Name].relationships(); len(rels) > 0 {
286300
for _, r := range rels {
287-
dropGraph.dependsOn(r, c.Name)
301+
if r.name == c.Name {
302+
continue
303+
}
304+
305+
if r.inverse {
306+
dropGraph.dependsOn(c.Name, r.name)
307+
} else {
308+
dropGraph.dependsOn(r.name, c.Name)
309+
}
288310
}
289311
} else {
290312
dropGraph.add(c.Name)
@@ -870,9 +892,9 @@ func (t *packageTransformer) transformRef(f *Field) (*Reference, error) {
870892
return nil, fmt.Errorf("kallax: unable to find table for type %s in field %s of model %s. Is the model type part of the generation input?", typ, f.Name, f.Model.Name)
871893
}
872894

873-
return &Reference{Table: table, Column: t.pkIndex[table].ColumnName()}, nil
895+
return &Reference{Table: table, Column: t.pkIndex[table].ColumnName(), inverse: true}, nil
874896
} else if f.Kind == Relationship {
875-
return &Reference{Table: f.Model.Table, Column: f.Model.ID.ColumnName()}, nil
897+
return &Reference{Table: f.Model.Table, Column: f.Model.ID.ColumnName(), inverse: false}, nil
876898
}
877899

878900
return nil, nil

generator/migration_test.go

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ func TestNewMigration(t *testing.T) {
2121
require.Equal(t, migration.Lock, new)
2222
}
2323

24+
func TestNewMigration_SelfRef(t *testing.T) {
25+
old := mkSchema()
26+
new := mkSchema(mkTable(
27+
"selfref",
28+
mkCol("id", SerialColumn, true, false, nil),
29+
mkCol("parent_id", BigIntColumn, false, false, mkRef("selfref", "id", true)),
30+
mkCol("child_id", BigIntColumn, false, false, mkRef("selfref", "id", false)),
31+
))
32+
33+
_, err := NewMigration(old, new)
34+
require.NoError(t, err)
35+
}
36+
2437
var table1 = mkTable(
2538
"table",
2639
mkCol("id", SerialColumn, true, true, nil),
@@ -29,7 +42,7 @@ var table1 = mkTable(
2942

3043
var table2 = mkTable(
3144
"table2",
32-
mkCol("table_id", SerialColumn, false, true, mkRef("table", "id")),
45+
mkCol("table_id", SerialColumn, false, true, mkRef("table", "id", false)),
3346
mkCol("num", NumericColumn(20), false, false, nil),
3447
)
3548

@@ -198,31 +211,31 @@ func TestColumnSchemaDiff(t *testing.T) {
198211
{
199212
"ref added",
200213
mkCol("foo", TextColumn, false, false, nil),
201-
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar")),
214+
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar", false)),
202215
true,
203216
},
204217
{
205218
"ref removed",
206-
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar")),
219+
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar", false)),
207220
mkCol("foo", TextColumn, false, false, nil),
208221
true,
209222
},
210223
{
211224
"ref table changed",
212-
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar")),
213-
mkCol("foo", TextColumn, false, false, mkRef("bar", "bar")),
225+
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar", false)),
226+
mkCol("foo", TextColumn, false, false, mkRef("bar", "bar", false)),
214227
true,
215228
},
216229
{
217230
"ref col changed",
218-
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar")),
219-
mkCol("foo", TextColumn, false, false, mkRef("foo", "foo")),
231+
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar", false)),
232+
mkCol("foo", TextColumn, false, false, mkRef("foo", "foo", false)),
220233
true,
221234
},
222235
{
223236
"ref col unchanged",
224-
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar")),
225-
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar")),
237+
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar", false)),
238+
mkCol("foo", TextColumn, false, false, mkRef("foo", "bar", false)),
226239
false,
227240
},
228241
{
@@ -368,25 +381,25 @@ func TestColumnSchemaEquals(t *testing.T) {
368381
{
369382
"one of the references is nil",
370383
mkCol("foo", TextColumn, false, false, nil),
371-
mkCol("foo", TextColumn, false, false, mkRef("a", "b")),
384+
mkCol("foo", TextColumn, false, false, mkRef("a", "b", false)),
372385
false,
373386
},
374387
{
375388
"reference table does not match",
376-
mkCol("foo", TextColumn, false, false, mkRef("a", "b")),
377-
mkCol("foo", TextColumn, false, false, mkRef("b", "b")),
389+
mkCol("foo", TextColumn, false, false, mkRef("a", "b", false)),
390+
mkCol("foo", TextColumn, false, false, mkRef("b", "b", false)),
378391
false,
379392
},
380393
{
381394
"reference column does not match",
382-
mkCol("foo", TextColumn, false, false, mkRef("a", "b")),
383-
mkCol("foo", TextColumn, false, false, mkRef("a", "a")),
395+
mkCol("foo", TextColumn, false, false, mkRef("a", "b", false)),
396+
mkCol("foo", TextColumn, false, false, mkRef("a", "a", false)),
384397
false,
385398
},
386399
{
387400
"equal with reference",
388-
mkCol("foo", TextColumn, false, false, mkRef("a", "b")),
389-
mkCol("foo", TextColumn, false, false, mkRef("a", "b")),
401+
mkCol("foo", TextColumn, false, false, mkRef("a", "b", false)),
402+
mkCol("foo", TextColumn, false, false, mkRef("a", "b", false)),
390403
true,
391404
},
392405
{
@@ -407,7 +420,7 @@ func TestChangeSetSorted(t *testing.T) {
407420
mkTable("table2"),
408421
mkTable(
409422
"table1",
410-
mkCol("foo", SerialColumn, false, false, mkRef("table2", "bar")),
423+
mkCol("foo", SerialColumn, false, false, mkRef("table2", "bar", false)),
411424
),
412425
mkTable("table3"),
413426
)
@@ -416,7 +429,7 @@ func TestChangeSetSorted(t *testing.T) {
416429
mkTable("table4"),
417430
mkTable(
418431
"table5",
419-
mkCol("foo", SerialColumn, false, false, mkRef("table4", "bar")),
432+
mkCol("foo", SerialColumn, false, false, mkRef("table4", "bar", false)),
420433
),
421434
)
422435
cs := SchemaDiff(old, new)
@@ -486,6 +499,16 @@ func (s *PackageTransformerSuite) SetupTest() {
486499
s.Require().NoError(err)
487500
}
488501

502+
func (s *PackageTransformerSuite) TestMigrationCircularDep() {
503+
require := s.Require()
504+
schema, err := s.t.transform(s.pkg)
505+
require.NoError(err)
506+
require.NotNil(schema)
507+
508+
_, err = NewMigration(mkSchema(), schema)
509+
require.NoError(err)
510+
}
511+
489512
func (s *PackageTransformerSuite) TestTransform() {
490513
require := s.Require()
491514
schema, err := s.t.transform(s.pkg)
@@ -498,14 +521,14 @@ func (s *PackageTransformerSuite) TestTransform() {
498521
mkCol("id", SerialColumn, true, false, nil),
499522
mkCol("color", ColumnType("char(6)"), false, false, nil),
500523
mkCol("background", TextColumn, false, false, nil),
501-
mkCol("user_id", UUIDColumn, false, false, mkRef("users", "id")),
524+
mkCol("user_id", UUIDColumn, false, false, mkRef("users", "id", true)),
502525
mkCol("spouse", UUIDColumn, false, false, nil),
503526
),
504527
mkTable(
505528
"metadata",
506529
mkCol("id", SerialColumn, true, false, nil),
507530
mkCol("metadata", JSONBColumn, false, false, nil),
508-
mkCol("profile_id", BigIntColumn, false, false, mkRef("profiles", "id")),
531+
mkCol("profile_id", BigIntColumn, false, false, mkRef("profiles", "id", false)),
509532
),
510533
mkTable(
511534
"users",
@@ -589,6 +612,6 @@ func mkCol(name string, typ ColumnType, pk, notNull bool, ref *Reference) *Colum
589612
return &ColumnSchema{name, typ, pk, ref, notNull}
590613
}
591614

592-
func mkRef(table, col string) *Reference {
593-
return &Reference{table, col}
615+
func mkRef(table, col string, inverse bool) *Reference {
616+
return &Reference{table, col, inverse}
594617
}

0 commit comments

Comments
 (0)