uni/WEB43-diary/internal/database/column.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
}