Documentation
¶
Overview ¶
Пакет graph строит граф зависимостей миграций и выполняет топологическую сортировку. Естественный порядок миграций — лексикографический по Version, объявления `depends-on` переопределяют его. При наличии цикла или висячей зависимости возвращаются типизированные ошибки ErrCycle и ErrDangling.
Index ¶
- type ErrCycle
- type ErrDangling
- func Build(migs []*parser.Migration, applied map[string]bool) ([]*parser.Migration, *ErrDangling, error)
- func SelectDown(all []*parser.Migration, applied map[string]bool, toVersion string) ([]*parser.Migration, *ErrDangling, error)
- func SelectUp(all []*parser.Migration, applied map[string]bool, toVersion string, ...) ([]*parser.Migration, *ErrDangling, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ErrCycle ¶
type ErrCycle struct {
Versions []string
}
ErrCycle — обнаружен цикл в графе зависимостей. В поле Versions перечислены вершины цикла в направлении рёбер depends-on.
type ErrDangling ¶
ErrDangling — миграция From объявляет depends-on на Missing, которой нет среди известных графу узлов.
func Build ¶
func Build(migs []*parser.Migration, applied map[string]bool) ([]*parser.Migration, *ErrDangling, error)
Build строит и валидирует граф, возвращает миграции в топологическом порядке (Кан + тай-брейк лексикографически по Version).
applied — множество версий, уже зафиксированных в schema_migrations (может быть nil). Зависимость считается висячей, если её version нет ни в migs, ни в applied — это соответствует определению из плана.
Миграции с висячими зависимостями (и их транзитивные дети) исключаются из результата, но возвращаются вторым значением — *ErrDangling по первой заблокированной миграции (детерминированно: минимальная version среди заблокированных). err возвращается только для дубликатов и циклов; для висячих зависимостей возвращается dangling != nil и err == nil — вызывающий код может применить безопасное подмножество и потом среагировать на dangling.
func SelectDown ¶
func SelectDown(all []*parser.Migration, applied map[string]bool, toVersion string) ([]*parser.Migration, *ErrDangling, error)
SelectDown возвращает миграции для команды `down`: applied-миграции с Version > toVersion, плюс каскадно подтянутые applied-зависимые (миграции, которые depends-on хоть одну из откатываемых). Всё это — в обратном топологическом порядке (зависимый откатывается раньше зависимости). Пустой toVersion — откатить всё applied.
Каскад нужен для целостности: если миграция A объявляет depends-on B и B попадает под откат, A тоже обязана откатиться, иначе A останется применённой без своей зависимости. Это требование «каскадного отката зависимых» из раздела «Definition of Done» плана.
Миграции, помеченные applied, но отсутствующие в `all`, в каскад не попадают: у них нет DownSQL, и принимать решения за пользователя здесь нельзя. Runner логирует такие случаи отдельным WARN перед запуском.
Down НЕ использует Build(all, applied): тот фильтрует миграции с висячими depends-on (как pending, так и applied), что приводит к двум проблемам: (1) пендинг-миграция со сломанной зависимостью загрязняет результат dangling-ошибкой, не связанной с откатом; (2) applied-миграция с висячей зависимостью исключается из каскада, и её настоящие зависимости можно откатить, оставив её осиротевшей. Поэтому здесь мы строим топологический порядок только над applied-on-disk подмножеством с рёбрами между applied миграциями — edges на non-applied версии считаются удовлетворёнными извне и игнорируются. *ErrDangling всегда nil; параметр сохранён ради симметрии с SelectUp.
func SelectUp ¶
func SelectUp(all []*parser.Migration, applied map[string]bool, toVersion string, logger *slog.Logger) ([]*parser.Migration, *ErrDangling, error)
SelectUp возвращает миграции для команды `up`: pending-миграции с Version <= toVersion, дополненные транзитивными pending-зависимостями (даже если их Version > toVersion — об этом пишется WARN). Результат отсортирован топологически. Пустой toVersion означает «без верхней границы».
Если в графе есть висячие зависимости (определение — см. Build), миграции с такими зависимостями (и их транзитивные потомки) в результат не попадают, а *ErrDangling возвращается вторым значением. Вызывающий код применяет безопасное подмножество, а затем поднимает dangling выше — это поведение «применить всё вплоть до отсутствующей» из спецификации.
func (*ErrDangling) Error ¶
func (e *ErrDangling) Error() string