Files
upstream-ory-kratos/oryx/popx/migration_info.go
upstream-mirror c60cc7ca75
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:19:12 +05:00

131 lines
3.4 KiB
Go

// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package popx
import (
"sort"
"strings"
"github.com/pkg/errors"
"github.com/ory/pop/v6"
)
// Migration handles the data for a given database migration
type Migration struct {
// Path to the migration (./migrations/123_create_widgets.up.sql)
Path string
// Version of the migration (123)
Version string
// Name of the migration (create_widgets)
Name string
// Direction of the migration (up|down)
Direction string
// Type of migration (sql|go)
Type string
// DB type (all|postgres|mysql...)
DBType string
// Runner function to run/execute the migration. Will be wrapped in a
// database transaction. Mutually exclusive with RunnerNoTx
Runner func(Migration, *pop.Connection) error
// Content is the raw content of the migration file
Content string
// Autocommit indicates whether the migration should be run in autocommit mode
Autocommit bool
}
func (m Migration) Valid() error {
if m.Runner == nil {
return errors.Errorf("no runner defined for %s", m.Path)
}
return nil
}
// Migrations is a collection of Migration
type Migrations []Migration
func (mfs Migrations) Len() int { return len(mfs) }
func (mfs Migrations) Less(i, j int) bool { return compareMigration(mfs[i], mfs[j]) < 0 }
func (mfs Migrations) Swap(i, j int) { mfs[i], mfs[j] = mfs[j], mfs[i] }
func compareMigration(a, b Migration) int {
if a.Version != b.Version {
return strings.Compare(a.Version, b.Version)
}
// Force "all" to be greater.
if a.DBType == "all" && b.DBType != "all" {
return 1
} else if a.DBType != "all" && b.DBType == "all" {
return -1
}
return strings.Compare(a.DBType, b.DBType)
}
// migrationRank ranks a migration's DBType for the given dialect and its ordered
// fallbacks. Higher numbers indicate a better match:
//
// -1 not applicable
// 0 "all" (generic, dialect-independent)
// 1..n a fallback dialect (earlier fallbacks rank higher)
// n+1 the exact dialect
//
// This lets a migration box prefer a dialect-specific override, then a fallback
// dialect (e.g. postgres for a postgres-wire-compatible database), then the
// generic file.
func migrationRank(dbType, dialect string, fallbacks []string) int {
switch dbType {
case dialect:
return len(fallbacks) + 1
case "all":
return 0
}
for i, fb := range fallbacks {
if dbType == fb {
return len(fallbacks) - i
}
}
return -1
}
func (mfs Migrations) sortAndFilter(dialect string, fallbacks ...string) Migrations {
byVersion := make(map[string]Migration, len(mfs))
for _, migration := range mfs {
rank := migrationRank(migration.DBType, dialect, fallbacks)
if rank < 0 {
// Not applicable to this dialect.
continue
}
if previousMigration, ok := byVersion[migration.Version]; ok {
if rank < migrationRank(previousMigration.DBType, dialect, fallbacks) {
// Previous migration is a better match, skip this one.
continue
}
}
byVersion[migration.Version] = migration
}
filtered := make(Migrations, 0, len(byVersion))
for k := range byVersion {
filtered = append(filtered, byVersion[k])
}
sort.Sort(filtered)
return filtered
}
func (mfs Migrations) find(version, dialect string, fallbacks ...string) *Migration {
var candidate *Migration
bestRank := -1
for i := range mfs {
if mfs[i].Version != version {
continue
}
if rank := migrationRank(mfs[i].DBType, dialect, fallbacks); rank > bestRank {
bestRank = rank
candidate = &mfs[i]
}
}
return candidate
}