Documentation
¶
Overview ¶
Пакет graph строит граф зависимостей миграций и выполняет топологическую сортировку. Естественный порядок миграций — лексикографический по Version, объявления `depends-on` переопределяют его. При наличии цикла или висячей зависимости возвращаются типизированные ошибки ErrCycle и ErrDangling.
Index ¶
- func SelectDownSteps(all []*parser.Migration, applied map[string]bool, appliedByIDDesc []string, ...) ([]*parser.Migration, error)
- 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 ¶
func SelectDownSteps ¶ added in v1.0.1
func SelectDownSteps(all []*parser.Migration, applied map[string]bool, appliedByIDDesc []string, n int) ([]*parser.Migration, error)
SelectDownSteps возвращает миграции для команды `down --steps N`: первые N applied-on-disk миграций из appliedByIDDesc плюс каскадно подтянутые applied-on-disk зависимые. Результат — в обратном топологическом порядке (зависимый раньше зависимости).
appliedByIDDesc — список version applied-миграций в порядке убывания id (хронологически: самая поздняя по времени применения первой). Сам граф о store ничего не знает, поэтому порядок передаётся снаружи (раннер строит его из ListApplied).
При n <= 0 возвращается nil без ошибки — валидация >0 живёт выше (CLI/lib). Версии из appliedByIDDesc, которых нет в applied-on-disk (например, applied, но файл удалён), молча пропускаются: раннер обязан проверять «висячие applied» до вызова Select.
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