62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package database
|
|
|
|
import (
|
|
"log"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
type sqlColumn struct {
|
|
Name string
|
|
Statement string
|
|
ForeignKey string
|
|
}
|
|
type sqlColumns []sqlColumn
|
|
|
|
func (columns sqlColumns) hasAnyForeignKey() bool {
|
|
return slices.ContainsFunc(columns, func(column sqlColumn) bool { return column.ForeignKey != "" })
|
|
}
|
|
|
|
func (columns sqlColumns) hasForeignKey(name string) bool {
|
|
return slices.ContainsFunc(columns, func(column sqlColumn) bool { return strings.HasPrefix(column.ForeignKey, name) })
|
|
}
|
|
|
|
type sqlTable struct {
|
|
Name string
|
|
Columns sqlColumns
|
|
PrimaryKey string
|
|
}
|
|
|
|
type ByTableName []*sqlTable
|
|
|
|
func (tables ByTableName) Len() int { return len(tables) }
|
|
func (tables ByTableName) Swap(i, j int) { tables[i], tables[j] = tables[j], tables[i] }
|
|
func (tables ByTableName) Less(i, j int) bool {
|
|
// bool -> true: i before j
|
|
iHasForeignKey := tables[i].Columns.hasAnyForeignKey()
|
|
jHasForeignKey := tables[j].Columns.hasAnyForeignKey()
|
|
|
|
// If one table has no foreign keys and the other does, prioritize the one without
|
|
if !iHasForeignKey && jHasForeignKey {
|
|
return true
|
|
} else if iHasForeignKey && !jHasForeignKey {
|
|
return false
|
|
}
|
|
|
|
// If both tables have foreign keys, check dependency order
|
|
iDependsOnJ := tables[i].Columns.hasForeignKey(tables[j].Name)
|
|
jDependsOnI := tables[j].Columns.hasForeignKey(tables[i].Name)
|
|
|
|
if iDependsOnJ && jDependsOnI {
|
|
log.Fatal("circular refs in sql-tables")
|
|
}
|
|
|
|
if iDependsOnJ {
|
|
return false
|
|
} else if jDependsOnI {
|
|
return true
|
|
}
|
|
|
|
return true
|
|
}
|