@pgpmjs/transform 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,15 +16,18 @@
16
16
  * modified objects routed through the granularity pipeline
17
17
  * (`restructureChanges`), so names come from the naming spec and `requires`
18
18
  * from the statement graph — the same derivation every other projection uses.
19
- * Every emitted change carries a full deploy/revert/verify triple: drops are
20
- * `@pgsql/scripts`' `revertFor` inverses of the object's own deploy
21
- * statements (never hand-templated), reverts recreate what was dropped, and
22
- * verifies come from `verifyFor`.
19
+ * Every emitted change carries a full deploy/revert/verify triple: inverses
20
+ * and existence checks are composed at the AST level via `@pgsql/scripts`'
21
+ * node-level API (`invertStatement`/`existenceCheck`) — never hand-templated
22
+ * and never round-tripped through deparsed text — deparsing only once at the
23
+ * end. Statements the node layer cannot derive fall back to the text layer
24
+ * (`revertFor`/`verifyFor`) solely to surface its not-derivable comment and
25
+ * warning.
23
26
  *
24
27
  * Requires `loadModule()` from `plpgsql-parser` before use.
25
28
  */
26
29
  import { pathFor } from '@pgpmjs/naming-spec';
27
- import { revertFor, verifyFor } from '@pgsql/scripts';
30
+ import { existenceCheck, invertStatement, revertFor, verifyFor } from '@pgsql/scripts';
28
31
  import { buildStatementGraph, classifyStatements, cleanTree, identityOf } from '@pgsql/transform';
29
32
  import { Deparser, parseSync } from 'plpgsql-parser';
30
33
  import { restructureChanges } from './granularity-driver';
@@ -252,17 +255,46 @@ export function diffSchemas(from, to, options = {}) {
252
255
  const forwardSql = [];
253
256
  const modifiedChanges = [];
254
257
  const dropUnits = [];
255
- /** `@pgsql/scripts` inverse of a deploy script (drops in reverse topo order). */
258
+ /**
259
+ * `@pgsql/scripts` inverse of a deploy script (drops in reverse topo
260
+ * order), composed at the AST level via `invertStatement` and deparsed
261
+ * once. Underivable statements fall back to `revertFor` on the single
262
+ * statement to surface its not-derivable comment and warning.
263
+ */
256
264
  const inverseOf = (deploy, context) => {
257
- const { sql, warnings: w } = revertFor(classifyStatements(deploy));
258
- warnings.push(...w.map(x => `${context}: ${x}`));
259
- return sql;
265
+ const facts = classifyStatements(deploy);
266
+ const graph = buildStatementGraph(facts);
267
+ const pieces = [];
268
+ for (const i of [...graph.order].reverse()) {
269
+ const nodes = invertStatement(facts[i]);
270
+ if (nodes === null) {
271
+ const { sql, warnings: w } = revertFor([facts[i]]);
272
+ warnings.push(...w.map(x => `${context}: ${x}`));
273
+ if (sql.trim())
274
+ pieces.push(sql);
275
+ continue;
276
+ }
277
+ pieces.push(...nodes.map(n => deparseStmt(n)));
278
+ }
279
+ return pieces.join('\n');
260
280
  };
261
- /** `@pgsql/scripts` existence checks for a deploy script. */
281
+ /**
282
+ * `@pgsql/scripts` existence checks for a deploy script, composed from
283
+ * `existenceCheck`'s SelectStmt nodes and deparsed once. Underivable
284
+ * statements fall back to `verifyFor` to surface the warning.
285
+ */
262
286
  const verifyOf = (deploy, context) => {
263
- const { sql, warnings: w } = verifyFor(classifyStatements(deploy));
264
- warnings.push(...w.map(x => `${context}: ${x}`));
265
- return sql;
287
+ const pieces = [];
288
+ for (const fact of classifyStatements(deploy)) {
289
+ const nodes = existenceCheck(fact);
290
+ if (nodes === null) {
291
+ const { warnings: w } = verifyFor([fact]);
292
+ warnings.push(...w.map(x => `${context}: ${x}`));
293
+ continue;
294
+ }
295
+ pieces.push(...nodes.map(n => deparseStmt(n)));
296
+ }
297
+ return pieces.join('\n\n');
266
298
  };
267
299
  for (const key of b.order) {
268
300
  const unit = b.units.get(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pgpmjs/transform",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Change-aware SQL transformation for PGPM — superset of @pgsql/transform plus change categorization, fixture closure, and bundle transpile/apply drivers",
6
6
  "main": "index.js",
@@ -48,5 +48,5 @@
48
48
  "@pgsql/transform": "^18.11.0",
49
49
  "plpgsql-parser": "^18.2.3"
50
50
  },
51
- "gitHead": "45cd961cf956d2d28e4d09b20db4204982c33593"
51
+ "gitHead": "6d3e25dc5c9f93421dba49ddedf93239f87213a8"
52
52
  }
@@ -16,10 +16,13 @@
16
16
  * modified objects routed through the granularity pipeline
17
17
  * (`restructureChanges`), so names come from the naming spec and `requires`
18
18
  * from the statement graph — the same derivation every other projection uses.
19
- * Every emitted change carries a full deploy/revert/verify triple: drops are
20
- * `@pgsql/scripts`' `revertFor` inverses of the object's own deploy
21
- * statements (never hand-templated), reverts recreate what was dropped, and
22
- * verifies come from `verifyFor`.
19
+ * Every emitted change carries a full deploy/revert/verify triple: inverses
20
+ * and existence checks are composed at the AST level via `@pgsql/scripts`'
21
+ * node-level API (`invertStatement`/`existenceCheck`) — never hand-templated
22
+ * and never round-tripped through deparsed text — deparsing only once at the
23
+ * end. Statements the node layer cannot derive fall back to the text layer
24
+ * (`revertFor`/`verifyFor`) solely to surface its not-derivable comment and
25
+ * warning.
23
26
  *
24
27
  * Requires `loadModule()` from `plpgsql-parser` before use.
25
28
  */
@@ -20,10 +20,13 @@ exports.diffChangeSets = diffChangeSets;
20
20
  * modified objects routed through the granularity pipeline
21
21
  * (`restructureChanges`), so names come from the naming spec and `requires`
22
22
  * from the statement graph — the same derivation every other projection uses.
23
- * Every emitted change carries a full deploy/revert/verify triple: drops are
24
- * `@pgsql/scripts`' `revertFor` inverses of the object's own deploy
25
- * statements (never hand-templated), reverts recreate what was dropped, and
26
- * verifies come from `verifyFor`.
23
+ * Every emitted change carries a full deploy/revert/verify triple: inverses
24
+ * and existence checks are composed at the AST level via `@pgsql/scripts`'
25
+ * node-level API (`invertStatement`/`existenceCheck`) — never hand-templated
26
+ * and never round-tripped through deparsed text — deparsing only once at the
27
+ * end. Statements the node layer cannot derive fall back to the text layer
28
+ * (`revertFor`/`verifyFor`) solely to surface its not-derivable comment and
29
+ * warning.
27
30
  *
28
31
  * Requires `loadModule()` from `plpgsql-parser` before use.
29
32
  */
@@ -256,17 +259,46 @@ function diffSchemas(from, to, options = {}) {
256
259
  const forwardSql = [];
257
260
  const modifiedChanges = [];
258
261
  const dropUnits = [];
259
- /** `@pgsql/scripts` inverse of a deploy script (drops in reverse topo order). */
262
+ /**
263
+ * `@pgsql/scripts` inverse of a deploy script (drops in reverse topo
264
+ * order), composed at the AST level via `invertStatement` and deparsed
265
+ * once. Underivable statements fall back to `revertFor` on the single
266
+ * statement to surface its not-derivable comment and warning.
267
+ */
260
268
  const inverseOf = (deploy, context) => {
261
- const { sql, warnings: w } = (0, scripts_1.revertFor)((0, transform_1.classifyStatements)(deploy));
262
- warnings.push(...w.map(x => `${context}: ${x}`));
263
- return sql;
269
+ const facts = (0, transform_1.classifyStatements)(deploy);
270
+ const graph = (0, transform_1.buildStatementGraph)(facts);
271
+ const pieces = [];
272
+ for (const i of [...graph.order].reverse()) {
273
+ const nodes = (0, scripts_1.invertStatement)(facts[i]);
274
+ if (nodes === null) {
275
+ const { sql, warnings: w } = (0, scripts_1.revertFor)([facts[i]]);
276
+ warnings.push(...w.map(x => `${context}: ${x}`));
277
+ if (sql.trim())
278
+ pieces.push(sql);
279
+ continue;
280
+ }
281
+ pieces.push(...nodes.map(n => deparseStmt(n)));
282
+ }
283
+ return pieces.join('\n');
264
284
  };
265
- /** `@pgsql/scripts` existence checks for a deploy script. */
285
+ /**
286
+ * `@pgsql/scripts` existence checks for a deploy script, composed from
287
+ * `existenceCheck`'s SelectStmt nodes and deparsed once. Underivable
288
+ * statements fall back to `verifyFor` to surface the warning.
289
+ */
266
290
  const verifyOf = (deploy, context) => {
267
- const { sql, warnings: w } = (0, scripts_1.verifyFor)((0, transform_1.classifyStatements)(deploy));
268
- warnings.push(...w.map(x => `${context}: ${x}`));
269
- return sql;
291
+ const pieces = [];
292
+ for (const fact of (0, transform_1.classifyStatements)(deploy)) {
293
+ const nodes = (0, scripts_1.existenceCheck)(fact);
294
+ if (nodes === null) {
295
+ const { warnings: w } = (0, scripts_1.verifyFor)([fact]);
296
+ warnings.push(...w.map(x => `${context}: ${x}`));
297
+ continue;
298
+ }
299
+ pieces.push(...nodes.map(n => deparseStmt(n)));
300
+ }
301
+ return pieces.join('\n\n');
270
302
  };
271
303
  for (const key of b.order) {
272
304
  const unit = b.units.get(key);