@pgsql/transform 18.9.0 → 18.11.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.
package/esm/facts.js CHANGED
@@ -223,9 +223,15 @@ function classifyOne(nodeTag, node) {
223
223
  }
224
224
  break;
225
225
  case 'CreateEnumStmt':
226
- case 'CreateDomainStmt':
227
226
  case 'CreateRangeStmt': {
228
- const name = nameListToQualified(node.typeName ?? node.domainname);
227
+ const name = nameListToQualified(node.typeName);
228
+ if (name)
229
+ facts.creates.push(name);
230
+ break;
231
+ }
232
+ case 'CreateDomainStmt': {
233
+ // `typeName` on a domain is the base type; the name is `domainname`.
234
+ const name = nameListToQualified(node.domainname);
229
235
  if (name)
230
236
  facts.creates.push(name);
231
237
  break;
@@ -352,6 +358,7 @@ export function classifyStatements(sql) {
352
358
  const start = stmt?.stmt_location ?? 0;
353
359
  facts.span = { start, len: stmt?.stmt_len ?? Math.max(0, sql.length - start) };
354
360
  if (stmtNode) {
361
+ facts.stmt = stmtNode;
355
362
  walkSql(stmtNode, createFactsVisitor(facts));
356
363
  }
357
364
  if (nodeTag === 'CreateFunctionStmt') {
package/esm/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { classifyStatements } from './facts';
2
2
  export { buildStatementGraph } from './graph';
3
+ export { identityOf } from './naming';
3
4
  export { orderStatements, restructureSql } from './restructure';
4
5
  export { COMMON_EXTENSIONS, ExtensionRouter } from './extension-router';
5
6
  export { createExtensionResult, createExtensionVisitor, transformExtensions, } from './extension-transform';
package/esm/naming.js ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Derive the identity of the object a statement primarily creates or
3
+ * targets, or `null` when the statement creates nothing (grants, comments —
4
+ * such statements ride with the change of the object they attach to).
5
+ *
6
+ * Table-scoped kinds are recovered from the classifier's table-qualified
7
+ * names (`table.trigger`) and, for indexes and constraints, from the
8
+ * targeted relation.
9
+ */
10
+ export function identityOf(facts) {
11
+ if (facts.kind === 'extension' && facts.extension) {
12
+ return { kind: 'extension', schema: null, name: facts.extension.name };
13
+ }
14
+ const created = facts.creates[0];
15
+ if (!created)
16
+ return null;
17
+ switch (facts.kind) {
18
+ case 'schema':
19
+ return { kind: 'schema', schema: null, name: created.name };
20
+ case 'trigger':
21
+ case 'policy': {
22
+ const dot = created.name.indexOf('.');
23
+ if (dot > 0) {
24
+ return {
25
+ kind: facts.kind,
26
+ schema: created.schema,
27
+ name: created.name.slice(dot + 1),
28
+ table: created.name.slice(0, dot)
29
+ };
30
+ }
31
+ return { kind: facts.kind, schema: created.schema, name: created.name };
32
+ }
33
+ case 'index': {
34
+ // IndexStmt records the index name in creates and the indexed relation
35
+ // in references (same-schema RangeVar).
36
+ const rel = facts.references.find(r => r.schema === created.schema) ?? facts.references[0];
37
+ return {
38
+ kind: 'index',
39
+ schema: created.schema,
40
+ name: created.name,
41
+ table: rel?.name
42
+ };
43
+ }
44
+ case 'fk_constraint':
45
+ case 'constraint':
46
+ case 'rls_enable':
47
+ // ALTER TABLE statements target their table.
48
+ return { kind: 'constraint', schema: created.schema, name: created.name, table: created.name };
49
+ case 'seed_dml':
50
+ return { kind: 'seed_dml', schema: created.schema, name: created.name, table: created.name };
51
+ case 'table':
52
+ // AlterTableStmt facts also classify as `table`-targeting; the created
53
+ // name is the table either way.
54
+ return { kind: 'table', schema: created.schema, name: created.name };
55
+ case 'view':
56
+ case 'function':
57
+ case 'type':
58
+ return { kind: facts.kind, schema: created.schema, name: created.name };
59
+ default:
60
+ if (facts.nodeTag === 'CreateSeqStmt') {
61
+ return { kind: 'sequence', schema: created.schema, name: created.name };
62
+ }
63
+ return { kind: 'other', schema: created.schema, name: created.name };
64
+ }
65
+ }
package/facts.d.ts CHANGED
@@ -104,6 +104,14 @@ export interface StatementFacts {
104
104
  * facts without a second parse.
105
105
  */
106
106
  span: StatementSpan;
107
+ /**
108
+ * The raw parsed statement node (`{ CreateStmt: {...} }` etc.), exactly as
109
+ * the parser produced it. Facts are still read-only — the node is carried
110
+ * so consumers like `revertFor`/`verifyFor` can derive inverse or
111
+ * existence-check statements without a second parse. Absent only for
112
+ * facts constructed by hand.
113
+ */
114
+ stmt?: Record<string, any>;
107
115
  }
108
116
  /** A statement's location in the source script (byte offsets). */
109
117
  export interface StatementSpan {
package/facts.js CHANGED
@@ -226,9 +226,15 @@ function classifyOne(nodeTag, node) {
226
226
  }
227
227
  break;
228
228
  case 'CreateEnumStmt':
229
- case 'CreateDomainStmt':
230
229
  case 'CreateRangeStmt': {
231
- const name = nameListToQualified(node.typeName ?? node.domainname);
230
+ const name = nameListToQualified(node.typeName);
231
+ if (name)
232
+ facts.creates.push(name);
233
+ break;
234
+ }
235
+ case 'CreateDomainStmt': {
236
+ // `typeName` on a domain is the base type; the name is `domainname`.
237
+ const name = nameListToQualified(node.domainname);
232
238
  if (name)
233
239
  facts.creates.push(name);
234
240
  break;
@@ -355,6 +361,7 @@ function classifyStatements(sql) {
355
361
  const start = stmt?.stmt_location ?? 0;
356
362
  facts.span = { start, len: stmt?.stmt_len ?? Math.max(0, sql.length - start) };
357
363
  if (stmtNode) {
364
+ facts.stmt = stmtNode;
358
365
  (0, traverse_1.walk)(stmtNode, createFactsVisitor(facts));
359
366
  }
360
367
  if (nodeTag === 'CreateFunctionStmt') {
package/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export type { ExtensionAction, ExtensionFact, QualifiedName, StatementFacts, Sta
2
2
  export { classifyStatements } from './facts';
3
3
  export type { EdgeKind, StatementEdge, StatementGraph, StatementNode, } from './graph';
4
4
  export { buildStatementGraph } from './graph';
5
+ export type { ObjectIdentity, ObjectIdentityKind, } from './naming';
6
+ export { identityOf } from './naming';
5
7
  export type { Granularity, RestructureOptions, RestructureResult, } from './restructure';
6
8
  export { orderStatements, restructureSql } from './restructure';
7
9
  export type { ExtensionDefinition, ExtensionRoute, ExtensionRouteSpec, ExtensionRouterOptions, ExtensionSymbol, ExtensionSymbolNamespace, SymbolRewrite, } from './extension-router';
package/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.walkPlpgsqlForSchemas = exports.validateNoUntransformedSchemas = exports.transformVerifyCalls = exports.transformSqlStatement = exports.transformSql = exports.transformSchemaName = exports.transformRelation = exports.transformPlpgsqlTypeString = exports.transformPlpgsqlTypeAst = exports.transformNameList = exports.transformJsonStringValues = exports.transformComments = exports.shouldTransformSchema = exports.extractPgpmHeader = exports.escapeRegexp = exports.createSqlVisitor = exports.createPlpgsqlVisitor = exports.trimDefElemBody = exports.normalizeTree = exports.cleanTree = exports.CLEAN_TREE_VOLATILE_KEYS = exports.validateRoundTrip = exports.normalizeParseTree = exports.firstDifference = exports.captureTransformAsts = exports.captureAstsFromSql = exports.SchemaRouter = exports.qualifyUnqualified = exports.mergeInventories = exports.createQualifyVisitor = exports.collectCreatedObjects = exports.transformRoles = exports.createRoleVisitor = exports.createRoleResult = exports.RoleRouter = exports.transformExtensions = exports.createExtensionVisitor = exports.createExtensionResult = exports.ExtensionRouter = exports.COMMON_EXTENSIONS = exports.restructureSql = exports.orderStatements = exports.buildStatementGraph = exports.classifyStatements = void 0;
3
+ exports.walkPlpgsqlForSchemas = exports.validateNoUntransformedSchemas = exports.transformVerifyCalls = exports.transformSqlStatement = exports.transformSql = exports.transformSchemaName = exports.transformRelation = exports.transformPlpgsqlTypeString = exports.transformPlpgsqlTypeAst = exports.transformNameList = exports.transformJsonStringValues = exports.transformComments = exports.shouldTransformSchema = exports.extractPgpmHeader = exports.escapeRegexp = exports.createSqlVisitor = exports.createPlpgsqlVisitor = exports.trimDefElemBody = exports.normalizeTree = exports.cleanTree = exports.CLEAN_TREE_VOLATILE_KEYS = exports.validateRoundTrip = exports.normalizeParseTree = exports.firstDifference = exports.captureTransformAsts = exports.captureAstsFromSql = exports.SchemaRouter = exports.qualifyUnqualified = exports.mergeInventories = exports.createQualifyVisitor = exports.collectCreatedObjects = exports.transformRoles = exports.createRoleVisitor = exports.createRoleResult = exports.RoleRouter = exports.transformExtensions = exports.createExtensionVisitor = exports.createExtensionResult = exports.ExtensionRouter = exports.COMMON_EXTENSIONS = exports.restructureSql = exports.orderStatements = exports.identityOf = exports.buildStatementGraph = exports.classifyStatements = void 0;
4
4
  var facts_1 = require("./facts");
5
5
  Object.defineProperty(exports, "classifyStatements", { enumerable: true, get: function () { return facts_1.classifyStatements; } });
6
6
  var graph_1 = require("./graph");
7
7
  Object.defineProperty(exports, "buildStatementGraph", { enumerable: true, get: function () { return graph_1.buildStatementGraph; } });
8
+ var naming_1 = require("./naming");
9
+ Object.defineProperty(exports, "identityOf", { enumerable: true, get: function () { return naming_1.identityOf; } });
8
10
  var restructure_1 = require("./restructure");
9
11
  Object.defineProperty(exports, "orderStatements", { enumerable: true, get: function () { return restructure_1.orderStatements; } });
10
12
  Object.defineProperty(exports, "restructureSql", { enumerable: true, get: function () { return restructure_1.restructureSql; } });
package/naming.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Object identity — the canonical, Postgres-native answer to "what object is
3
+ * this statement about?".
4
+ *
5
+ * Identity is the key used by dependency graphs, semantic diffing, and any
6
+ * downstream naming scheme. It is a pure function of classifier facts —
7
+ * grounded in the parser's node taxonomy (`CreateStmt`, `CreateTrigStmt`,
8
+ * `IndexStmt`, ...), never in surface syntax like RangeVars. Rendering an
9
+ * identity to a change path (e.g. a pgpm module layout) is deliberately NOT
10
+ * defined here: paths are derived projections that belong to whichever
11
+ * packaging layer consumes the identity, so nothing is ever attached to them.
12
+ *
13
+ * Identity tuple: `(kind, schema, name, table?)` — `table` scopes objects
14
+ * that are only unique per table (triggers, policies, indexes, constraints,
15
+ * seed data). Function overloads share an identity for now (signature
16
+ * disambiguation is a planned refinement).
17
+ */
18
+ import { StatementFacts } from './facts';
19
+ /** The kinds of objects an identity can describe. */
20
+ export type ObjectIdentityKind = 'schema' | 'extension' | 'role' | 'table' | 'view' | 'sequence' | 'type' | 'function' | 'index' | 'trigger' | 'policy' | 'constraint' | 'seed_dml' | 'other';
21
+ /**
22
+ * The identity of a database object. Identity is the diff/dependency key;
23
+ * any path or name is only a downstream rendering of it.
24
+ */
25
+ export interface ObjectIdentity {
26
+ kind: ObjectIdentityKind;
27
+ /** Owning schema (`null` for non-schema objects: roles, extensions). */
28
+ schema: string | null;
29
+ /** Object name, unqualified (for table-scoped kinds: without the table). */
30
+ name: string;
31
+ /** Owning table, for objects only unique per table (trigger/policy/index/constraint/seed). */
32
+ table?: string;
33
+ }
34
+ /**
35
+ * Derive the identity of the object a statement primarily creates or
36
+ * targets, or `null` when the statement creates nothing (grants, comments —
37
+ * such statements ride with the change of the object they attach to).
38
+ *
39
+ * Table-scoped kinds are recovered from the classifier's table-qualified
40
+ * names (`table.trigger`) and, for indexes and constraints, from the
41
+ * targeted relation.
42
+ */
43
+ export declare function identityOf(facts: StatementFacts): ObjectIdentity | null;
package/naming.js ADDED
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.identityOf = identityOf;
4
+ /**
5
+ * Derive the identity of the object a statement primarily creates or
6
+ * targets, or `null` when the statement creates nothing (grants, comments —
7
+ * such statements ride with the change of the object they attach to).
8
+ *
9
+ * Table-scoped kinds are recovered from the classifier's table-qualified
10
+ * names (`table.trigger`) and, for indexes and constraints, from the
11
+ * targeted relation.
12
+ */
13
+ function identityOf(facts) {
14
+ if (facts.kind === 'extension' && facts.extension) {
15
+ return { kind: 'extension', schema: null, name: facts.extension.name };
16
+ }
17
+ const created = facts.creates[0];
18
+ if (!created)
19
+ return null;
20
+ switch (facts.kind) {
21
+ case 'schema':
22
+ return { kind: 'schema', schema: null, name: created.name };
23
+ case 'trigger':
24
+ case 'policy': {
25
+ const dot = created.name.indexOf('.');
26
+ if (dot > 0) {
27
+ return {
28
+ kind: facts.kind,
29
+ schema: created.schema,
30
+ name: created.name.slice(dot + 1),
31
+ table: created.name.slice(0, dot)
32
+ };
33
+ }
34
+ return { kind: facts.kind, schema: created.schema, name: created.name };
35
+ }
36
+ case 'index': {
37
+ // IndexStmt records the index name in creates and the indexed relation
38
+ // in references (same-schema RangeVar).
39
+ const rel = facts.references.find(r => r.schema === created.schema) ?? facts.references[0];
40
+ return {
41
+ kind: 'index',
42
+ schema: created.schema,
43
+ name: created.name,
44
+ table: rel?.name
45
+ };
46
+ }
47
+ case 'fk_constraint':
48
+ case 'constraint':
49
+ case 'rls_enable':
50
+ // ALTER TABLE statements target their table.
51
+ return { kind: 'constraint', schema: created.schema, name: created.name, table: created.name };
52
+ case 'seed_dml':
53
+ return { kind: 'seed_dml', schema: created.schema, name: created.name, table: created.name };
54
+ case 'table':
55
+ // AlterTableStmt facts also classify as `table`-targeting; the created
56
+ // name is the table either way.
57
+ return { kind: 'table', schema: created.schema, name: created.name };
58
+ case 'view':
59
+ case 'function':
60
+ case 'type':
61
+ return { kind: facts.kind, schema: created.schema, name: created.name };
62
+ default:
63
+ if (facts.nodeTag === 'CreateSeqStmt') {
64
+ return { kind: 'sequence', schema: created.schema, name: created.name };
65
+ }
66
+ return { kind: 'other', schema: created.schema, name: created.name };
67
+ }
68
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pgsql/transform",
3
- "version": "18.9.0",
3
+ "version": "18.11.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "AST-based SQL transformation, qualification, classification and closure analysis for PostgreSQL",
6
6
  "main": "index.js",
@@ -49,5 +49,5 @@
49
49
  "classify",
50
50
  "plpgsql"
51
51
  ],
52
- "gitHead": "ffe07838bbc332b12062679f4f0af6b952380cb1"
52
+ "gitHead": "f888a7701dc5abf309c0dfd04e0069375d4e7550"
53
53
  }