71 lines
1.6 KiB
Go
71 lines
1.6 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
func NewMigrationGraph() MigrationGraph {
|
||
|
return MigrationGraph{Migrations: map[string]Migration{}, parentage: map[string]*Migration{}}
|
||
|
}
|
||
|
|
||
|
// Adds a migration to the graph.
|
||
|
//
|
||
|
// This also adds the migration to the parentage mappings to link it
|
||
|
// to its parent. If the migration added has no parent, then it's also
|
||
|
// set to be the root of the graph.
|
||
|
func (g *MigrationGraph) AddMigration(m Migration) {
|
||
|
if m.Requires == "" {
|
||
|
g.addRoot(m)
|
||
|
}
|
||
|
|
||
|
g.Migrations[m.Name] = m
|
||
|
g.parentage[m.Requires] = &m
|
||
|
}
|
||
|
|
||
|
// Builds the linear history of migrations.
|
||
|
func (g *MigrationGraph) GetLinearHistory() ([]Migration, error) {
|
||
|
if g.Root == nil {
|
||
|
return []Migration{}, errors.New("Cannot get linear history, the graph has no root.")
|
||
|
}
|
||
|
|
||
|
ordered := []Migration{}
|
||
|
visited := map[string]bool{}
|
||
|
unordered := []Migration{*g.Root}
|
||
|
|
||
|
for len(unordered) > 0 {
|
||
|
migration := unordered[0]
|
||
|
unordered = unordered[1:]
|
||
|
|
||
|
if _, hasVisited := visited[migration.Name]; hasVisited {
|
||
|
return []Migration{}, errors.New("Cycle detected, cannot generate linear history.")
|
||
|
}
|
||
|
|
||
|
child, hasChildren := g.parentage[migration.Name]
|
||
|
|
||
|
ordered = append(ordered, migration)
|
||
|
|
||
|
if hasChildren {
|
||
|
unordered = append(unordered, *child)
|
||
|
}
|
||
|
|
||
|
visited[migration.Name] = true
|
||
|
}
|
||
|
|
||
|
if len(ordered) != len(g.Migrations) {
|
||
|
return ordered, errors.New("Not all migrations in the graph are part of the history.")
|
||
|
}
|
||
|
|
||
|
return ordered, nil
|
||
|
}
|
||
|
|
||
|
func (g *MigrationGraph) addRoot(m Migration) error {
|
||
|
if g.Root != nil {
|
||
|
return errors.New(fmt.Sprintf("Cannot have more than one root, tried to add %#v but already knew about %#v.", m, g.Root))
|
||
|
}
|
||
|
|
||
|
g.Root = &m
|
||
|
|
||
|
return nil
|
||
|
}
|