diff --git a/cmd/bundb/main.go b/cmd/bundb/main.go new file mode 100644 index 000000000..07337ce0f --- /dev/null +++ b/cmd/bundb/main.go @@ -0,0 +1,32 @@ +/* +TODO: + +- Add a mechanism to detect potentially duplicate migration files. That is, +once we've collected migrations in a bytes.Buffer, check if 'migrations/' package +has another migration files that: + 1. is identical in content + 2. belongs to the migration that has not been applied yet + +If we find such migration, prompt the user for confirmation, unless -force flag is set. +Ideally, we should be able to ignore "transactional" for this purpose, +i.e. same_thing.up.tx.sql should overwrite same_thing.up.sql. + +- Store configured options to env variables? E.g. after 'bundb init --create-directory=db-migrations/' +set BUNDB_MIGRATIONS=db-migrations, so that subsequent commands can be run without additional parameters. +Although... this way we are moving towards a .bundb.config or something. +*/ +package main + +import ( + "log" + "os" + + "github.com/uptrace/bun/extra/buncli" +) + +func main() { + log.SetPrefix("bundb: ") + if err := buncli.NewStandalone("bundb").Run(os.Args); err != nil { + log.Fatal(err) + } +} diff --git a/dialect/pgdialect/go.mod b/dialect/pgdialect/go.mod index 1b2412aed..682f739b3 100644 --- a/dialect/pgdialect/go.mod +++ b/dialect/pgdialect/go.mod @@ -13,11 +13,13 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect golang.org/x/sys v0.27.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/dialect/pgdialect/go.sum b/dialect/pgdialect/go.sum index 207443654..fa488033a 100644 --- a/dialect/pgdialect/go.sum +++ b/dialect/pgdialect/go.sum @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= diff --git a/driver/pgdriver/go.mod b/driver/pgdriver/go.mod index 1c836c726..1ba83f5ff 100644 --- a/driver/pgdriver/go.mod +++ b/driver/pgdriver/go.mod @@ -13,7 +13,8 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect - github.com/kr/text v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect @@ -21,5 +22,6 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect golang.org/x/crypto v0.29.0 // indirect golang.org/x/sys v0.27.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/driver/pgdriver/go.sum b/driver/pgdriver/go.sum index e545dc75d..9df3772e2 100644 --- a/driver/pgdriver/go.sum +++ b/driver/pgdriver/go.sum @@ -4,8 +4,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/example/migrate/go.mod b/example/migrate/go.mod index d70e7fe5d..c49cdb9a0 100644 --- a/example/migrate/go.mod +++ b/example/migrate/go.mod @@ -12,8 +12,8 @@ replace github.com/uptrace/bun/driver/sqliteshim => ../../driver/sqliteshim require ( github.com/uptrace/bun v1.2.6 - github.com/uptrace/bun/dialect/sqlitedialect v1.2.6 - github.com/uptrace/bun/driver/sqliteshim v1.2.6 + github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e github.com/uptrace/bun/extra/bundebug v1.2.6 github.com/urfave/cli/v2 v2.27.5 ) diff --git a/extra/buncli/auto.go b/extra/buncli/auto.go new file mode 100644 index 000000000..089d43431 --- /dev/null +++ b/extra/buncli/auto.go @@ -0,0 +1,54 @@ +package buncli + +import ( + "github.com/uptrace/bun/migrate" + "github.com/urfave/cli/v2" +) + +// CmdAuto creates the auto command hierarchy. +func CmdAuto(c AutoConfig) *cli.Command { + return &cli.Command{ + Name: "auto", + Usage: "Manage database schema with AutoMigrator", + Subcommands: cli.Commands{ + &cli.Command{ + Name: "create", + Usage: "Generate SQL migration files", + Flags: []cli.Flag{ + flagTx, + }, + Action: func(ctx *cli.Context) error { + return runAutoCreate(ctx, c) + }, + }, + &cli.Command{ + Name: "migrate", + Usage: "Generate SQL migrations and apply them right away", + Action: func(ctx *cli.Context) error { + return runAutoMigrate(ctx, c) + }, + }, + }, + } +} + +// AutoConfig provides configuration for commands related to auto migration. +type AutoConfig interface { + OptionsConfig + Auto() *migrate.AutoMigrator +} + +func runAutoMigrate(ctx *cli.Context, c AutoConfig) error { + _, err := c.Auto().Migrate(ctx.Context, c.GetMigrateOptions()...) + return err +} + +func runAutoCreate(ctx *cli.Context, c AutoConfig) error { + var err error + if flagTx.Get(ctx) { + _, err = c.Auto().CreateTxSQLMigrations(ctx.Context) + } else { + _, err = c.Auto().CreateSQLMigrations(ctx.Context) + } + return err +} diff --git a/extra/buncli/buncli.go b/extra/buncli/buncli.go new file mode 100644 index 000000000..c1333e3e9 --- /dev/null +++ b/extra/buncli/buncli.go @@ -0,0 +1,105 @@ +/* +TODO: + - Commands: + - init - Create migration+locks tables [--no-cmd to omit cmd/ folder] + - provide NewCommand() *cli.Command intead of the cli.App, so that buncli could be embeded in the existing CLIs + - configure logging and verbosity + - (experimental, low prio) add FromPlugin() to read config from plugin and use from cmd/bundb. +*/ +package buncli + +import ( + "context" + + "github.com/uptrace/bun" + "github.com/uptrace/bun/migrate" + "github.com/urfave/cli/v2" +) + +// bunApp is the root-level bundb app that all other commands attach to. +var bunApp = &cli.App{ + Name: "bundb", + Usage: "Database migration tool for uptrace/bun", + Suggest: true, +} + +// New creates a new CLI application for managing bun migrations. +func New(c *Config) *App { + if c.RootName != "" { + bunApp.Name = c.RootName + } + bunApp.Commands = cli.Commands{ + CmdMigrate(c), + CmdRollback(c), + CmdCreate(c), + CmdAuto(c), + CmdUnlock(c), + } + return &App{ + App: bunApp, + } +} + +// NewStandalone create a new CLI application to be distributed as a standalone binary. +// It's intended to be used in the cmb/bundb and does not require any prior setup from the user: +// the app only includes the Init command and reads all its configuration from command line. +// +// Prefer using New(*Config) in your custom entrypoint. +func NewStandalone(name string) *App { + bunApp.Name = name + bunApp.Commands = cli.Commands{ + CmdInit(), + } + + // NOTE: use `-tags experimental` to enable/disable this feature? + addCommandGroup(bunApp, "EXPERIMENTAL", pluginCommands()...) + return &App{ + App: bunApp, + } +} + +type Config struct { + RootName string + DB *bun.DB + AutoMigrator *migrate.AutoMigrator + Migrations *migrate.Migrations + MigratorOptions []migrate.MigratorOption + MigrateOptions []migrate.MigrationOption + GoMigrationOptions []migrate.GoMigrationOption +} + +// Run calls cli.App.Run and returns its error. +func Run(args []string, c *Config) error { + return New(c).Run(args) +} + +// RunContext calls cli.App.RunContext and returns its error. +func RunContext(ctx context.Context, args []string, c *Config) error { + return New(c).RunContext(ctx, args) +} + +// App is a wrapper around cli.App that extends it with bun-specific features. +type App struct { + *cli.App +} + +var _ OptionsConfig = (*Config)(nil) +var _ MigratorConfig = (*Config)(nil) +var _ AutoConfig = (*Config)(nil) + +func (c *Config) NewMigrator() *migrate.Migrator { + return migrate.NewMigrator(c.DB, c.Migrations, c.MigratorOptions...) +} + +func (c *Config) Auto() *migrate.AutoMigrator { return c.AutoMigrator } +func (c *Config) GetMigratorOptions() []migrate.MigratorOption { return c.MigratorOptions } +func (c *Config) GetMigrateOptions() []migrate.MigrationOption { return c.MigrateOptions } +func (c *Config) GetGoMigrationOptions() []migrate.GoMigrationOption { return c.GoMigrationOptions } + +// addCommandGroup groups commands into one category. +func addCommandGroup(app *cli.App, group string, commands ...*cli.Command) { + for _, cmd := range commands { + cmd.Category = group + } + app.Commands = append(app.Commands, commands...) +} \ No newline at end of file diff --git a/extra/buncli/go.mod b/extra/buncli/go.mod new file mode 100644 index 000000000..900ae1e89 --- /dev/null +++ b/extra/buncli/go.mod @@ -0,0 +1,61 @@ +module github.com/uptrace/bun/extra/buncli + +go 1.22.0 + +require ( + github.com/uptrace/bun v1.2.7-0.20241125022320-89e9d5169f8a + github.com/uptrace/bun/dialect/mssqldialect v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/dialect/mysqldialect v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/dialect/oracledialect v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/dialect/pgdialect v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/driver/pgdriver v1.2.7-0.20241126124946-928d0779110e + github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e + github.com/urfave/cli/v2 v2.27.5 + golang.org/x/mod v0.22.0 +) + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.24 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect + golang.org/x/sys v0.27.0 // indirect + mellium.im/sasl v0.3.2 // indirect + modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 // indirect + modernc.org/libc v1.61.2 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.34.1 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect +) + +replace github.com/uptrace/bun => ../.. + +// replace github.com/uptrace/bun/dialect/mssqldialect => ../../dialect/mssqldialect + +// replace github.com/uptrace/bun/dialect/mysqldialect => ../../dialect/mysqldialect + +// replace github.com/uptrace/bun/dialect/oracledialect => ../../dialect/oracledialect + +// replace github.com/uptrace/bun/dialect/pgdialect => ../../dialect/pgdialect + +// replace github.com/uptrace/bun/dialect/sqlitedialect => ../../dialect/sqlitedialect + +// replace github.com/uptrace/bun/driver/pgdriver => ../../driver/pgdriver + +// replace github.com/uptrace/bun/driver/sqliteshim => ../../driver/sqliteshim diff --git a/extra/buncli/go.sum b/extra/buncli/go.sum new file mode 100644 index 000000000..5f6d0b542 --- /dev/null +++ b/extra/buncli/go.sum @@ -0,0 +1,97 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= +github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/uptrace/bun/dialect/mssqldialect v1.2.7-0.20241126124946-928d0779110e h1:gaD0dmqaYNFtX+iPxhX9UDelJ6u6BVajSNH4Ing5Ty4= +github.com/uptrace/bun/dialect/mssqldialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:IzBp33ztsWM76cdCqJAb1iXpwKl+djYEsA5EIPh2H6M= +github.com/uptrace/bun/dialect/mysqldialect v1.2.7-0.20241126124946-928d0779110e h1:w2VE7E0DrlYd1QdHH2MGmSO3AyTfU3D5Yn8aGuSTh9c= +github.com/uptrace/bun/dialect/mysqldialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:f3OuhVaMIwb98ZH+QhFuxlDNgkxTWcy93o3bYml78qA= +github.com/uptrace/bun/dialect/oracledialect v1.2.7-0.20241126124946-928d0779110e h1:HRWeCrgT9ggMISNuvx+QeFqgstFFh27ab8FBYgvQ5pY= +github.com/uptrace/bun/dialect/oracledialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:vCYOY37smpebuKD6FCoF7oy/TxDjz/wIZJ7jRjTxYHM= +github.com/uptrace/bun/dialect/pgdialect v1.2.7-0.20241126124946-928d0779110e h1:iMJU0gy83bPL6JtoPOAroc0GdEdDLz6B6irE83ebnas= +github.com/uptrace/bun/dialect/pgdialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:hfkgRt/bb5VYxS6CDngcjxF0An0iXOeVz8TSsWJIb/I= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e h1:X2j53OxG6XgnMGWkFoyLWlZQS0hGFxNZGYXU73mUtRw= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:/jVQkA37QsTWBjGesSHubm8W1PLI5+gCzFrSX1k0Kfs= +github.com/uptrace/bun/driver/pgdriver v1.2.7-0.20241126124946-928d0779110e h1:18aMpwYKpAwFcOm7Swv8zHikkq5NTW8fFEpmnDF1gH4= +github.com/uptrace/bun/driver/pgdriver v1.2.7-0.20241126124946-928d0779110e/go.mod h1:B+uzDgcf88kUubal/g7L5VB58n1DBCugKBKA16YAM6w= +github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e h1:HsHf0+SS9q01zbV9jNIg9lf8U/hjSPQOvGXa+3WwzXg= +github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e/go.mod h1:6NKvfZH+x8b+LEt9+zvx0LFWxJf18/tt/NFzn4FxNMM= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= +golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mellium.im/sasl v0.3.2 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0= +mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY= +modernc.org/cc/v4 v4.23.1 h1:WqJoPL3x4cUufQVHkXpXX7ThFJ1C4ik80i2eXEXbhD8= +modernc.org/cc/v4 v4.23.1/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.22.3 h1:C7AW89Zw3kygesTQWBzApwIn9ldM+cb/plrTIKq41Os= +modernc.org/ccgo/v4 v4.22.3/go.mod h1:Dz7n0/UkBbH3pnYaxgi1mFSfF4REqUOZNziphZASx6k= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M= +modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 h1:IYXPPTTjjoSHvUClZIYexDiO7g+4x+XveKT4gCIAwiY= +modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.61.2 h1:dkO4DlowfClcJYsvf/RiK6fUwvzCQTmB34bJLt0CAGQ= +modernc.org/libc v1.61.2/go.mod h1:4QGjNyX3h+rn7V5oHpJY2yH0QN6frt1X+5BkXzwLPCo= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.34.1 h1:u3Yi6M0N8t9yKRDwhXcyp1eS5/ErhPTBggxWFuR6Hfk= +modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/extra/buncli/init.go b/extra/buncli/init.go new file mode 100644 index 000000000..0d1df1733 --- /dev/null +++ b/extra/buncli/init.go @@ -0,0 +1,404 @@ +package buncli + +import ( + "database/sql" + "fmt" + "os" + "path" + "strings" + + "github.com/uptrace/bun" + "github.com/uptrace/bun/dialect/mssqldialect" + "github.com/uptrace/bun/dialect/mysqldialect" + "github.com/uptrace/bun/dialect/oracledialect" + "github.com/uptrace/bun/dialect/pgdialect" + "github.com/uptrace/bun/dialect/sqlitedialect" + "github.com/uptrace/bun/driver/pgdriver" + "github.com/uptrace/bun/driver/sqliteshim" + "github.com/uptrace/bun/migrate" + "github.com/uptrace/bun/schema" + "github.com/urfave/cli/v2" + "golang.org/x/mod/modfile" +) + +// CmdInit creates init command. +func CmdInit() *cli.Command { + return &cli.Command{ + Name: "init", + Usage: "Create migration tables and default project layout", + Args: true, + Flags: []cli.Flag{ + flagDSN, + flagDriver, + flagTable, + flagLocks, + flagBinary, + flagMigrations, + flagPluginMode, + }, + Action: func(ctx *cli.Context) error { + c, err := fromCLI(ctx) + if err != nil { + return err + } + return runInit(ctx, c) + }, + } +} + +type OptionsConfig interface { + GetMigratorOptions() []migrate.MigratorOption + GetMigrateOptions() []migrate.MigrationOption + GetGoMigrationOptions() []migrate.GoMigrationOption +} + +const ( + maingo = "main.go" + defaultBin = "bun" + defaultMigrations = "migrations" +) + +var ( + supportedDrivers = []string{"postgres", "sqlserver", "mysql", "oci8", "file"} + + flagDSN = &cli.StringFlag{ + Name: "dsn", + Usage: "database connection string", + Required: true, + EnvVars: []string{"BUNDB_URI"}, + Aliases: []string{"uri"}, + } + + flagDriver = &cli.StringFlag{ + Name: "driver", + Usage: strings.Join(supportedDrivers, ", "), + } + + flagTable = &cli.StringFlag{ + Name: "table", + Usage: "override migrations table name", + Value: migrate.DefaultTable, + } + + flagLocks = &cli.StringFlag{ + Name: "locks", + Usage: "override locks table name", + Value: migrate.DefaultLocksTable, + } + + flagBinary = &cli.StringFlag{ + Name: "b", + Aliases: []string{"binary"}, + Usage: "override cmd/ `ENTRYPOINT` name", + Value: defaultBin, + } + + flagMigrations = &cli.StringFlag{ + Name: "m", + Aliases: []string{"migrations-directory"}, + Usage: "override migrations `DIR`", + Value: defaultMigrations, + } + + flagPluginMode = &cli.BoolFlag{ + Name: "P", + Aliases: []string{"plugin"}, + Usage: "create a 'main' package to be used as a plugin", + DisableDefaultText: true, + } +) + +func runInit(ctx *cli.Context, c MigratorConfig) error { + m := c.NewMigrator() + if err := m.Init(ctx.Context); err != nil { + return err + } + + loc := ctx.Args().Get(0) + binName := flagBinary.Get(ctx) + migrationsDir := flagMigrations.Get(ctx) + migratorOpts := stringNonDefaultMigratorOptions(ctx) + + var b interface{ Bootstrap() error } + switch { + default: + b = &normalMode{Loc: loc, Binary: binName, Migrations: migrationsDir, MigratorOptions: migratorOpts} + case flagPluginMode.Get(ctx): + b = &pluginMode{Loc: loc, Migrations: migrationsDir, MigratorOptions: migratorOpts} + } + + return b.Bootstrap() +} + +// fromCLI creates minimal Config from command line arguments. +// It is inteded to be used exclusively by Init command, as it creates +// the default project structure and the user has no other way of configuring buncli. +// +// DB and Migrations are the only valid fields in the created config, other objects are nil. +func fromCLI(ctx *cli.Context) (*Config, error) { + db, err := newDB(ctx) + if err != nil { + return nil, err + } + return &Config{ + DB: db, + MigratorOptions: addNonDefaultMigratorOptions(ctx), + Migrations: migrate.NewMigrations(), + }, nil +} + +// normalMode creates the default migrations directory and a cmd/ entrypoint. +// +// . +// └── cmd +// └── bun +// ├── main.go +// └── migrations +// └── main.go +type normalMode struct { + Loc string + Binary string + Migrations string + MigratorOptions []string +} + +const entrypointTemplate = `package main + +import ( + "os" + + "github.com/uptrace/bun" + "github.com/uptrace/bun/extra/buncli" + "github.com/uptrace/bun/migrate" + + %q +) + +func main() { + // TODO: connect to db + var _ /* db */ *bun.DB + + // TODO: configure AutoMigrator + var _ /* auto */ migrate.AutoMigrator + + cfg := &buncli.Config{ + RootName: %q, + // DB: db, + // AutoMigrator: auto, + Migrations: migrations.Migrations, + MigratorOptions: []migrate.MigratorOption{%s}, + } + + if err := buncli.Run(os.Args, cfg); err != nil { + panic(err) + } +} +` + +var migrationsTemplate = `package migrations + +import "github.com/uptrace/bun/migrate" + +var Migrations = migrate.NewMigrations() + +func init() { + if err := Migrations.DiscoverCaller(); err != nil { + panic(err) + } +} +` + +func (n *normalMode) Bootstrap() error { + // Create cmd/bun/main.go entrypoint + binDir := path.Join(n.Loc, "cmd", n.Binary) + modPath, err := n.migrationsImportPath(binDir) + if err != nil { + return err + } + + migratorOpts := strings.Join(n.MigratorOptions, ", ") + if err := writef(binDir, maingo, entrypointTemplate, modPath, n.Binary, migratorOpts); err != nil { + return err + } + + // Create migrations/main.go template + migrationsDir := path.Join(binDir, n.Migrations) + if err := writef(migrationsDir, maingo, migrationsTemplate); err != nil { + return err + } + + + return nil +} + +func (n *normalMode) migrationsImportPath(binDir string) (string, error) { + modPath, err := getModPath() + if err != nil { + return "", err + } + return path.Join(modPath, strings.TrimLeft(binDir, "."), n.Migrations), nil +} + +// pluginMode creates a layout of a project that can be compiled and imported as a plugin. +// +// . +// └── migrations +// └── main.go +type pluginMode struct { + Loc string + Migrations string + MigratorOptions []string +} + +var pluginTemplate = `package main + +import ( + "github.com/uptrace/bun" + "github.com/uptrace/bun/extra/buncli" + "github.com/uptrace/bun/migrate" +) + +var Config *buncli.Config + +func init() { + migrations := migrate.NewMigrations() + if err := migrations.DiscoverCaller(); err != nil { + panic(err) + } + + // TODO: connect to db + var _ /* db */ *bun.DB + + // TODO: configure AutoMigrator + var _ /* auto */ migrate.AutoMigrator + + Config = &buncli.Config{ + // DB: db, + // AutoMigrator: auto, + Migrations: migrations, + MigratorOptions: []migrate.MigratorOption{%s}, + } +} +` + +func (p *pluginMode) Bootstrap() error { + migrationsDir := path.Join(p.Loc, p.Migrations) + migratorOpts := strings.Join(p.MigratorOptions, ", ") + if err := writef(migrationsDir, maingo, pluginTemplate, migratorOpts); err != nil { + return err + } + + // TODO: run go mod init in migrations/ directory so that it'd be a standalone package + // TODO: run go mod init in migrations/ directory + + return nil +} + +// getModPath parses the ./go.mod file in the current directory and returns the declared module path. +func getModPath() (string, error) { + f, err := os.ReadFile("go.mod") + if err != nil { + return "", err + } + + gomod, err := modfile.Parse("go.mod", f, nil) + if err != nil { + return "", err + } + return gomod.Module.Mod.Path, nil +} + +// TODO: document +func writef(dir string, file string, format string, args ...interface{}) error { + if err := os.MkdirAll(dir, 0755); err != nil { + return err + } + + f, err := os.OpenFile(path.Join(dir, file), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0666) + if err != nil { + if os.IsExist(err) { + // TODO: log the fact that we haven't modified an existing main.go + return nil + } + return err + } + defer f.Close() + + if _, err := fmt.Fprintf(f, format, args...); err != nil { + return err + } + return nil +} + +// newDB connects to the database specified by the DSN. +// It will attempt to guess the driver from the connection string prefix, unless it is passed explicitly. +func newDB(ctx *cli.Context) (*bun.DB, error) { + var sqlDB *sql.DB + var dialect schema.Dialect + var err error + + dsn := flagDSN.Get(ctx) + driver := flagDriver.Get(ctx) + if !flagDriver.IsSet() { + guess, _, found := strings.Cut(dsn, ":") + if !found { + return nil, fmt.Errorf("driver cannot be guessed from connection string; pass --driver option explicitly") + } + driver = guess + } + + switch driver { + case "postgres": + sqlDB = sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn))) + dialect = pgdialect.New() + case "sqlserver": + sqlDB, err = sql.Open(driver, dsn) + dialect = mssqldialect.New() + case "file": + sqlDB, err = sql.Open(sqliteshim.ShimName, dsn) + dialect = sqlitedialect.New() + case "mysql": + sqlDB, err = sql.Open(driver, dsn) + dialect = mysqldialect.New() + case "oci8": + sqlDB, err = sql.Open(driver, dsn) + dialect = oracledialect.New() + default: + err = fmt.Errorf("driver %q not recognized, supported drivers are %v", driver, supportedDrivers) + } + + if err != nil { + return nil, err + } + + return bun.NewDB(sqlDB, dialect), nil +} + +// addNonDefaultMigratorOptions collects migrate.MigratorOption for every value overriden by a command-line flag. +func addNonDefaultMigratorOptions(ctx *cli.Context) []migrate.MigratorOption { + var opts []migrate.MigratorOption + + if t := flagTable.Get(ctx); ctx.IsSet(flagTable.Name) { + opts = append(opts, migrate.WithTableName(t)) + } + + if l := flagLocks.Get(ctx); ctx.IsSet(flagLocks.Name) { + opts = append(opts, migrate.WithLocksTableName(l)) + } + return opts +} + +// stringNonDefaultMigratorOptions is like addNonDefaultMigratorOptions, but stringifies options so they can be written to a file. +func stringNonDefaultMigratorOptions(ctx *cli.Context) []string { + var opts []string + + if t := flagTable.Get(ctx); ctx.IsSet(flagTable.Name) { + opts = append(opts, fmt.Sprintf("migrate.WithTableName(%q)", t)) + } + + if l := flagLocks.Get(ctx); ctx.IsSet(flagLocks.Name) { + opts = append(opts, fmt.Sprintf("migrate.WithLocksTableName(%q)", l)) + } + + return opts +} diff --git a/extra/buncli/migrator.go b/extra/buncli/migrator.go new file mode 100644 index 000000000..fc4355a4e --- /dev/null +++ b/extra/buncli/migrator.go @@ -0,0 +1,129 @@ +package buncli + +import ( + "github.com/uptrace/bun/migrate" + "github.com/urfave/cli/v2" +) + +// CmdMigrate creates migrate command. +func CmdMigrate(c MigratorConfig) *cli.Command { + return &cli.Command{ + Name: "migrate", + Usage: "Apply database migrations", + Action: func(ctx *cli.Context) error { + return runMigrate(ctx, c) + }, + } +} + +// MigratorConfig provides configuration related to conventional migrations. +type MigratorConfig interface { + OptionsConfig + NewMigrator() *migrate.Migrator +} + +func runMigrate(ctx *cli.Context, c MigratorConfig) error { + m := c.NewMigrator() + _, err := m.Migrate(ctx.Context, c.GetMigrateOptions()...) + return err +} + +// CmdRollback creates rollback command. +func CmdRollback(c MigratorConfig) *cli.Command { + return &cli.Command{ + Name: "rollback", + Usage: "Rollback the last migration group", + Action: func(ctx *cli.Context) error { + return runRollback(ctx, c) + }, + } +} + +func runRollback(ctx *cli.Context, c MigratorConfig) error { + m := c.NewMigrator() + _, err := m.Rollback(ctx.Context, c.GetMigrateOptions()...) + return err +} + +// CmdCreate creates create command. +func CmdCreate(c MigratorConfig) *cli.Command { + return &cli.Command{ + Name: "create", + Usage: "Create a new migration file template", + Args: true, // TODO: add usage example and description + Flags: []cli.Flag{ + flagTx, + flagGo, + flagSQL, + }, + Action: func(ctx *cli.Context) error { + return runCreate(ctx, c) + }, + } +} + +var ( + // createGo controls the type of the template (Go/SQL) the Migrator should create. + createGo bool + + // flagTx adds --transactional flag. + flagTx = &cli.BoolFlag{ + Name: "tx", + Aliases: []string{"transactional"}, + Usage: "write migrations to .tx.(up|down).sql file, they will be marked as transactional", + Value: false, + } + + // flagGo adds --go flag. Prefer checking 'createGo' as the flagGo and flagSQL are mutually exclusive and it is how they synchronize. + flagGo = &cli.BoolFlag{ + Name: "go", + Usage: "create .go migration file", + Value: false, + Destination: &createGo, + } + + // flagSQL adds --sql flag. Prefer checking 'createGo' as the flagGo and flagSQL are mutually exclusive and it is how they synchronize. + flagSQL = &cli.BoolFlag{ + Name: "sql", + Usage: "create .sql migrations", + Value: true, + Action: func(ctx *cli.Context, b bool) error { + createGo = !b + return nil + }, + } +) + +func runCreate(ctx *cli.Context, c MigratorConfig) error { + var err error + m := c.NewMigrator() + name := ctx.Args().First() + + if createGo { + _, err = m.CreateGoMigration(ctx.Context, name, c.GetGoMigrationOptions()...) + return err + } + + if flagTx.Get(ctx) { + _, err = m.CreateTxSQLMigrations(ctx.Context, name) + } else { + _, err = m.CreateSQLMigrations(ctx.Context, name) + } + return err +} + +// CmdUnlock creates an unlock command. +func CmdUnlock(c MigratorConfig) *cli.Command { + return &cli.Command{ + Name: "unlock", + Usage: "Unlock migration locks table", + Action: func(ctx *cli.Context) error { + return runUnlock(ctx, c) + }, + } +} + +func runUnlock(ctx *cli.Context, c MigratorConfig) error { + m := c.NewMigrator() + return m.Unlock(ctx.Context) +} diff --git a/extra/buncli/plugin.go b/extra/buncli/plugin.go new file mode 100644 index 000000000..2ff370dcc --- /dev/null +++ b/extra/buncli/plugin.go @@ -0,0 +1,176 @@ +package buncli + +import ( + "bytes" + "fmt" + "os/exec" + "path" + "plugin" + "sync" + + "github.com/uptrace/bun/migrate" + "github.com/urfave/cli/v2" +) + +const ( + pluginName = "plugin.so" + configLookupName = "Config" +) + +var ( + buildOnce = sync.OnceValue(buildPlugin) + importOnce = sync.OnceValues(importConfig) + + pluginPath string + + flagPluginPath = &cli.StringFlag{ + Name: "m", + Usage: "relative `PATH` to migrations directory", + Value: "./" + defaultMigrations, + Destination: &pluginPath, + } +) + +func pluginCommands() cli.Commands { + c := fromPlugin() + + auto := CmdAuto(c) + skipAuto := func(c *cli.Command) bool { + return c == auto + } + return extendCommands(cli.Commands{ + auto, + CmdMigrate(c), + CmdRollback(c), + CmdCreate(c), + CmdUnlock(c), + }, skipAuto, withBefore(checkCanImportPlugin), withFlag(flagPluginPath)) +} + +func fromPlugin() *pluginConfig { + return &pluginConfig{ + config: func() *Config { + c, _ := importOnce() + return c + }, + } +} + +// checkCanImportPlugin returns an error if migrations/ plugin build failed or *buncli.Config could not be imported from it. +func checkCanImportPlugin(ctx *cli.Context) error { + if isHelp(ctx) { + // Do not build plugin if on -help. + return nil + } + _, err := importOnce() + return err +} + +func isHelp(ctx *cli.Context) bool { + help := cli.HelpFlag.(*cli.BoolFlag) + return ctx.Command.Name == bunApp.HelpName || help.Get(ctx) +} + +// importConfig builds migrations/ plugin and imports Config from it. +// Config must be exported and of type *buncli.Config. +func importConfig() (*Config, error) { + if err := buildOnce(); err != nil { + return nil, err + } + + p, err := plugin.Open(path.Join(pluginPath, pluginName)) + if err != nil { + return nil, err + } + sym, err := p.Lookup(configLookupName) + if err != nil { + return nil, err + } + cfg, ok := sym.(**Config) + if !ok { + return nil, fmt.Errorf("migrations plugin must export Config as *buncli.Config, got %T", sym) + } + return *cfg, nil +} + +type pluginConfig struct { + config func() *Config +} + +var _ OptionsConfig = (*pluginConfig)(nil) +var _ MigratorConfig = (*pluginConfig)(nil) +var _ AutoConfig = (*pluginConfig)(nil) + +func (p *pluginConfig) NewMigrator() *migrate.Migrator { + return p.config().NewMigrator() +} + +func (p *pluginConfig) Auto() *migrate.AutoMigrator { + return p.config().Auto() +} + +func (p *pluginConfig) GetMigratorOptions() []migrate.MigratorOption { + return p.config().GetMigratorOptions() +} + +func (p *pluginConfig) GetMigrateOptions() []migrate.MigrationOption { + return p.config().GetMigrateOptions() +} + +func (p *pluginConfig) GetGoMigrationOptions() []migrate.GoMigrationOption { + return p.config().GetGoMigrationOptions() +} + +// buildPlugin compiles migrations/ plugin with -buildmode=plugin. +func buildPlugin() error { + cmd := exec.Command("go", "build", "-C", pluginPath, "-buildmode", "plugin", "-o", pluginName) + + // Cmd.Run returns *exec.ExitError which will only contain the exit code message in case of an error. + // Rather than logging "exit code 1" we want to output a more informative error, so we redirect the Stderr. + var errBuf bytes.Buffer + cmd.Stderr = &errBuf + + err := cmd.Run() + if err != nil { + return fmt.Errorf("build %s: %s", path.Join(pluginPath, pluginName), &errBuf) + } + return nil +} + +type commandOption func(*cli.Command) + +func extendCommands(commands cli.Commands, skip func(c *cli.Command) bool, options ...commandOption) cli.Commands { + var all cli.Commands + var flatten func(cmds cli.Commands) + + flatten = func(cmds cli.Commands) { + for _, cmd := range cmds { + if skip != nil && !skip(cmd) { + all = append(all, cmd) + } + flatten(cmd.Subcommands) + } + } + flatten(commands) + + for _, cmd := range all { + for _, opt := range options { + opt(cmd) + } + } + return commands +} + +// withFlag adds a flag to command. +func withFlag(f cli.Flag) commandOption { + return func(c *cli.Command) { + c.Flags = append(c.Flags, f) + } +} + +// withBefore adds BeforeFunc to command. +func withBefore(bf cli.BeforeFunc) commandOption { + return func(c *cli.Command) { + c.Before = bf + } +} diff --git a/go.mod b/go.mod index 48b197ab8..b95700e62 100644 --- a/go.mod +++ b/go.mod @@ -8,17 +8,46 @@ require ( github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.8.1 github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc + github.com/uptrace/bun/extra/buncli v0.0.0-00010101000000-000000000000 github.com/vmihailenco/msgpack/v5 v5.4.1 ) require ( + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/mattn/go-sqlite3 v1.14.24 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/uptrace/bun/dialect/mssqldialect v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/uptrace/bun/dialect/mysqldialect v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/uptrace/bun/dialect/oracledialect v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/uptrace/bun/dialect/pgdialect v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/uptrace/bun/driver/pgdriver v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e // indirect + github.com/urfave/cli/v2 v2.27.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + golang.org/x/crypto v0.29.0 // indirect + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/sys v0.27.0 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + mellium.im/sasl v0.3.2 // indirect + modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 // indirect + modernc.org/libc v1.61.2 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.34.1 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect ) + +replace github.com/uptrace/bun/extra/buncli => ./extra/buncli diff --git a/go.sum b/go.sum index 0e97efd20..d617bd1c9 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,32 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -21,9 +34,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -33,18 +50,74 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/uptrace/bun/dialect/mssqldialect v1.2.7-0.20241126124946-928d0779110e h1:gaD0dmqaYNFtX+iPxhX9UDelJ6u6BVajSNH4Ing5Ty4= +github.com/uptrace/bun/dialect/mssqldialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:IzBp33ztsWM76cdCqJAb1iXpwKl+djYEsA5EIPh2H6M= +github.com/uptrace/bun/dialect/mysqldialect v1.2.7-0.20241126124946-928d0779110e h1:w2VE7E0DrlYd1QdHH2MGmSO3AyTfU3D5Yn8aGuSTh9c= +github.com/uptrace/bun/dialect/mysqldialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:f3OuhVaMIwb98ZH+QhFuxlDNgkxTWcy93o3bYml78qA= +github.com/uptrace/bun/dialect/oracledialect v1.2.7-0.20241126124946-928d0779110e h1:HRWeCrgT9ggMISNuvx+QeFqgstFFh27ab8FBYgvQ5pY= +github.com/uptrace/bun/dialect/oracledialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:vCYOY37smpebuKD6FCoF7oy/TxDjz/wIZJ7jRjTxYHM= +github.com/uptrace/bun/dialect/pgdialect v1.2.7-0.20241126124946-928d0779110e h1:iMJU0gy83bPL6JtoPOAroc0GdEdDLz6B6irE83ebnas= +github.com/uptrace/bun/dialect/pgdialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:hfkgRt/bb5VYxS6CDngcjxF0An0iXOeVz8TSsWJIb/I= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e h1:X2j53OxG6XgnMGWkFoyLWlZQS0hGFxNZGYXU73mUtRw= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.7-0.20241126124946-928d0779110e/go.mod h1:/jVQkA37QsTWBjGesSHubm8W1PLI5+gCzFrSX1k0Kfs= +github.com/uptrace/bun/driver/pgdriver v1.2.7-0.20241126124946-928d0779110e h1:18aMpwYKpAwFcOm7Swv8zHikkq5NTW8fFEpmnDF1gH4= +github.com/uptrace/bun/driver/pgdriver v1.2.7-0.20241126124946-928d0779110e/go.mod h1:B+uzDgcf88kUubal/g7L5VB58n1DBCugKBKA16YAM6w= +github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e h1:HsHf0+SS9q01zbV9jNIg9lf8U/hjSPQOvGXa+3WwzXg= +github.com/uptrace/bun/driver/sqliteshim v1.2.7-0.20241126124946-928d0779110e/go.mod h1:6NKvfZH+x8b+LEt9+zvx0LFWxJf18/tt/NFzn4FxNMM= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= +golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +mellium.im/sasl v0.3.2 h1:PT6Xp7ccn9XaXAnJ03FcEjmAn7kK1x7aoXV6F+Vmrl0= +mellium.im/sasl v0.3.2/go.mod h1:NKXDi1zkr+BlMHLQjY3ofYuU4KSPFxknb8mfEu6SveY= +modernc.org/cc/v4 v4.23.1 h1:WqJoPL3x4cUufQVHkXpXX7ThFJ1C4ik80i2eXEXbhD8= +modernc.org/cc/v4 v4.23.1/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.22.3 h1:C7AW89Zw3kygesTQWBzApwIn9ldM+cb/plrTIKq41Os= +modernc.org/ccgo/v4 v4.22.3/go.mod h1:Dz7n0/UkBbH3pnYaxgi1mFSfF4REqUOZNziphZASx6k= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.5.0 h1:bJ9ChznK1L1mUtAQtxi0wi5AtAs5jQuw4PrPHO5pb6M= +modernc.org/gc/v2 v2.5.0/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 h1:IYXPPTTjjoSHvUClZIYexDiO7g+4x+XveKT4gCIAwiY= +modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.61.2 h1:dkO4DlowfClcJYsvf/RiK6fUwvzCQTmB34bJLt0CAGQ= +modernc.org/libc v1.61.2/go.mod h1:4QGjNyX3h+rn7V5oHpJY2yH0QN6frt1X+5BkXzwLPCo= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.34.1 h1:u3Yi6M0N8t9yKRDwhXcyp1eS5/ErhPTBggxWFuR6Hfk= +modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= diff --git a/migrate/auto.go b/migrate/auto.go index 16804cd99..e56ca2a64 100644 --- a/migrate/auto.go +++ b/migrate/auto.go @@ -140,8 +140,8 @@ type AutoMigrator struct { func NewAutoMigrator(db *bun.DB, opts ...AutoMigratorOption) (*AutoMigrator, error) { am := &AutoMigrator{ db: db, - table: defaultTable, - locksTable: defaultLocksTable, + table: DefaultTable, + locksTable: DefaultLocksTable, schemaName: db.Dialect().DefaultSchema(), } diff --git a/migrate/migrator.go b/migrate/migrator.go index d5a72aec0..7466fbe27 100644 --- a/migrate/migrator.go +++ b/migrate/migrator.go @@ -13,8 +13,8 @@ import ( ) const ( - defaultTable = "bun_migrations" - defaultLocksTable = "bun_migration_locks" + DefaultTable = "bun_migrations" + DefaultLocksTable = "bun_migration_locks" ) type MigratorOption func(m *Migrator) @@ -59,8 +59,8 @@ func NewMigrator(db *bun.DB, migrations *Migrations, opts ...MigratorOption) *Mi ms: migrations.ms, - table: defaultTable, - locksTable: defaultLocksTable, + table: DefaultTable, + locksTable: DefaultLocksTable, } for _, opt := range opts { opt(m)