Skip to content

Commit ed2eb02

Browse files
committed
no-mistakes(review): Rewrite only the depth-0 IS DISTINCT FROM operator
1 parent 6ae1046 commit ed2eb02

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,20 @@ function matchingParen(s: string, open: number): number {
8787
return -1;
8888
}
8989

90-
/** `inner` with its depth-0 text (literals, quoted identifiers and bracketed groups blanked). */
90+
/**
91+
* `inner` with everything below depth 0 blanked (literals, quoted identifiers, bracketed
92+
* groups). Same length as `inner`, so an offset found here is the same offset in `inner`.
93+
*/
9194
function topLevelText(inner: string): string {
9295
let out = "";
9396
let depth = 0;
9497
for (let i = 0; i < inner.length; i++) {
9598
const ch = inner[i]!;
9699
if (ch === "'" || ch === '"') {
97-
i++;
100+
const start = i++;
98101
while (i < inner.length && !(inner[i] === ch && inner[i + 1] !== ch)) i += inner[i] === ch ? 2 : 1;
99-
out += " ";
102+
i = Math.min(i, inner.length - 1);
103+
out += " ".repeat(i - start + 1);
100104
} else if (ch === "(" || ch === "[") { depth++; out += " "; }
101105
else if (ch === ")" || ch === "]") { depth--; out += " "; }
102106
else out += depth === 0 ? ch : " ";
@@ -131,8 +135,10 @@ function foldNotDistinctFrom(expr: string): string {
131135
if (close !== -1) {
132136
const inner = expr.slice(open + 1, close);
133137
const top = topLevelText(inner);
134-
if (top.match(/\bis\s+distinct\s+from\b/gi)?.length === 1 && !/\b(?:and|or|not)\b/i.test(top)) {
135-
out += `(${inner.replace(/\bis\s+distinct\s+from\b/i, "is not distinct from")})`;
138+
const operators = [...top.matchAll(/\bis\s+distinct\s+from\b/gi)];
139+
if (operators.length === 1 && !/\b(?:and|or|not)\b/i.test(top)) {
140+
const op = operators[0]!;
141+
out += `(${inner.slice(0, op.index)}is not distinct from${inner.slice(op.index + op[0].length)})`;
136142
i = close + 1;
137143
continue;
138144
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,12 @@ describe("Postgres analyzer rewrites that text normalisation cannot undo", () =>
261261
expect(checkExprEquals(`x IS NOT DISTINCT FROM y`, `NOT (x IS DISTINCT FROM y)`)).toBe(true);
262262
// a negated group that is more than one comparison is not folded
263263
expect(checkExprEquals(`NOT (a IS DISTINCT FROM b OR c)`, `a IS NOT DISTINCT FROM b OR c`)).toBe(false);
264+
// only the depth-0 operator is rewritten: a nested comparison that comes first is not the one negated
265+
expect(checkExprEquals(`NOT ((a IS DISTINCT FROM b) IS DISTINCT FROM c)`, `(a IS NOT DISTINCT FROM b) IS DISTINCT FROM c`)).toBe(false);
266+
expect(checkExprEquals(`NOT ((a IS DISTINCT FROM b) IS DISTINCT FROM c)`, `(a IS DISTINCT FROM b) IS NOT DISTINCT FROM c`)).toBe(true);
267+
// the phrase inside a literal is data, never the operator
268+
expect(checkExprEquals(`NOT ('x is distinct from y' IS DISTINCT FROM z)`, `'x is not distinct from y' IS DISTINCT FROM z`)).toBe(false);
269+
expect(checkExprEquals(`NOT ('x is distinct from y' IS DISTINCT FROM z)`, `'x is distinct from y' IS NOT DISTINCT FROM z`)).toBe(true);
264270
// `IS NOT NULL` is not a left operand
265271
expect(normalizeCheckExpr(`NOT (x IS NOT NULL IS DISTINCT FROM y)`)).toBe(`not x is not null is distinct from y`);
266272
});

0 commit comments

Comments
 (0)