可以使用golang-migrate与Go的嵌入功能一起使用吗?

huangapple go评论120阅读模式
英文:

Can you use golang-migrate with go's embed function?

问题

我正在尝试使用golang-migrate将一个SQL文件迁移到我的PostgreSQL数据库中。我可能做错了什么,但当我运行迁移命令时,它显示找不到模式:

  1. $ go run ./cmd/migrate
  2. 2022/04/05 16:20:29 no scheme
  3. exit status 1

以下是代码:

  1. // package dbschema contains the database schema, migrations, and seeding data.
  2. package dbschema
  3. import (
  4. "context"
  5. _ "embed" // 调用init函数。
  6. "fmt"
  7. "log"
  8. "github.com/golang-migrate/migrate/v4"
  9. "github.com/golang-migrate/migrate/v4/database/postgres"
  10. "github.com/jmoiron/sqlx"
  11. "github.com/jonleopard/bootstrap/pkg/sys/database"
  12. _ "github.com/lib/pq"
  13. )
  14. var (
  15. //go:embed sql/000001_schema.up.sql
  16. schemaDoc string
  17. //go:embed sql/seed.sql
  18. seedDoc string
  19. )
  20. // Migrate尝试使用此包中定义的迁移将数据库的模式更新到最新状态。
  21. func Migrate(ctx context.Context, db *sqlx.DB) error {
  22. if err := database.StatusCheck(ctx, db); err != nil {
  23. return fmt.Errorf("status check database: %w", err)
  24. }
  25. driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
  26. if err != nil {
  27. return fmt.Errorf("Construct Migrate driver: %w", err)
  28. }
  29. m, err := migrate.NewWithDatabaseInstance(schemaDoc, "postgres", driver)
  30. if err != nil {
  31. log.Fatal(err)
  32. }
  33. return m.Up()
  34. }

希望这可以帮助到你。

英文:

I'm trying to use golang-migrate to migrate a sql file into my postgresql database. I'm likely doing this wrong, but when I run the command to migrate it says that no scheme is found:

  1. $ go run ./cmd/ migrate
  2. 2022/04/05 16:20:29 no scheme
  3. exit status 1

Here is the code:

  1. // package dbschema contains the database schema, migrations, and seeding data.
  2. package dbschema
  3. import (
  4. "context"
  5. _ "embed" // Calls init function.
  6. "fmt"
  7. "log"
  8. "github.com/golang-migrate/migrate/v4"
  9. "github.com/golang-migrate/migrate/v4/database/postgres"
  10. "github.com/jmoiron/sqlx"
  11. "github.com/jonleopard/bootstrap/pkg/sys/database"
  12. _ "github.com/lib/pq"
  13. )
  14. var (
  15. //go:embed sql/000001_schema.up.sql
  16. schemaDoc string
  17. //go:embed sql/seed.sql
  18. seedDoc string
  19. )
  20. // Migrate attempts to bring the schema for db up to date with the migrations
  21. // defined in this package.
  22. func Migrate(ctx context.Context, db *sqlx.DB) error {
  23. if err := database.StatusCheck(ctx, db); err != nil {
  24. return fmt.Errorf("status check database: %w", err)
  25. }
  26. driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
  27. if err != nil {
  28. return fmt.Errorf("Construct Migrate driver: %w", err)
  29. }
  30. m, err := migrate.NewWithDatabaseInstance(schemaDoc, "postgres", driver)
  31. if err != nil {
  32. log.Fatal(err)
  33. }
  34. return m.Up()
  35. }

答案1

得分: 6

NewWithDatabaseInstance的定义如下:

  1. func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInstance database.Driver) (*Migrate, error)

所以第一个参数是一个URL,而你传入的是脚本本身。NewWithDatabaseInstance调用了SchemeFromURL,这就是你看到的错误的原因(因为你传入的URL不包含:)。URL由一个“scheme”后跟:,然后是其他信息组成。

要使用golang-migrateembed,请参考文档中的示例

  1. //go:embed testdata/migrations/*.sql
  2. var fs embed.FS
  3. func main() {
  4. d, err := iofs.New(fs, "testdata/migrations")
  5. if err != nil {
  6. log.Fatal(err)
  7. }
  8. m, err := migrate.NewWithSourceInstance("iofs", d, "postgres://postgres@localhost/postgres?sslmode=disable")
  9. if err != nil {
  10. log.Fatal(err)
  11. }
  12. err = m.Up()
  13. if err != nil {
  14. // ...
  15. }
  16. // ...
  17. }

你会注意到,这里传入的是一个文件夹(作为embed.FS),而不是单个文件。这是因为golang-migrate设计用于应用多个迁移,而不仅仅是对数据库运行单个脚本。你应该可以使用类似以下的代码:

  1. //go:embed sql/*.sql
  2. var schemaFs embed.FS
  3. ...
  4. d, err := iofs.New(fs, "sql") // 从sql文件夹获取迁移
  5. if err != nil {
  6. log.Fatal(err)
  7. }
  8. m, err := migrate.NewWithInstance("iofs", d, "postgres", driver)
英文:

The definition of NewWithDatabaseInstance is:

  1. func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInstance database.Driver) (*Migrate, error)

So the first parameter is a URL and you are passing in the script itself. NewWithDatabaseInstance calls SchemeFromURL which is what generates the error you are seeing (because the url you are passing does not contain a :). A URL consists of a "scheme" followed by : and then other info.

To use golang-migrate with embed see the example in the docs:

  1. //go:embed testdata/migrations/*.sql
  2. var fs embed.FS
  3. func main() {
  4. d, err := iofs.New(fs, "testdata/migrations")
  5. if err != nil {
  6. log.Fatal(err)
  7. }
  8. m, err := migrate.NewWithSourceInstance("iofs", d, "postgres://postgres@localhost/postgres?sslmode=disable")
  9. if err != nil {
  10. log.Fatal(err)
  11. }
  12. err = m.Up()
  13. if err != nil {
  14. // ...
  15. }
  16. // ...
  17. }

You will note that this passes in a folder (as an embed.FS) rather than a single file. This is because golang-migrate is designed to apply multiple migrations rather than just running a single script against the database. You should be able to use something like:

  1. //go:embed sql/*.sql
  2. var schemaFs embed.FS
  3. ...
  4. d, err := iofs.New(fs, "sql") // Get migrations from sql folder
  5. if err != nil {
  6. log.Fatal(err)
  7. }
  8. m, err := migrate.NewWithInstance("iofs", d, "postgres", driver)

huangapple
  • 本文由 发表于 2022年4月6日 07:26:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/71759491.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定