github.com/supabase/cli@v1.168.1/internal/db/diff/pgadmin.go (about) 1 package diff 2 3 import ( 4 "context" 5 _ "embed" 6 "fmt" 7 "os" 8 9 "github.com/go-errors/errors" 10 "github.com/jackc/pgconn" 11 "github.com/spf13/afero" 12 "github.com/supabase/cli/internal/db/start" 13 "github.com/supabase/cli/internal/migration/new" 14 "github.com/supabase/cli/internal/utils" 15 ) 16 17 var warnDiff = `WARNING: The diff tool is not foolproof, so you may need to manually rearrange and modify the generated migration. 18 Run ` + utils.Aqua("supabase db reset") + ` to verify that the new migration does not generate errors.` 19 20 func SaveDiff(out, file string, fsys afero.Fs) error { 21 if len(out) < 2 { 22 fmt.Fprintln(os.Stderr, "No schema changes found") 23 } else if len(file) > 0 { 24 path := new.GetMigrationPath(utils.GetCurrentTimestamp(), file) 25 if err := utils.WriteFile(path, []byte(out), fsys); err != nil { 26 return err 27 } 28 fmt.Fprintln(os.Stderr, warnDiff) 29 } else { 30 fmt.Println(out) 31 } 32 return nil 33 } 34 35 func RunPgAdmin(ctx context.Context, schema []string, file string, config pgconn.Config, fsys afero.Fs) error { 36 // Sanity checks. 37 { 38 if err := utils.LoadConfigFS(fsys); err != nil { 39 return err 40 } 41 if err := utils.AssertSupabaseDbIsRunning(); err != nil { 42 return err 43 } 44 } 45 46 if err := utils.RunProgram(ctx, func(p utils.Program, ctx context.Context) error { 47 return run(p, ctx, schema, config, fsys) 48 }); err != nil { 49 return err 50 } 51 52 return SaveDiff(output, file, fsys) 53 } 54 55 var output string 56 57 func run(p utils.Program, ctx context.Context, schema []string, config pgconn.Config, fsys afero.Fs) error { 58 p.Send(utils.StatusMsg("Creating shadow database...")) 59 60 // 1. Create shadow db and run migrations 61 shadow, err := CreateShadowDatabase(ctx, utils.Config.Db.ShadowPort) 62 if err != nil { 63 return err 64 } 65 defer utils.DockerRemove(shadow) 66 if !start.WaitForHealthyService(ctx, shadow, start.HealthTimeout) { 67 return errors.New(start.ErrDatabase) 68 } 69 if err := MigrateShadowDatabase(ctx, shadow, fsys); err != nil { 70 return err 71 } 72 73 p.Send(utils.StatusMsg("Diffing local database with current migrations...")) 74 75 // 2. Diff local db (source) with shadow db (target), print it. 76 source := utils.ToPostgresURL(config) 77 target := fmt.Sprintf("postgresql://postgres:postgres@127.0.0.1:%d/postgres", utils.Config.Db.ShadowPort) 78 output, err = DiffSchemaPgAdmin(ctx, source, target, schema, p) 79 return err 80 } 81 82 func DiffSchemaPgAdmin(ctx context.Context, source, target string, schema []string, p utils.Program) (string, error) { 83 stream := utils.NewDiffStream(p) 84 args := []string{"--json-diff", source, target} 85 if len(schema) == 0 { 86 if err := utils.DockerRunOnceWithStream( 87 ctx, 88 utils.DifferImage, 89 nil, 90 args, 91 stream.Stdout(), 92 stream.Stderr(), 93 ); err != nil { 94 return "", err 95 } 96 } 97 for _, s := range schema { 98 p.Send(utils.StatusMsg("Diffing schema: " + s)) 99 if err := utils.DockerRunOnceWithStream( 100 ctx, 101 utils.DifferImage, 102 nil, 103 append([]string{"--schema", s}, args...), 104 stream.Stdout(), 105 stream.Stderr(), 106 ); err != nil { 107 return "", err 108 } 109 } 110 diffBytes, err := stream.Collect() 111 return string(diffBytes), err 112 }