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