From ddc32af1f2ec5d677b80fd1418005baabe8d26bd Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 24 Sep 2022 15:10:25 -0800 Subject: [PATCH] use embedded atlas migrations --- Taskfile.yml | 26 ++++++++-- backend/app/api/main.go | 61 ++++++++++++++++++++++- backend/app/migrations/main.go | 43 ++++++++++++++++ backend/internal/migrations/migrations.go | 6 +++ 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 backend/app/migrations/main.go create mode 100644 backend/internal/migrations/migrations.go diff --git a/Taskfile.yml b/Taskfile.yml index 04aa8e1..88146c3 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,14 +1,16 @@ version: "3" +env: + HBOX_STORAGE_SQLITE_URL: .data/homebox.db?_fk=1 + tasks: generate: desc: | Generates collateral files from the backend project including swagger docs and typescripts type for the frontend + deps: + - db:generate cmds: - - | - cd backend && ent generate ./ent/schema \ - --template=ent/schema/templates/has_id.tmpl - cd backend/app/api/ && swag fmt - cd backend/app/api/ && swag init --dir=./,../../internal,../../pkgs - | @@ -72,3 +74,21 @@ tasks: desc: Run frontend development server cmds: - cd frontend && pnpm dev + + db:generate: + desc: Run Entgo.io Code Generation + cmds: + - | + cd backend && go generate ./... \ + --template=ent/schema/templates/has_id.tmpl + sources: + - "./backend/ent/schema/**/*" + generates: + - "./backend/ent/" + + db:migration: + desc: Runs the database diff engine to generate a SQL migration files + deps: + - db:generate + cmds: + - cd backend && go run app/migrations/main.go {{ .CLI_ARGS }} diff --git a/backend/app/api/main.go b/backend/app/api/main.go index f25d20f..da9be3d 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -3,12 +3,15 @@ package main import ( "context" "os" + "path/filepath" "time" + atlas "ariga.io/atlas/sql/migrate" "entgo.io/ent/dialect/sql/schema" "github.com/hay-kot/homebox/backend/app/api/docs" "github.com/hay-kot/homebox/backend/ent" "github.com/hay-kot/homebox/backend/internal/config" + "github.com/hay-kot/homebox/backend/internal/migrations" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" "github.com/hay-kot/homebox/backend/pkgs/server" @@ -71,9 +74,63 @@ func run(cfg *config.Config) error { Msg("failed opening connection to sqlite") } defer func(c *ent.Client) { - _ = c.Close() + err := c.Close() + if err != nil { + log.Fatal().Err(err).Msg("failed to close database connection") + } }(c) - if err := c.Schema.Create(context.Background(), schema.WithAtlas(true)); err != nil { + + err = func() error { + temp := filepath.Join(os.TempDir(), "migrations") + defer func() { + err := os.RemoveAll(temp) + if err != nil { + log.Err(err).Msg("failed to remove temp directory") + } + }() + + err := os.MkdirAll(temp, 0755) + if err != nil { + return err + } + + // Write the embed migrations to the temp directory. + fsDir, err := migrations.Files.ReadDir(".") + if err != nil { + } + + for _, f := range fsDir { + if f.IsDir() { + continue + } + + b, err := migrations.Files.ReadFile(filepath.Join("migrations", f.Name())) + if err != nil { + return err + } + + err = os.WriteFile(filepath.Join(temp, f.Name()), b, 0644) + if err != nil { + return err + } + } + + dir, err := atlas.NewLocalDir(temp) + if err != nil { + return err + } + + options := []schema.MigrateOption{ + schema.WithAtlas(true), + schema.WithDir(dir), + schema.WithDropColumn(true), + schema.WithDropIndex(true), + } + + return c.Schema.Create(context.Background(), options...) + }() + + if err != nil { log.Fatal(). Err(err). Str("driver", "sqlite"). diff --git a/backend/app/migrations/main.go b/backend/app/migrations/main.go new file mode 100644 index 0000000..61b0358 --- /dev/null +++ b/backend/app/migrations/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "context" + "log" + "os" + + "github.com/hay-kot/homebox/backend/ent/migrate" + + atlas "ariga.io/atlas/sql/migrate" + _ "ariga.io/atlas/sql/sqlite" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql/schema" + _ "github.com/mattn/go-sqlite3" +) + +func main() { + ctx := context.Background() + // Create a local migration directory able to understand Atlas migration file format for replay. + dir, err := atlas.NewLocalDir("internal/migrations/migrations") + if err != nil { + log.Fatalf("failed creating atlas migration directory: %v", err) + } + // Migrate diff options. + opts := []schema.MigrateOption{ + schema.WithAtlas(true), + schema.WithDir(dir), // provide migration directory + schema.WithMigrationMode(schema.ModeReplay), // provide migration mode + schema.WithDialect(dialect.SQLite), // Ent dialect to use + schema.WithFormatter(atlas.DefaultFormatter), + schema.WithDropIndex(true), + schema.WithDropColumn(true), + } + if len(os.Args) != 2 { + log.Fatalln("migration name is required. Use: 'go run -mod=mod ent/migrate/main.go '") + } + + // Generate migrations using Atlas support for MySQL (note the Ent dialect option passed above). + err = migrate.NamedDiff(ctx, "sqlite://.data/homebox.migration.db?_fk=1", os.Args[1], opts...) + if err != nil { + log.Fatalf("failed generating migration file: %v", err) + } +} diff --git a/backend/internal/migrations/migrations.go b/backend/internal/migrations/migrations.go new file mode 100644 index 0000000..46120a4 --- /dev/null +++ b/backend/internal/migrations/migrations.go @@ -0,0 +1,6 @@ +package migrations + +import "embed" + +// go:embed all:migrations +var Files embed.FS