Skip to content

Commit 9baac15

Browse files
committed
feat: implement pg-delta flag for schema diff
1 parent 358a5ff commit 9baac15

3 files changed

Lines changed: 78 additions & 1 deletion

File tree

cmd/db.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ var (
8787
useMigra bool
8888
usePgAdmin bool
8989
usePgSchema bool
90+
usePgDelta bool
9091
schema []string
9192
file string
9293

@@ -101,6 +102,8 @@ var (
101102
if usePgSchema {
102103
differ = diff.DiffPgSchema
103104
fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "--use-pg-schema flag is experimental and may not include all entities, such as views and grants.")
105+
} else if usePgDelta {
106+
differ = diff.DiffPgDelta
104107
}
105108
return diff.Run(cmd.Context(), schema, file, flags.DbConfig, differ, afero.NewOsFs())
106109
},
@@ -257,7 +260,8 @@ func init() {
257260
diffFlags.BoolVar(&useMigra, "use-migra", true, "Use migra to generate schema diff.")
258261
diffFlags.BoolVar(&usePgAdmin, "use-pgadmin", false, "Use pgAdmin to generate schema diff.")
259262
diffFlags.BoolVar(&usePgSchema, "use-pg-schema", false, "Use pg-schema-diff to generate schema diff.")
260-
dbDiffCmd.MarkFlagsMutuallyExclusive("use-migra", "use-pgadmin")
263+
diffFlags.BoolVar(&usePgDelta, "use-pg-delta", false, "Use pg-delta to generate schema diff.")
264+
dbDiffCmd.MarkFlagsMutuallyExclusive("use-migra", "use-pgadmin", "use-pg-schema", "use-pg-delta")
261265
diffFlags.String("db-url", "", "Diffs against the database specified by the connection string (must be percent-encoded).")
262266
diffFlags.Bool("linked", false, "Diffs local migration files against the linked project.")
263267
diffFlags.Bool("local", true, "Diffs local migration files against the local database.")

internal/db/diff/pgdelta.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package diff
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"strings"
7+
8+
"github.com/docker/docker/api/types/container"
9+
"github.com/docker/docker/api/types/network"
10+
"github.com/go-errors/errors"
11+
"github.com/jackc/pgconn"
12+
"github.com/jackc/pgx/v4"
13+
"github.com/spf13/viper"
14+
"github.com/supabase/cli/internal/gen/types"
15+
"github.com/supabase/cli/internal/utils"
16+
)
17+
18+
//go:embed templates/delta.ts
19+
var pgDeltaScript string
20+
21+
func DiffPgDelta(ctx context.Context, source, target pgconn.Config, schema []string, options ...func(*pgx.ConnConfig)) (string, error) {
22+
env := []string{
23+
"SOURCE=" + utils.ToPostgresURL(source),
24+
"TARGET=" + utils.ToPostgresURL(target),
25+
}
26+
if ca, err := types.GetRootCA(ctx, utils.ToPostgresURL(target), options...); err != nil {
27+
return "", err
28+
} else if len(ca) > 0 {
29+
env = append(env, "SSL_CA="+ca)
30+
}
31+
if len(schema) > 0 {
32+
env = append(env, "INCLUDED_SCHEMAS="+strings.Join(schema, ","))
33+
} else {
34+
env = append(env, "EXCLUDED_SCHEMAS="+strings.Join(managedSchemas, ","))
35+
}
36+
cmd := []string{"edge-runtime", "start", "--main-service=."}
37+
if viper.GetBool("DEBUG") {
38+
cmd = append(cmd, "--verbose")
39+
}
40+
cmdString := strings.Join(cmd, " ")
41+
entrypoint := []string{"sh", "-c", `cat <<'EOF' > index.ts && ` + cmdString + `
42+
` + pgDeltaScript + `
43+
EOF
44+
`}
45+
var out, stderr bytes.Buffer
46+
if err := utils.DockerRunOnceWithConfig(
47+
ctx,
48+
container.Config{
49+
Image: utils.Config.EdgeRuntime.Image,
50+
Env: env,
51+
Entrypoint: entrypoint,
52+
},
53+
container.HostConfig{
54+
Binds: []string{utils.EdgeRuntimeId + ":/root/.cache/deno:rw"},
55+
NetworkMode: network.NetworkHost,
56+
},
57+
network.NetworkingConfig{},
58+
"",
59+
&out,
60+
&stderr,
61+
); err != nil && !strings.HasPrefix(stderr.String(), "main worker has been destroyed") {
62+
return "", errors.Errorf("error diffing schema: %w:\n%s", err, stderr.String())
63+
}
64+
return out.String(), nil
65+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { main } from "npm:@supabase/pg-delta@1.0.0-alpha.0";
2+
import { supabase } from "npm:@supabase/integrations";
3+
4+
const source = Deno.env.get("SOURCE");
5+
const target = Deno.env.get("TARGET");
6+
7+
const { migrationScript } = await main(source, target, supabase)
8+
console.log(migrationScript)

0 commit comments

Comments
 (0)