Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions pgpm/core/__tests__/packaging/round-trip-diff.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { mergeSqlStatements } from '../../src/packaging/package';

/**
* The round-trip check (parse -> deparse -> reparse) must ignore positional
* metadata. PG17+ emits list_start/list_end (A_ArrayExpr) and
* rexpr_list_start/rexpr_list_end (A_Expr IN lists), which shift whenever the
* deparsed SQL is formatted differently than the source.
*/
describe('AST round-trip diff detection', () => {
it('does not flag ARRAY[...] expressions', async () => {
const { diff } = await mergeSqlStatements(
`CREATE TABLE things (
id int,
tags text[] DEFAULT ARRAY['a', 'b', 'c']::text[]
);`,
{}
);
expect(diff).toBeUndefined();
});

it('does not flag IN (...) lists', async () => {
const { diff } = await mergeSqlStatements(
`SELECT * FROM things WHERE id IN (1, 2, 3);`,
{}
);
expect(diff).toBeUndefined();
});
});
24 changes: 21 additions & 3 deletions pgpm/core/src/packaging/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ export const cleanTree = (tree: any): any => {
});
};

/**
* Same as cleanTree, but also drops the byte-offset fields PG17+ added for list
* expressions (`ARRAY[...]`, `x IN (...)`). They are positional metadata, not
* semantics, so they must not count as a round-trip difference. Kept separate
* from cleanTree so migration hashes (hashSqlFile) stay stable.
*/
export const cleanTreeForDiff = (tree: any): any => {
return transformProps(tree, {
stmt_len: noop,
stmt_location: noop,
location: noop,
list_start: noop,
list_end: noop,
rexpr_list_start: noop,
rexpr_list_end: noop,
});
};

interface PackageModuleOptions {
usePlan?: boolean;
extension?: boolean;
Expand Down Expand Up @@ -94,11 +112,11 @@ export const mergeSqlStatements = async (
sql: `${topLine}${finalSql}`,
};

const diff = JSON.stringify(cleanTree(tree1)) !== JSON.stringify(cleanTree(tree2));
const diff = JSON.stringify(cleanTreeForDiff(tree1)) !== JSON.stringify(cleanTreeForDiff(tree2));
if (diff) {
results.diff = true;
results.tree1 = JSON.stringify(cleanTree(tree1), null, 2);
results.tree2 = JSON.stringify(cleanTree(tree2), null, 2);
results.tree1 = JSON.stringify(cleanTreeForDiff(tree1), null, 2);
results.tree2 = JSON.stringify(cleanTreeForDiff(tree2), null, 2);
}

return results;
Expand Down
Loading