diff options
author | 2021-08-31 19:27:02 +0200 | |
---|---|---|
committer | 2021-08-31 19:27:02 +0200 | |
commit | 3d8aa7a4d2f3f3f986241da21a953fa194d25fd8 (patch) | |
tree | 395b059a4885d8dc8aec9c85f532abe4475d62d9 /vendor/github.com | |
parent | change muchos things (diff) | |
download | gotosocial-3d8aa7a4d2f3f3f986241da21a953fa194d25fd8.tar.xz |
more updates
Diffstat (limited to 'vendor/github.com')
-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 |
3 files changed, 841 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 +} |