supabase-cli/internal/db/diff/pgadmin.go

108 lines
2.9 KiB
Go

package diff
import (
"context"
_ "embed"
"fmt"
"os"
"github.com/jackc/pgconn"
"github.com/spf13/afero"
"github.com/supabase/cli/internal/db/start"
"github.com/supabase/cli/internal/migration/new"
"github.com/supabase/cli/internal/utils"
"github.com/supabase/cli/pkg/config"
)
var warnDiff = `WARNING: The diff tool is not foolproof, so you may need to manually rearrange and modify the generated migration.
Run ` + utils.Aqua("supabase db reset") + ` to verify that the new migration does not generate errors.`
func SaveDiff(out, file string, fsys afero.Fs) error {
if len(out) < 2 {
fmt.Fprintln(os.Stderr, "No schema changes found")
} else if len(file) > 0 {
path := new.GetMigrationPath(utils.GetCurrentTimestamp(), file)
if err := utils.WriteFile(path, []byte(out), fsys); err != nil {
return err
}
fmt.Fprintln(os.Stderr, warnDiff)
} else {
fmt.Println(out)
}
return nil
}
func RunPgAdmin(ctx context.Context, schema []string, file string, config pgconn.Config, fsys afero.Fs) error {
// Sanity checks.
if err := utils.AssertSupabaseDbIsRunning(); err != nil {
return err
}
if err := utils.RunProgram(ctx, func(p utils.Program, ctx context.Context) error {
return run(p, ctx, schema, config, fsys)
}); err != nil {
return err
}
return SaveDiff(output, file, fsys)
}
var output string
func run(p utils.Program, ctx context.Context, schema []string, config pgconn.Config, fsys afero.Fs) error {
p.Send(utils.StatusMsg("Creating shadow database..."))
// 1. Create shadow db and run migrations
shadow, err := CreateShadowDatabase(ctx, utils.Config.Db.ShadowPort)
if err != nil {
return err
}
defer utils.DockerRemove(shadow)
if err := start.WaitForHealthyService(ctx, start.HealthTimeout, shadow); err != nil {
return err
}
if err := MigrateShadowDatabase(ctx, shadow, fsys); err != nil {
return err
}
p.Send(utils.StatusMsg("Diffing local database with current migrations..."))
// 2. Diff local db (source) with shadow db (target), print it.
source := utils.ToPostgresURL(config)
target := fmt.Sprintf("postgresql://postgres:postgres@127.0.0.1:%d/postgres", utils.Config.Db.ShadowPort)
output, err = DiffSchemaPgAdmin(ctx, source, target, schema, p)
return err
}
func DiffSchemaPgAdmin(ctx context.Context, source, target string, schema []string, p utils.Program) (string, error) {
stream := utils.NewDiffStream(p)
args := []string{"--json-diff", source, target}
if len(schema) == 0 {
if err := utils.DockerRunOnceWithStream(
ctx,
config.Images.Differ,
nil,
args,
stream.Stdout(),
stream.Stderr(),
); err != nil {
return "", err
}
}
for _, s := range schema {
p.Send(utils.StatusMsg("Diffing schema: " + s))
if err := utils.DockerRunOnceWithStream(
ctx,
config.Images.Differ,
nil,
append([]string{"--schema", s}, args...),
stream.Stdout(),
stream.Stderr(),
); err != nil {
return "", err
}
}
diffBytes, err := stream.Collect()
return string(diffBytes), err
}