diff options
Diffstat (limited to 'vendor')
| -rw-r--r-- | vendor/github.com/uptrace/bun/migrate/migration.go | 272 | ||||
| -rw-r--r-- | vendor/github.com/uptrace/bun/migrate/migrations.go | 168 | ||||
| -rw-r--r-- | vendor/github.com/uptrace/bun/migrate/migrator.go | 401 | ||||
| -rw-r--r-- | vendor/modules.txt | 1 | 
4 files changed, 842 insertions, 0 deletions
| diff --git a/vendor/github.com/uptrace/bun/migrate/migration.go b/vendor/github.com/uptrace/bun/migrate/migration.go new file mode 100644 index 000000000..79f13f972 --- /dev/null +++ b/vendor/github.com/uptrace/bun/migrate/migration.go @@ -0,0 +1,272 @@ +package migrate + +import ( +	"bufio" +	"bytes" +	"context" +	"fmt" +	"io/fs" +	"sort" +	"strings" +	"time" + +	"github.com/uptrace/bun" +) + +type Migration struct { +	bun.BaseModel + +	ID         int64 +	Name       string +	GroupID    int64 +	MigratedAt time.Time `bun:",notnull,nullzero,default:current_timestamp"` + +	Up   MigrationFunc `bun:"-"` +	Down MigrationFunc `bun:"-"` +} + +func (m *Migration) String() string { +	return m.Name +} + +func (m *Migration) IsApplied() bool { +	return m.ID > 0 +} + +type MigrationFunc func(ctx context.Context, db *bun.DB) error + +func NewSQLMigrationFunc(fsys fs.FS, name string) MigrationFunc { +	return func(ctx context.Context, db *bun.DB) error { +		isTx := strings.HasSuffix(name, ".tx.up.sql") || strings.HasSuffix(name, ".tx.down.sql") + +		f, err := fsys.Open(name) +		if err != nil { +			return err +		} + +		scanner := bufio.NewScanner(f) +		var queries []string + +		var query []byte +		for scanner.Scan() { +			b := scanner.Bytes() + +			const prefix = "--bun:" +			if bytes.HasPrefix(b, []byte(prefix)) { +				b = b[len(prefix):] +				if bytes.Equal(b, []byte("split")) { +					queries = append(queries, string(query)) +					query = query[:0] +					continue +				} +				return fmt.Errorf("bun: unknown directive: %q", b) +			} + +			query = append(query, b...) +			query = append(query, '\n') +		} + +		if len(query) > 0 { +			queries = append(queries, string(query)) +		} +		if err := scanner.Err(); err != nil { +			return err +		} + +		var idb bun.IConn + +		if isTx { +			tx, err := db.BeginTx(ctx, nil) +			if err != nil { +				return err +			} +			idb = tx +		} else { +			conn, err := db.Conn(ctx) +			if err != nil { +				return err +			} +			idb = conn +		} + +		for _, q := range queries { +			_, err = idb.ExecContext(ctx, q) +			if err != nil { +				return err +			} +		} + +		if tx, ok := idb.(bun.Tx); ok { +			return tx.Commit() +		} else if conn, ok := idb.(bun.Conn); ok { +			return conn.Close() +		} + +		panic("not reached") +	} +} + +const goTemplate = `package %s + +import ( +	"context" +	"fmt" + +	"github.com/uptrace/bun" +) + +func init() { +	Migrations.MustRegister(func(ctx context.Context, db *bun.DB) error { +		fmt.Print(" [up migration] ") +		return nil +	}, func(ctx context.Context, db *bun.DB) error { +		fmt.Print(" [down migration] ") +		return nil +	}) +} +` + +const sqlTemplate = `SELECT 1 + +--bun:split + +SELECT 2 +` + +//------------------------------------------------------------------------------ + +type MigrationSlice []Migration + +func (ms MigrationSlice) String() string { +	if len(ms) == 0 { +		return "empty" +	} + +	if len(ms) > 5 { +		return fmt.Sprintf("%d migrations (%s ... %s)", len(ms), ms[0].Name, ms[len(ms)-1].Name) +	} + +	var sb strings.Builder + +	for i := range ms { +		if i > 0 { +			sb.WriteString(", ") +		} +		sb.WriteString(ms[i].Name) +	} + +	return sb.String() +} + +// Applied returns applied migrations in descending order +// (the order is important and is used in Rollback). +func (ms MigrationSlice) Applied() MigrationSlice { +	var applied MigrationSlice +	for i := range ms { +		if ms[i].IsApplied() { +			applied = append(applied, ms[i]) +		} +	} +	sortDesc(applied) +	return applied +} + +// Unapplied returns unapplied migrations in ascending order +// (the order is important and is used in Migrate). +func (ms MigrationSlice) Unapplied() MigrationSlice { +	var unapplied MigrationSlice +	for i := range ms { +		if !ms[i].IsApplied() { +			unapplied = append(unapplied, ms[i]) +		} +	} +	sortAsc(unapplied) +	return unapplied +} + +// LastGroupID returns the last applied migration group id. +// The id is 0 when there are no migration groups. +func (ms MigrationSlice) LastGroupID() int64 { +	var lastGroupID int64 +	for i := range ms { +		groupID := ms[i].GroupID +		if groupID != 0 && groupID > lastGroupID { +			lastGroupID = groupID +		} +	} +	return lastGroupID +} + +// LastGroup returns the last applied migration group. +func (ms MigrationSlice) LastGroup() *MigrationGroup { +	group := &MigrationGroup{ +		ID: ms.LastGroupID(), +	} +	if group.ID == 0 { +		return group +	} +	for i := range ms { +		if ms[i].GroupID == group.ID { +			group.Migrations = append(group.Migrations, ms[i]) +		} +	} +	return group +} + +type MigrationGroup struct { +	ID         int64 +	Migrations MigrationSlice +} + +func (g *MigrationGroup) IsZero() bool { +	return g.ID == 0 && len(g.Migrations) == 0 +} + +func (g *MigrationGroup) String() string { +	if g.IsZero() { +		return "nil" +	} +	return fmt.Sprintf("group #%d (%s)", g.ID, g.Migrations) +} + +type MigrationFile struct { +	Name    string +	Path    string +	Content string +} + +//------------------------------------------------------------------------------ + +type migrationConfig struct { +	nop bool +} + +func newMigrationConfig(opts []MigrationOption) *migrationConfig { +	cfg := new(migrationConfig) +	for _, opt := range opts { +		opt(cfg) +	} +	return cfg +} + +type MigrationOption func(cfg *migrationConfig) + +func WithNopMigration() MigrationOption { +	return func(cfg *migrationConfig) { +		cfg.nop = true +	} +} + +//------------------------------------------------------------------------------ + +func sortAsc(ms MigrationSlice) { +	sort.Slice(ms, func(i, j int) bool { +		return ms[i].Name < ms[j].Name +	}) +} + +func sortDesc(ms MigrationSlice) { +	sort.Slice(ms, func(i, j int) bool { +		return ms[i].Name > ms[j].Name +	}) +} diff --git a/vendor/github.com/uptrace/bun/migrate/migrations.go b/vendor/github.com/uptrace/bun/migrate/migrations.go new file mode 100644 index 000000000..9af861048 --- /dev/null +++ b/vendor/github.com/uptrace/bun/migrate/migrations.go @@ -0,0 +1,168 @@ +package migrate + +import ( +	"errors" +	"fmt" +	"io/fs" +	"os" +	"path/filepath" +	"regexp" +	"runtime" +	"strings" +) + +type MigrationsOption func(m *Migrations) + +func WithMigrationsDirectory(directory string) MigrationsOption { +	return func(m *Migrations) { +		m.explicitDirectory = directory +	} +} + +type Migrations struct { +	ms MigrationSlice + +	explicitDirectory string +	implicitDirectory string +} + +func NewMigrations(opts ...MigrationsOption) *Migrations { +	m := new(Migrations) +	for _, opt := range opts { +		opt(m) +	} +	m.implicitDirectory = filepath.Dir(migrationFile()) +	return m +} + +func (m *Migrations) Sorted() MigrationSlice { +	migrations := make(MigrationSlice, len(m.ms)) +	copy(migrations, m.ms) +	sortAsc(migrations) +	return migrations +} + +func (m *Migrations) MustRegister(up, down MigrationFunc) { +	if err := m.Register(up, down); err != nil { +		panic(err) +	} +} + +func (m *Migrations) Register(up, down MigrationFunc) error { +	fpath := migrationFile() +	name, err := extractMigrationName(fpath) +	if err != nil { +		return err +	} + +	m.Add(Migration{ +		Name: name, +		Up:   up, +		Down: down, +	}) + +	return nil +} + +func (m *Migrations) Add(migration Migration) { +	if migration.Name == "" { +		panic("migration name is required") +	} +	m.ms = append(m.ms, migration) +} + +func (m *Migrations) DiscoverCaller() error { +	dir := filepath.Dir(migrationFile()) +	return m.Discover(os.DirFS(dir)) +} + +func (m *Migrations) Discover(fsys fs.FS) error { +	return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { +		if err != nil { +			return err +		} +		if d.IsDir() { +			return nil +		} + +		if !strings.HasSuffix(path, ".up.sql") && !strings.HasSuffix(path, ".down.sql") { +			return nil +		} + +		name, err := extractMigrationName(path) +		if err != nil { +			return err +		} + +		migration := m.getOrCreateMigration(name) +		if err != nil { +			return err +		} +		migrationFunc := NewSQLMigrationFunc(fsys, path) + +		if strings.HasSuffix(path, ".up.sql") { +			migration.Up = migrationFunc +			return nil +		} +		if strings.HasSuffix(path, ".down.sql") { +			migration.Down = migrationFunc +			return nil +		} + +		return errors.New("migrate: not reached") +	}) +} + +func (m *Migrations) getOrCreateMigration(name string) *Migration { +	for i := range m.ms { +		m := &m.ms[i] +		if m.Name == name { +			return m +		} +	} + +	m.ms = append(m.ms, Migration{Name: name}) +	return &m.ms[len(m.ms)-1] +} + +func (m *Migrations) getDirectory() string { +	if m.explicitDirectory != "" { +		return m.explicitDirectory +	} +	if m.implicitDirectory != "" { +		return m.implicitDirectory +	} +	return filepath.Dir(migrationFile()) +} + +func migrationFile() string { +	const depth = 32 +	var pcs [depth]uintptr +	n := runtime.Callers(1, pcs[:]) +	frames := runtime.CallersFrames(pcs[:n]) + +	for { +		f, ok := frames.Next() +		if !ok { +			break +		} +		if !strings.Contains(f.Function, "/bun/migrate.") { +			return f.File +		} +	} + +	return "" +} + +var fnameRE = regexp.MustCompile(`^(\d{14})_[0-9a-z_\-]+\.`) + +func extractMigrationName(fpath string) (string, error) { +	fname := filepath.Base(fpath) + +	matches := fnameRE.FindStringSubmatch(fname) +	if matches == nil { +		return "", fmt.Errorf("migrate: unsupported migration name format: %q", fname) +	} + +	return matches[1], nil +} diff --git a/vendor/github.com/uptrace/bun/migrate/migrator.go b/vendor/github.com/uptrace/bun/migrate/migrator.go new file mode 100644 index 000000000..f9b4a51c2 --- /dev/null +++ b/vendor/github.com/uptrace/bun/migrate/migrator.go @@ -0,0 +1,401 @@ +package migrate + +import ( +	"context" +	"errors" +	"fmt" +	"io/ioutil" +	"log" +	"path/filepath" +	"regexp" +	"time" + +	"github.com/uptrace/bun" +) + +type MigratorOption func(m *Migrator) + +func WithTableName(table string) MigratorOption { +	return func(m *Migrator) { +		m.table = table +	} +} + +func WithLocksTableName(table string) MigratorOption { +	return func(m *Migrator) { +		m.locksTable = table +	} +} + +type Migrator struct { +	db         *bun.DB +	migrations *Migrations + +	ms MigrationSlice + +	table      string +	locksTable string +} + +func NewMigrator(db *bun.DB, migrations *Migrations, opts ...MigratorOption) *Migrator { +	m := &Migrator{ +		db:         db, +		migrations: migrations, + +		ms: migrations.ms, + +		table:      "bun_migrations", +		locksTable: "bun_migration_locks", +	} +	for _, opt := range opts { +		opt(m) +	} +	return m +} + +func (m *Migrator) DB() *bun.DB { +	return m.db +} + +// MigrationsWithStatus returns migrations with status in ascending order. +func (m *Migrator) MigrationsWithStatus(ctx context.Context) (MigrationSlice, error) { +	sorted := m.migrations.Sorted() + +	applied, err := m.selectAppliedMigrations(ctx) +	if err != nil { +		return nil, err +	} + +	appliedMap := migrationMap(applied) +	for i := range sorted { +		m1 := &sorted[i] +		if m2, ok := appliedMap[m1.Name]; ok { +			m1.ID = m2.ID +			m1.GroupID = m2.GroupID +			m1.MigratedAt = m2.MigratedAt +		} +	} + +	return sorted, nil +} + +func (m *Migrator) Init(ctx context.Context) error { +	if _, err := m.db.NewCreateTable(). +		Model((*Migration)(nil)). +		ModelTableExpr(m.table). +		IfNotExists(). +		Exec(ctx); err != nil { +		return err +	} +	if _, err := m.db.NewCreateTable(). +		Model((*migrationLock)(nil)). +		ModelTableExpr(m.locksTable). +		IfNotExists(). +		Exec(ctx); err != nil { +		return err +	} +	return nil +} + +func (m *Migrator) Reset(ctx context.Context) error { +	if _, err := m.db.NewDropTable(). +		Model((*Migration)(nil)). +		ModelTableExpr(m.table). +		IfExists(). +		Exec(ctx); err != nil { +		return err +	} +	if _, err := m.db.NewDropTable(). +		Model((*migrationLock)(nil)). +		ModelTableExpr(m.locksTable). +		IfExists(). +		Exec(ctx); err != nil { +		return err +	} +	return m.Init(ctx) +} + +func (m *Migrator) Migrate(ctx context.Context, opts ...MigrationOption) (*MigrationGroup, error) { +	cfg := newMigrationConfig(opts) + +	if err := m.validate(); err != nil { +		return nil, err +	} + +	if err := m.Lock(ctx); err != nil { +		return nil, err +	} +	defer m.Unlock(ctx) //nolint:errcheck + +	migrations, err := m.MigrationsWithStatus(ctx) +	if err != nil { +		return nil, err +	} + +	group := &MigrationGroup{ +		Migrations: migrations.Unapplied(), +	} +	if len(group.Migrations) == 0 { +		return group, nil +	} +	group.ID = migrations.LastGroupID() + 1 + +	for i := range group.Migrations { +		migration := &group.Migrations[i] +		migration.GroupID = group.ID + +		if !cfg.nop && migration.Up != nil { +			if err := migration.Up(ctx, m.db); err != nil { +				return nil, err +			} +		} + +		if err := m.MarkApplied(ctx, migration); err != nil { +			return nil, err +		} +	} + +	return group, nil +} + +func (m *Migrator) Rollback(ctx context.Context, opts ...MigrationOption) (*MigrationGroup, error) { +	cfg := newMigrationConfig(opts) + +	if err := m.validate(); err != nil { +		return nil, err +	} + +	if err := m.Lock(ctx); err != nil { +		return nil, err +	} +	defer m.Unlock(ctx) //nolint:errcheck + +	migrations, err := m.MigrationsWithStatus(ctx) +	if err != nil { +		return nil, err +	} + +	lastGroup := migrations.LastGroup() + +	for i := len(lastGroup.Migrations) - 1; i >= 0; i-- { +		migration := &lastGroup.Migrations[i] + +		if !cfg.nop && migration.Down != nil { +			if err := migration.Down(ctx, m.db); err != nil { +				return nil, err +			} +		} + +		if err := m.MarkUnapplied(ctx, migration); err != nil { +			return nil, err +		} +	} + +	return lastGroup, nil +} + +type MigrationStatus struct { +	Migrations    MigrationSlice +	NewMigrations MigrationSlice +	LastGroup     *MigrationGroup +} + +func (m *Migrator) Status(ctx context.Context) (*MigrationStatus, error) { +	log.Printf( +		"DEPRECATED: bun: replace Status(ctx) with " + +			"MigrationsWithStatus(ctx)") + +	migrations, err := m.MigrationsWithStatus(ctx) +	if err != nil { +		return nil, err +	} +	return &MigrationStatus{ +		Migrations:    migrations, +		NewMigrations: migrations.Unapplied(), +		LastGroup:     migrations.LastGroup(), +	}, nil +} + +func (m *Migrator) MarkCompleted(ctx context.Context) (*MigrationGroup, error) { +	log.Printf( +		"DEPRECATED: bun: replace MarkCompleted(ctx) with " + +			"Migrate(ctx, migrate.WithNopMigration())") + +	return m.Migrate(ctx, WithNopMigration()) +} + +type goMigrationConfig struct { +	packageName string +} + +type GoMigrationOption func(cfg *goMigrationConfig) + +func WithPackageName(name string) GoMigrationOption { +	return func(cfg *goMigrationConfig) { +		cfg.packageName = name +	} +} + +// CreateGoMigration creates a Go migration file. +func (m *Migrator) CreateGoMigration( +	ctx context.Context, name string, opts ...GoMigrationOption, +) (*MigrationFile, error) { +	cfg := &goMigrationConfig{ +		packageName: "migrations", +	} +	for _, opt := range opts { +		opt(cfg) +	} + +	name, err := m.genMigrationName(name) +	if err != nil { +		return nil, err +	} + +	fname := name + ".go" +	fpath := filepath.Join(m.migrations.getDirectory(), fname) +	content := fmt.Sprintf(goTemplate, cfg.packageName) + +	if err := ioutil.WriteFile(fpath, []byte(content), 0o644); err != nil { +		return nil, err +	} + +	mf := &MigrationFile{ +		Name:    fname, +		Path:    fpath, +		Content: content, +	} +	return mf, nil +} + +// CreateSQLMigrations creates an up and down SQL migration files. +func (m *Migrator) CreateSQLMigrations(ctx context.Context, name string) ([]*MigrationFile, error) { +	name, err := m.genMigrationName(name) +	if err != nil { +		return nil, err +	} + +	up, err := m.createSQL(ctx, name+".up.sql") +	if err != nil { +		return nil, err +	} + +	down, err := m.createSQL(ctx, name+".down.sql") +	if err != nil { +		return nil, err +	} + +	return []*MigrationFile{up, down}, nil +} + +func (m *Migrator) createSQL(ctx context.Context, fname string) (*MigrationFile, error) { +	fpath := filepath.Join(m.migrations.getDirectory(), fname) + +	if err := ioutil.WriteFile(fpath, []byte(sqlTemplate), 0o644); err != nil { +		return nil, err +	} + +	mf := &MigrationFile{ +		Name:    fname, +		Path:    fpath, +		Content: goTemplate, +	} +	return mf, nil +} + +var nameRE = regexp.MustCompile(`^[0-9a-z_\-]+$`) + +func (m *Migrator) genMigrationName(name string) (string, error) { +	const timeFormat = "20060102150405" + +	if name == "" { +		return "", errors.New("migrate: migration name can't be empty") +	} +	if !nameRE.MatchString(name) { +		return "", fmt.Errorf("migrate: invalid migration name: %q", name) +	} + +	version := time.Now().UTC().Format(timeFormat) +	return fmt.Sprintf("%s_%s", version, name), nil +} + +// MarkApplied marks the migration as applied (applied). +func (m *Migrator) MarkApplied(ctx context.Context, migration *Migration) error { +	_, err := m.db.NewInsert().Model(migration). +		ModelTableExpr(m.table). +		Exec(ctx) +	return err +} + +// MarkUnapplied marks the migration as unapplied (new). +func (m *Migrator) MarkUnapplied(ctx context.Context, migration *Migration) error { +	_, err := m.db.NewDelete(). +		Model(migration). +		ModelTableExpr(m.table). +		Where("id = ?", migration.ID). +		Exec(ctx) +	return err +} + +// selectAppliedMigrations selects applied (applied) migrations in descending order. +func (m *Migrator) selectAppliedMigrations(ctx context.Context) (MigrationSlice, error) { +	var ms MigrationSlice +	if err := m.db.NewSelect(). +		ColumnExpr("*"). +		Model(&ms). +		ModelTableExpr(m.table). +		Scan(ctx); err != nil { +		return nil, err +	} +	return ms, nil +} + +func (m *Migrator) formattedTableName(db *bun.DB) string { +	return db.Formatter().FormatQuery(m.table) +} + +func (m *Migrator) validate() error { +	if len(m.ms) == 0 { +		return errors.New("migrate: there are no any migrations") +	} +	return nil +} + +//------------------------------------------------------------------------------ + +type migrationLock struct { +	ID        int64 +	TableName string `bun:",unique"` +} + +func (m *Migrator) Lock(ctx context.Context) error { +	lock := &migrationLock{ +		TableName: m.formattedTableName(m.db), +	} +	if _, err := m.db.NewInsert(). +		Model(lock). +		ModelTableExpr(m.locksTable). +		Exec(ctx); err != nil { +		return fmt.Errorf("migrate: migrations table is already locked (%w)", err) +	} +	return nil +} + +func (m *Migrator) Unlock(ctx context.Context) error { +	tableName := m.formattedTableName(m.db) +	_, err := m.db.NewDelete(). +		Model((*migrationLock)(nil)). +		ModelTableExpr(m.locksTable). +		Where("? = ?", bun.Ident("table_name"), tableName). +		Exec(ctx) +	return err +} + +func migrationMap(ms MigrationSlice) map[string]*Migration { +	mp := make(map[string]*Migration) +	for i := range ms { +		m := &ms[i] +		mp[m.Name] = m +	} +	return mp +} diff --git a/vendor/modules.txt b/vendor/modules.txt index d98ddb2cf..f8bdb32e2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -404,6 +404,7 @@ github.com/uptrace/bun/extra/bunjson  github.com/uptrace/bun/internal  github.com/uptrace/bun/internal/parser  github.com/uptrace/bun/internal/tagparser +github.com/uptrace/bun/migrate  github.com/uptrace/bun/schema  # github.com/uptrace/bun/dialect/pgdialect v0.4.3  ## explicit | 
