Skip to content

Commit 0061305

Browse files
committed
no-mistakes(review): Fold authored bare col::text on text columns
1 parent ed2eb02 commit 0061305

2 files changed

Lines changed: 12 additions & 7 deletions

File tree

‎server/typescript/packages/migrate-ts/src/check-expr-compare.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// - respells a cast TARGET canonically: `x::int` → `(x)::integer`
1919
// All five are canonicalized below so an enum/range CHECK introspected from PG
2020
// compares equal to the one we generate (idempotency on the --from-db / verify paths).
21-
// Three more are folded back by foldPgAnalyzerRewrites and PAREN_COLUMN_TEXT_CAST: a
21+
// Three more are folded back by foldPgAnalyzerRewrites and COLUMN_TEXT_CAST: a
2222
// one-element `x IN (v)` stored as `x = v`, `a IS NOT DISTINCT FROM b` stored as
2323
// `NOT (a IS DISTINCT FROM b)`, and `(varchar_col)::text` stored for a text operator.
2424
//
@@ -54,13 +54,13 @@ const NO_COLUMNS: ReadonlySet<string> = new Set();
5454
/**
5555
* `(col)::text` — the form Postgres writes when it casts a `varchar` column to `text` to reach
5656
* a text operator or function (`length((code)::text)`, `(a)::text < (b)::text`,
57-
* `((region)::text IS DISTINCT FROM 'eu'::text)`). Matched BEFORE the brackets are stripped,
58-
* while `(col)` can still be told from a call `f(col)`: the opening bracket must not follow a
59-
* word character. It is dropped only for a column the caller names as text-family
57+
* `((region)::text IS DISTINCT FROM 'eu'::text)`) — and the bare `col::text` an author writes
58+
* for the same cast. Matched BEFORE the brackets are stripped, while `(col)` can still be told
59+
* from a call `f(col)`: the match must not follow a word character or a dot. It is dropped only for a column the caller names as text-family
6060
* (`text` / `varchar`), where the cast changes nothing; on any other column it changes the
6161
* operator (citext) or the value (`char(n)` trims its padding), so it stays and reads as drift.
6262
*/
63-
const PAREN_COLUMN_TEXT_CAST = /(?<!\w)\(\s*([a-z_]\w*)\s*\)\s*::\s*text\b/g;
63+
const COLUMN_TEXT_CAST = /(?<![\w.])(?:\(\s*([a-z_]\w*)\s*\)|([a-z_]\w*))\s*::\s*text\b/g;
6464

6565
/** Split on single-quoted literals ('' escapes honored) and rewrite only the text between them. */
6666
function mapOutsideLiterals(s: string, fn: (part: string, index: number) => string): string {
@@ -184,7 +184,7 @@ function foldPgAnalyzerRewrites(s: string): string {
184184
* around commas, casts and SYMBOLIC operators (outside single-quoted literals).
185185
*
186186
* `textColumns` (lower-cased names of `text` / `varchar` columns) lets a `(col)::text` cast
187-
* fold away; see PAREN_COLUMN_TEXT_CAST and isElidableCast.
187+
* fold away; see COLUMN_TEXT_CAST and isElidableCast.
188188
*/
189189
export function normalizeCheckExpr(expr: string, textColumns: ReadonlySet<string> = NO_COLUMNS): string {
190190
// Every textual rewrite below runs OUTSIDE single-quoted literals. A literal is DATA: its
@@ -205,7 +205,10 @@ export function normalizeCheckExpr(expr: string, textColumns: ReadonlySet<string
205205
// makes the generated and introspected forms compare equal, and keeps a
206206
// legacy unquoted check matching its quoted re-emit.
207207
.replace(/"(\w+)"/g, "$1")
208-
.replace(PAREN_COLUMN_TEXT_CAST, (whole, column: string) => (textColumns.has(column) ? column : whole))
208+
.replace(COLUMN_TEXT_CAST, (whole, parenthesised: string | undefined, bare: string | undefined) => {
209+
const column = parenthesised ?? bare!;
210+
return textColumns.has(column) ? column : whole;
211+
})
209212
.replace(/[()[\]]/g, " ") // drop parens AND square brackets (ARRAY[…])
210213
.replace(/\s+/g, " ")
211214
// PG stores `col IN (…)` as `col = ANY (ARRAY[…])`; after the bracket strip above

‎server/typescript/packages/migrate-ts/test/check-evolution/normalize.test.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ describe("Postgres analyzer rewrites that text normalisation cannot undo", () =>
272272
});
273273
test("a varchar column's `(col)::text` cast is dropped wherever Postgres adds it", () => {
274274
const cols = new Set(["region", "name_a", "name_b", "short_code"]);
275+
expect(checkExprEquals(`length("short_code"::text) >= 2`, `(length((short_code)::text) >= 2)`, cols)).toBe(true);
276+
expect(checkExprEquals(`length(lower(short_code)::text) >= 2`, `(length((short_code)::text) >= 2)`, cols)).toBe(false);
275277
expect(checkExprEquals(`"region" IS NOT DISTINCT FROM 'eu'`, `NOT ((region)::text IS DISTINCT FROM 'eu'::text)`, cols)).toBe(true);
276278
expect(checkExprEquals(`("region" IS DISTINCT FROM 'us') OR (x IS NOT NULL)`, `(((region)::text IS DISTINCT FROM 'us'::text) OR (x IS NOT NULL))`, cols)).toBe(true);
277279
expect(checkExprEquals(`"name_a" < "name_b"`, `((name_a)::text < (name_b)::text)`, cols)).toBe(true);

0 commit comments

Comments
 (0)