@@ -16,6 +16,7 @@ import (
1616 "github.com/synnaxlabs/alamos"
1717 "github.com/synnaxlabs/x/binary"
1818 "github.com/synnaxlabs/x/errors"
19+ "github.com/synnaxlabs/x/graph"
1920 "github.com/synnaxlabs/x/kv"
2021 "go.uber.org/zap"
2122)
@@ -262,16 +263,9 @@ func MigrationDepOpt[T any](ctx context.Context) (T, bool) {
262263 return v , ok
263264}
264265
265- // ErrCyclicDependency is returned when migrations form a dependency cycle.
266- var ErrCyclicDependency = errors .New ("cyclic dependency detected in migrations" )
267-
268- // ErrMissingDependency is returned when a migration depends on a name that
269- // does not exist in the migration list and has not already been applied.
270- var ErrMissingDependency = errors .New ("missing migration dependency" )
271-
272266// topoSort filters out already-applied migrations, then produces a valid
273- // execution order using Kahn's algorithm . Dependencies that are already applied
274- // are considered satisfied and do not need to appear in the pending set.
267+ // execution order. Dependencies that are already applied are considered
268+ // satisfied and do not need to appear in the pending set.
275269func topoSort (migrations []Migration , applied map [string ]bool ) ([]Migration , error ) {
276270 byName := make (map [string ]Migration , len (migrations ))
277271 for _ , m := range migrations {
@@ -299,59 +293,28 @@ func topoSort(migrations []Migration, applied map[string]bool) ([]Migration, err
299293 return pending , nil
300294 }
301295
302- pendingSet := make (map [string ]bool , len (pending ))
303- for _ , m := range pending {
304- pendingSet [m .Name ()] = true
305- }
306-
307- inDegree := make (map [string ]int , len (pending ))
308- dependents := make (map [string ][]string , len (pending ))
296+ adj := make (map [string ][]string , len (pending ))
309297 for _ , m := range pending {
310298 name := m .Name ()
311- if _ , exists := inDegree [name ]; ! exists {
312- inDegree [name ] = 0
313- }
299+ adj [name ] = nil
314300 if dd , ok := m .(DependencyDeclarer ); ok {
315301 for _ , dep := range dd .Dependencies () {
316302 if applied [dep ] {
317303 continue
318304 }
319- if ! pendingSet [dep ] {
320- if _ , known := byName [dep ]; ! known {
321- return nil , fmt .Errorf (
322- "%w: migration %q depends on %q which does not exist" ,
323- ErrMissingDependency , name , dep ,
324- )
325- }
326- }
327- inDegree [name ]++
328- dependents [dep ] = append (dependents [dep ], name )
305+ adj [name ] = append (adj [name ], dep )
329306 }
330307 }
331308 }
332309
333- var queue []string
334- for _ , m := range pending {
335- if inDegree [m .Name ()] == 0 {
336- queue = append (queue , m .Name ())
337- }
338- }
339-
340- var sorted []Migration
341- for len (queue ) > 0 {
342- name := queue [0 ]
343- queue = queue [1 :]
344- sorted = append (sorted , byName [name ])
345- for _ , dep := range dependents [name ] {
346- inDegree [dep ]--
347- if inDegree [dep ] == 0 {
348- queue = append (queue , dep )
349- }
350- }
310+ order , err := graph .TopoSort (adj )
311+ if err != nil {
312+ return nil , err
351313 }
352314
353- if len (sorted ) != len (pending ) {
354- return nil , fmt .Errorf ("%w: not all migrations could be ordered" , ErrCyclicDependency )
315+ sorted := make ([]Migration , len (order ))
316+ for i , name := range order {
317+ sorted [i ] = byName [name ]
355318 }
356319 return sorted , nil
357320}
0 commit comments