diff --git a/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.ts b/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.ts index 3479541302..f64c883c62 100644 --- a/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.ts +++ b/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.ts @@ -2,11 +2,11 @@ * Internal Postgres schemas the `inspect db` queries exclude, and the LIKE-escape * helper that turns them into `LIKE ANY($1)` exclusion patterns. * - * 1:1 port of Go's `utils.InternalSchemas` (`apps/cli-go/pkg/migration/dump.go:21-53`) - * and `reset.LikeEscapeSchema` (`apps/cli-go/internal/db/reset/reset.go:259-266`). - * The order is preserved verbatim because the escaped array is passed straight - * through to `LIKE ANY($1)`, where order is observable in nothing but is kept - * identical to avoid any drift from the Go source. + * The schema list is a 1:1 port of Go's `utils.InternalSchemas` + * (`apps/cli-go/pkg/migration/dump.go:21-53`). The order is preserved verbatim + * because the escaped array is passed straight through to `LIKE ANY($1)`, where + * order is observable in nothing but is kept identical to avoid any drift from + * the Go source. */ export const LEGACY_INTERNAL_SCHEMAS: ReadonlyArray = [ "information_schema", @@ -43,12 +43,20 @@ export const LEGACY_INTERNAL_SCHEMAS: ReadonlyArray = [ ]; /** - * Escapes each schema name into a SQL `LIKE` pattern, treating `_` as a literal - * underscore (`\_`) and `*` as the any-character wildcard (`%`). Mirrors Go's - * `strings.NewReplacer("_", "\\_", "*", "%")` — both replacements are applied to - * the original string, and since `_`→`\_` introduces only a backslash (not a `*`) - * and `*`→`%` introduces only a `%`, sequential JS replaces are equivalent. + * Escapes each schema name into a SQL `LIKE` pattern, treating `\` and `_` as + * literals and `*` as the any-character wildcard (`%`). */ export function legacyLikeEscapeSchema(schemas: ReadonlyArray): ReadonlyArray { - return schemas.map((schema) => schema.replace(/_/g, "\\_").replace(/\*/g, "%")); + return schemas.map((schema) => + schema.replace(/[\\_*]/g, (char) => { + switch (char) { + case "*": + return "%"; + case "\\": + return "\\\\"; + default: + return "\\_"; + } + }), + ); } diff --git a/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.unit.test.ts b/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.unit.test.ts index e71326d751..9179cf6ffc 100644 --- a/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.unit.test.ts +++ b/apps/cli/src/legacy/commands/inspect/db/legacy-inspect-schemas.unit.test.ts @@ -10,6 +10,15 @@ describe("legacyLikeEscapeSchema", () => { expect(legacyLikeEscapeSchema(["supabase_functions"])).toEqual(["supabase\\_functions"]); }); + it("escapes backslashes before LIKE metacharacters", () => { + expect(legacyLikeEscapeSchema([String.raw`custom\schema`])).toEqual([ + String.raw`custom\\schema`, + ]); + expect(legacyLikeEscapeSchema([String.raw`custom\_schema`])).toEqual([ + String.raw`custom\\\_schema`, + ]); + }); + it("leaves a plain schema name untouched", () => { expect(legacyLikeEscapeSchema(["auth"])).toEqual(["auth"]); });