more updates

This commit is contained in:
tsmethurst
2021-08-31 19:27:02 +02:00
committed by tsmethurst
parent 2786b5f887
commit 7b01304dac
18 changed files with 1368 additions and 133 deletions

272
vendor/github.com/uptrace/bun/migrate/migration.go generated vendored Normal file
View File

@@ -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
})
}

168
vendor/github.com/uptrace/bun/migrate/migrations.go generated vendored Normal file
View File

@@ -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
}

401
vendor/github.com/uptrace/bun/migrate/migrator.go generated vendored Normal file
View File

@@ -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
}