英文:
Can you use golang-migrate with go's embed function?
问题
我正在尝试使用golang-migrate
将一个SQL文件迁移到我的PostgreSQL数据库中。我可能做错了什么,但当我运行迁移命令时,它显示找不到模式:
$ go run ./cmd/migrate
2022/04/05 16:20:29 no scheme
exit status 1
以下是代码:
// package dbschema contains the database schema, migrations, and seeding data.
package dbschema
import (
"context"
_ "embed" // 调用init函数。
"fmt"
"log"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
"github.com/jmoiron/sqlx"
"github.com/jonleopard/bootstrap/pkg/sys/database"
_ "github.com/lib/pq"
)
var (
//go:embed sql/000001_schema.up.sql
schemaDoc string
//go:embed sql/seed.sql
seedDoc string
)
// Migrate尝试使用此包中定义的迁移将数据库的模式更新到最新状态。
func Migrate(ctx context.Context, db *sqlx.DB) error {
if err := database.StatusCheck(ctx, db); err != nil {
return fmt.Errorf("status check database: %w", err)
}
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
if err != nil {
return fmt.Errorf("Construct Migrate driver: %w", err)
}
m, err := migrate.NewWithDatabaseInstance(schemaDoc, "postgres", driver)
if err != nil {
log.Fatal(err)
}
return m.Up()
}
希望这可以帮助到你。
英文:
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:
$ go run ./cmd/ migrate
2022/04/05 16:20:29 no scheme
exit status 1
Here is the code:
// package dbschema contains the database schema, migrations, and seeding data.
package dbschema
import (
"context"
_ "embed" // Calls init function.
"fmt"
"log"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
"github.com/jmoiron/sqlx"
"github.com/jonleopard/bootstrap/pkg/sys/database"
_ "github.com/lib/pq"
)
var (
//go:embed sql/000001_schema.up.sql
schemaDoc string
//go:embed sql/seed.sql
seedDoc string
)
// Migrate attempts to bring the schema for db up to date with the migrations
// defined in this package.
func Migrate(ctx context.Context, db *sqlx.DB) error {
if err := database.StatusCheck(ctx, db); err != nil {
return fmt.Errorf("status check database: %w", err)
}
driver, err := postgres.WithInstance(db.DB, &postgres.Config{})
if err != nil {
return fmt.Errorf("Construct Migrate driver: %w", err)
}
m, err := migrate.NewWithDatabaseInstance(schemaDoc, "postgres", driver)
if err != nil {
log.Fatal(err)
}
return m.Up()
}
答案1
得分: 6
NewWithDatabaseInstance
的定义如下:
func NewWithDatabaseInstance(sourceURL string, databaseName string, databaseInstance database.Driver) (*Migrate, error)
所以第一个参数是一个URL,而你传入的是脚本本身。NewWithDatabaseInstance
调用了SchemeFromURL
,这就是你看到的错误的原因(因为你传入的URL不包含:
)。URL由一个“scheme”后跟:
,然后是其他信息组成。
要使用golang-migrate
和embed
,请参考文档中的示例:
//go:embed testdata/migrations/*.sql
var fs embed.FS
func main() {
d, err := iofs.New(fs, "testdata/migrations")
if err != nil {
log.Fatal(err)
}
m, err := migrate.NewWithSourceInstance("iofs", d, "postgres://postgres@localhost/postgres?sslmode=disable")
if err != nil {
log.Fatal(err)
}
err = m.Up()
if err != nil {
// ...
}
// ...
}
你会注意到,这里传入的是一个文件夹(作为embed.FS
),而不是单个文件。这是因为golang-migrate
设计用于应用多个迁移,而不仅仅是对数据库运行单个脚本。你应该可以使用类似以下的代码:
//go:embed sql/*.sql
var schemaFs embed.FS
...
d, err := iofs.New(fs, "sql") // 从sql文件夹获取迁移
if err != nil {
log.Fatal(err)
}
m, err := migrate.NewWithInstance("iofs", d, "postgres", driver)
英文:
The definition of NewWithDatabaseInstance
is:
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:
//go:embed testdata/migrations/*.sql
var fs embed.FS
func main() {
d, err := iofs.New(fs, "testdata/migrations")
if err != nil {
log.Fatal(err)
}
m, err := migrate.NewWithSourceInstance("iofs", d, "postgres://postgres@localhost/postgres?sslmode=disable")
if err != nil {
log.Fatal(err)
}
err = m.Up()
if err != nil {
// ...
}
// ...
}
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:
//go:embed sql/*.sql
var schemaFs embed.FS
...
d, err := iofs.New(fs, "sql") // Get migrations from sql folder
if err != nil {
log.Fatal(err)
}
m, err := migrate.NewWithInstance("iofs", d, "postgres", driver)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论