@query-doctor/core 0.8.1 → 0.8.2-rc.1

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.
Files changed (118) hide show
  1. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/defineProperty.cjs +13 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/defineProperty.mjs +13 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPrimitive.cjs +15 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPrimitive.mjs +15 -0
  5. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPropertyKey.cjs +10 -0
  6. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPropertyKey.mjs +10 -0
  7. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/typeof.cjs +17 -0
  8. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/typeof.mjs +12 -0
  9. package/dist/_virtual/_rolldown/runtime.cjs +24 -0
  10. package/dist/index.cjs +33 -2568
  11. package/dist/index.d.cts +11 -781
  12. package/dist/index.d.mts +11 -781
  13. package/dist/index.mjs +10 -2522
  14. package/dist/optimizer/genalgo.cjs +365 -0
  15. package/dist/optimizer/genalgo.cjs.map +1 -0
  16. package/dist/optimizer/genalgo.d.cts +111 -0
  17. package/dist/optimizer/genalgo.d.cts.map +1 -0
  18. package/dist/optimizer/genalgo.d.mts +111 -0
  19. package/dist/optimizer/genalgo.d.mts.map +1 -0
  20. package/dist/optimizer/genalgo.mjs +362 -0
  21. package/dist/optimizer/genalgo.mjs.map +1 -0
  22. package/dist/optimizer/pss-rewriter.cjs +31 -0
  23. package/dist/optimizer/pss-rewriter.cjs.map +1 -0
  24. package/dist/optimizer/pss-rewriter.d.cts +16 -0
  25. package/dist/optimizer/pss-rewriter.d.cts.map +1 -0
  26. package/dist/optimizer/pss-rewriter.d.mts +16 -0
  27. package/dist/optimizer/pss-rewriter.d.mts.map +1 -0
  28. package/dist/optimizer/pss-rewriter.mjs +31 -0
  29. package/dist/optimizer/pss-rewriter.mjs.map +1 -0
  30. package/dist/optimizer/statistics.cjs +738 -0
  31. package/dist/optimizer/statistics.cjs.map +1 -0
  32. package/dist/optimizer/statistics.d.cts +389 -0
  33. package/dist/optimizer/statistics.d.cts.map +1 -0
  34. package/dist/optimizer/statistics.d.mts +389 -0
  35. package/dist/optimizer/statistics.d.mts.map +1 -0
  36. package/dist/optimizer/statistics.mjs +729 -0
  37. package/dist/optimizer/statistics.mjs.map +1 -0
  38. package/dist/sentry.cjs +13 -0
  39. package/dist/sentry.cjs.map +1 -0
  40. package/dist/sentry.d.cts +7 -0
  41. package/dist/sentry.d.cts.map +1 -0
  42. package/dist/sentry.d.mts +7 -0
  43. package/dist/sentry.d.mts.map +1 -0
  44. package/dist/sentry.mjs +13 -0
  45. package/dist/sentry.mjs.map +1 -0
  46. package/dist/sql/analyzer.cjs +242 -0
  47. package/dist/sql/analyzer.cjs.map +1 -0
  48. package/dist/sql/analyzer.d.cts +112 -0
  49. package/dist/sql/analyzer.d.cts.map +1 -0
  50. package/dist/sql/analyzer.d.mts +112 -0
  51. package/dist/sql/analyzer.d.mts.map +1 -0
  52. package/dist/sql/analyzer.mjs +240 -0
  53. package/dist/sql/analyzer.mjs.map +1 -0
  54. package/dist/sql/ast-utils.cjs +19 -0
  55. package/dist/sql/ast-utils.cjs.map +1 -0
  56. package/dist/sql/ast-utils.d.cts +9 -0
  57. package/dist/sql/ast-utils.d.cts.map +1 -0
  58. package/dist/sql/ast-utils.d.mts +9 -0
  59. package/dist/sql/ast-utils.d.mts.map +1 -0
  60. package/dist/sql/ast-utils.mjs +17 -0
  61. package/dist/sql/ast-utils.mjs.map +1 -0
  62. package/dist/sql/builder.cjs +94 -0
  63. package/dist/sql/builder.cjs.map +1 -0
  64. package/dist/sql/builder.d.cts +37 -0
  65. package/dist/sql/builder.d.cts.map +1 -0
  66. package/dist/sql/builder.d.mts +37 -0
  67. package/dist/sql/builder.d.mts.map +1 -0
  68. package/dist/sql/builder.mjs +94 -0
  69. package/dist/sql/builder.mjs.map +1 -0
  70. package/dist/sql/database.cjs +35 -0
  71. package/dist/sql/database.cjs.map +1 -0
  72. package/dist/sql/database.d.cts +91 -0
  73. package/dist/sql/database.d.cts.map +1 -0
  74. package/dist/sql/database.d.mts +91 -0
  75. package/dist/sql/database.d.mts.map +1 -0
  76. package/dist/sql/database.mjs +32 -0
  77. package/dist/sql/database.mjs.map +1 -0
  78. package/dist/sql/indexes.cjs +17 -0
  79. package/dist/sql/indexes.cjs.map +1 -0
  80. package/dist/sql/indexes.d.cts +14 -0
  81. package/dist/sql/indexes.d.cts.map +1 -0
  82. package/dist/sql/indexes.d.mts +14 -0
  83. package/dist/sql/indexes.d.mts.map +1 -0
  84. package/dist/sql/indexes.mjs +16 -0
  85. package/dist/sql/indexes.mjs.map +1 -0
  86. package/dist/sql/nudges.cjs +484 -0
  87. package/dist/sql/nudges.cjs.map +1 -0
  88. package/dist/sql/nudges.d.cts +21 -0
  89. package/dist/sql/nudges.d.cts.map +1 -0
  90. package/dist/sql/nudges.d.mts +21 -0
  91. package/dist/sql/nudges.d.mts.map +1 -0
  92. package/dist/sql/nudges.mjs +484 -0
  93. package/dist/sql/nudges.mjs.map +1 -0
  94. package/dist/sql/permutations.cjs +28 -0
  95. package/dist/sql/permutations.cjs.map +1 -0
  96. package/dist/sql/permutations.mjs +28 -0
  97. package/dist/sql/permutations.mjs.map +1 -0
  98. package/dist/sql/pg-identifier.cjs +216 -0
  99. package/dist/sql/pg-identifier.cjs.map +1 -0
  100. package/dist/sql/pg-identifier.d.cts +31 -0
  101. package/dist/sql/pg-identifier.d.cts.map +1 -0
  102. package/dist/sql/pg-identifier.d.mts +31 -0
  103. package/dist/sql/pg-identifier.d.mts.map +1 -0
  104. package/dist/sql/pg-identifier.mjs +216 -0
  105. package/dist/sql/pg-identifier.mjs.map +1 -0
  106. package/dist/sql/walker.cjs +314 -0
  107. package/dist/sql/walker.cjs.map +1 -0
  108. package/dist/sql/walker.d.cts +15 -0
  109. package/dist/sql/walker.d.cts.map +1 -0
  110. package/dist/sql/walker.d.mts +15 -0
  111. package/dist/sql/walker.d.mts.map +1 -0
  112. package/dist/sql/walker.mjs +313 -0
  113. package/dist/sql/walker.mjs.map +1 -0
  114. package/package.json +2 -1
  115. package/dist/index.cjs.map +0 -1
  116. package/dist/index.d.cts.map +0 -1
  117. package/dist/index.d.mts.map +0 -1
  118. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,314 @@
1
+ "use client";
2
+ require("../_virtual/_rolldown/runtime.cjs");
3
+ const require_ast_utils = require("./ast-utils.cjs");
4
+ const require_nudges = require("./nudges.cjs");
5
+ const require_defineProperty = require("../_virtual/_@oxc-project_runtime@0.122.0/helpers/defineProperty.cjs");
6
+ let pgsql_deparser = require("pgsql-deparser");
7
+ //#region src/sql/walker.ts
8
+ const JSONB_EXTRACTION_OPS = new Set(["->", "->>"]);
9
+ const COMPARISON_OPS = new Set([
10
+ "=",
11
+ "<>",
12
+ "!=",
13
+ "<",
14
+ "<=",
15
+ ">",
16
+ ">=",
17
+ "~~",
18
+ "~~*",
19
+ "!~~",
20
+ "!~~*"
21
+ ]);
22
+ /**
23
+ * Walks the AST of a sql query and extracts query metadata.
24
+ * This pattern is used to segregate the mutable state that's more common for the
25
+ * AST walking process from the rest of the analyzer.
26
+ */
27
+ var Walker = class Walker {
28
+ constructor(query) {
29
+ this.query = query;
30
+ require_defineProperty._defineProperty(this, "tableMappings", /* @__PURE__ */ new Map());
31
+ require_defineProperty._defineProperty(this, "tempTables", /* @__PURE__ */ new Set());
32
+ require_defineProperty._defineProperty(this, "highlights", []);
33
+ require_defineProperty._defineProperty(this, "indexRepresentations", /* @__PURE__ */ new Set());
34
+ require_defineProperty._defineProperty(this, "indexesToCheck", []);
35
+ require_defineProperty._defineProperty(this, "highlightPositions", /* @__PURE__ */ new Set());
36
+ require_defineProperty._defineProperty(this, "seenReferences", /* @__PURE__ */ new Map());
37
+ require_defineProperty._defineProperty(this, "shadowedAliases", []);
38
+ require_defineProperty._defineProperty(this, "nudges", []);
39
+ }
40
+ walk(root) {
41
+ this.tableMappings = /* @__PURE__ */ new Map();
42
+ this.tempTables = /* @__PURE__ */ new Set();
43
+ this.highlights = [];
44
+ this.indexRepresentations = /* @__PURE__ */ new Set();
45
+ this.indexesToCheck = [];
46
+ this.highlightPositions = /* @__PURE__ */ new Set();
47
+ this.seenReferences = /* @__PURE__ */ new Map();
48
+ this.shadowedAliases = [];
49
+ this.nudges = [];
50
+ Walker.traverse(root, (node, stack) => {
51
+ const nodeNudges = require_nudges.parseNudges(node, stack);
52
+ this.nudges = [...this.nudges, ...nodeNudges];
53
+ if (require_ast_utils.is(node, "CommonTableExpr")) {
54
+ if (node.CommonTableExpr.ctename) this.tempTables.add(node.CommonTableExpr.ctename);
55
+ }
56
+ if (require_ast_utils.is(node, "RangeSubselect")) {
57
+ if (node.RangeSubselect.alias?.aliasname) this.tempTables.add(node.RangeSubselect.alias.aliasname);
58
+ }
59
+ if (require_ast_utils.is(node, "NullTest")) {
60
+ if (node.NullTest.arg && node.NullTest.nulltesttype && require_ast_utils.is(node.NullTest.arg, "ColumnRef")) this.add(node.NullTest.arg, { where: { nulltest: node.NullTest.nulltesttype } });
61
+ }
62
+ if (require_ast_utils.is(node, "UpdateStmt")) {
63
+ if (node.UpdateStmt.relation) this.registerTable(node.UpdateStmt.relation);
64
+ }
65
+ if (require_ast_utils.is(node, "DeleteStmt")) {
66
+ if (node.DeleteStmt.relation) this.registerTable(node.DeleteStmt.relation);
67
+ }
68
+ if (require_ast_utils.is(node, "RangeVar") && node.RangeVar.relname) this.registerTable(node.RangeVar);
69
+ if (require_ast_utils.is(node, "SortBy")) {
70
+ if (node.SortBy.node && require_ast_utils.is(node.SortBy.node, "ColumnRef")) this.add(node.SortBy.node, { sort: {
71
+ dir: node.SortBy.sortby_dir ?? "SORTBY_DEFAULT",
72
+ nulls: node.SortBy.sortby_nulls ?? "SORTBY_NULLS_DEFAULT"
73
+ } });
74
+ }
75
+ if (require_ast_utils.is(node, "JoinExpr") && node.JoinExpr.quals) {
76
+ if (require_ast_utils.is(node.JoinExpr.quals, "A_Expr")) {
77
+ if (node.JoinExpr.quals.A_Expr.lexpr && require_ast_utils.is(node.JoinExpr.quals.A_Expr.lexpr, "ColumnRef")) this.add(node.JoinExpr.quals.A_Expr.lexpr);
78
+ if (node.JoinExpr.quals.A_Expr.rexpr && require_ast_utils.is(node.JoinExpr.quals.A_Expr.rexpr, "ColumnRef")) this.add(node.JoinExpr.quals.A_Expr.rexpr);
79
+ }
80
+ }
81
+ if (require_ast_utils.is(node, "A_Expr") && node.A_Expr.kind === "AEXPR_OP") {
82
+ const opName = node.A_Expr.name?.[0] && require_ast_utils.is(node.A_Expr.name[0], "String") && node.A_Expr.name[0].String.sval;
83
+ if (opName && (opName === "@>" || opName === "?" || opName === "?|" || opName === "?&" || opName === "@@" || opName === "@?")) {
84
+ const jsonbOperator = opName;
85
+ if (node.A_Expr.lexpr && require_ast_utils.is(node.A_Expr.lexpr, "ColumnRef")) this.add(node.A_Expr.lexpr, { jsonbOperator });
86
+ if (node.A_Expr.rexpr && require_ast_utils.is(node.A_Expr.rexpr, "ColumnRef")) this.add(node.A_Expr.rexpr, { jsonbOperator });
87
+ }
88
+ if (opName && COMPARISON_OPS.has(opName)) for (const operand of [node.A_Expr.lexpr, node.A_Expr.rexpr]) {
89
+ if (!operand) continue;
90
+ const extraction = extractJsonbPath(operand);
91
+ if (extraction) this.add(extraction.columnRef, { jsonbExtraction: extraction.expression });
92
+ }
93
+ }
94
+ if (require_ast_utils.is(node, "ColumnRef")) {
95
+ for (let i = 0; i < stack.length; i++) {
96
+ if (stack[i] === "returningList" && stack[i + 1] === "ResTarget" && stack[i + 2] === "val" && stack[i + 3] === "ColumnRef") {
97
+ this.add(node, { ignored: true });
98
+ return;
99
+ }
100
+ if (stack[i + 1] === "targetList" && stack[i + 2] === "ResTarget" && stack[i + 3] === "val" && stack[i + 4] === "ColumnRef") {
101
+ this.add(node, { ignored: true });
102
+ return;
103
+ }
104
+ if (stack[i] === "FuncCall" && stack[i + 1] === "args") {
105
+ this.add(node, { ignored: true });
106
+ return;
107
+ }
108
+ }
109
+ this.add(node);
110
+ }
111
+ });
112
+ return {
113
+ highlights: this.highlights,
114
+ indexRepresentations: this.indexRepresentations,
115
+ indexesToCheck: this.indexesToCheck,
116
+ shadowedAliases: this.shadowedAliases,
117
+ tempTables: this.tempTables,
118
+ tableMappings: this.tableMappings,
119
+ nudges: this.nudges
120
+ };
121
+ }
122
+ add(node, options) {
123
+ if (!node.ColumnRef.location) {
124
+ console.error(`Node did not have a location. Skipping`, node);
125
+ return;
126
+ }
127
+ if (!node.ColumnRef.fields) {
128
+ console.error(node);
129
+ throw new Error("Column reference must have fields");
130
+ }
131
+ let ignored = options?.ignored ?? false;
132
+ let runningLength = node.ColumnRef.location;
133
+ const parts = node.ColumnRef.fields.map((field, i, length) => {
134
+ if (!require_ast_utils.is(field, "String") || !field.String.sval) {
135
+ const out = (0, pgsql_deparser.deparseSync)(field);
136
+ ignored = true;
137
+ return {
138
+ quoted: out.startsWith("\""),
139
+ text: out,
140
+ start: runningLength
141
+ };
142
+ }
143
+ const start = runningLength;
144
+ const size = field.String.sval?.length ?? 0;
145
+ let quoted = false;
146
+ if (node.ColumnRef.location !== void 0) {
147
+ if (this.query[runningLength] === "\"") quoted = true;
148
+ }
149
+ const isLastIteration = i === length.length - 1;
150
+ runningLength += size + (isLastIteration ? 0 : 1) + (quoted ? 2 : 0);
151
+ return {
152
+ text: field.String.sval,
153
+ start,
154
+ quoted
155
+ };
156
+ });
157
+ const end = runningLength;
158
+ if (this.highlightPositions.has(node.ColumnRef.location)) return;
159
+ this.highlightPositions.add(node.ColumnRef.location);
160
+ const highlighted = `${this.query.slice(node.ColumnRef.location, end)}`;
161
+ const seen = this.seenReferences.get(highlighted);
162
+ if (!ignored) this.seenReferences.set(highlighted, (seen ?? 0) + 1);
163
+ const ref = {
164
+ frequency: seen ?? 1,
165
+ representation: highlighted,
166
+ parts,
167
+ ignored: ignored ?? false,
168
+ position: {
169
+ start: node.ColumnRef.location,
170
+ end
171
+ }
172
+ };
173
+ if (options?.sort) ref.sort = options.sort;
174
+ if (options?.where) ref.where = options.where;
175
+ if (options?.jsonbOperator) ref.jsonbOperator = options.jsonbOperator;
176
+ if (options?.jsonbExtraction) ref.jsonbExtraction = options.jsonbExtraction;
177
+ this.highlights.push(ref);
178
+ }
179
+ registerTable(rangeVar) {
180
+ if (!rangeVar.relname) return;
181
+ const columnReference = {
182
+ text: rangeVar.relname,
183
+ start: rangeVar.location,
184
+ quoted: false
185
+ };
186
+ if (rangeVar.schemaname) columnReference.schema = rangeVar.schemaname;
187
+ this.tableMappings.set(rangeVar.relname, columnReference);
188
+ if (rangeVar.alias?.aliasname) {
189
+ const aliasName = rangeVar.alias.aliasname;
190
+ const existingMapping = this.tableMappings.get(aliasName);
191
+ const part = {
192
+ text: rangeVar.relname,
193
+ start: rangeVar.location,
194
+ quoted: true,
195
+ alias: aliasName
196
+ };
197
+ if (rangeVar.schemaname) part.schema = rangeVar.schemaname;
198
+ if (existingMapping) {
199
+ if (!(rangeVar.relname?.startsWith("pg_") ?? false)) console.warn(`Ignoring alias ${aliasName} as it shadows an existing mapping for ${existingMapping.text}. We currently do not support alias shadowing.`);
200
+ this.shadowedAliases.push(part);
201
+ return;
202
+ }
203
+ this.tableMappings.set(aliasName, part);
204
+ }
205
+ }
206
+ /**
207
+ * Descend only into shallow combinators of a node such as
208
+ * - And
209
+ * - Or
210
+ * - Not
211
+ * - ::typecast
212
+ * without deep traversing into subqueries. Useful for checking members
213
+ * of a `WHERE` clause
214
+ */
215
+ static shallowMatch(expr, kind, callback) {
216
+ if (require_ast_utils.is(expr, kind)) {
217
+ callback(expr);
218
+ return;
219
+ }
220
+ if (require_ast_utils.is(expr, "BoolExpr") && expr.BoolExpr.args) {
221
+ for (const arg of expr.BoolExpr.args) Walker.shallowMatch(arg, kind, callback);
222
+ return;
223
+ }
224
+ if (require_ast_utils.is(expr, "A_Expr")) {
225
+ if (expr.A_Expr.lexpr) Walker.shallowMatch(expr.A_Expr.lexpr, kind, callback);
226
+ if (expr.A_Expr.rexpr) Walker.shallowMatch(expr.A_Expr.rexpr, kind, callback);
227
+ return;
228
+ }
229
+ if (require_ast_utils.is(expr, "NullTest") && expr.NullTest.arg) {
230
+ Walker.shallowMatch(expr.NullTest.arg, kind, callback);
231
+ return;
232
+ }
233
+ if (require_ast_utils.is(expr, "BooleanTest") && expr.BooleanTest.arg) {
234
+ Walker.shallowMatch(expr.BooleanTest.arg, kind, callback);
235
+ return;
236
+ }
237
+ if (require_ast_utils.is(expr, "SubLink") && expr.SubLink.testexpr) {
238
+ Walker.shallowMatch(expr.SubLink.testexpr, kind, callback);
239
+ return;
240
+ }
241
+ if (require_ast_utils.is(expr, "TypeCast") && expr.TypeCast.arg) {
242
+ Walker.shallowMatch(expr.TypeCast.arg, kind, callback);
243
+ return;
244
+ }
245
+ }
246
+ static traverse(node, callback) {
247
+ Walker.doTraverse(node, [], callback);
248
+ }
249
+ static doTraverse(node, stack, callback) {
250
+ if (require_ast_utils.isANode(node)) callback(node, [...stack, require_ast_utils.getNodeKind(node)]);
251
+ if (typeof node !== "object" || node === null) return;
252
+ if (Array.isArray(node)) {
253
+ for (const item of node) if (require_ast_utils.isANode(item)) Walker.doTraverse(item, stack, callback);
254
+ } else if (require_ast_utils.isANode(node)) {
255
+ const keys = Object.keys(node);
256
+ Walker.doTraverse(node[keys[0]], [...stack, require_ast_utils.getNodeKind(node)], callback);
257
+ } else for (const [key, child] of Object.entries(node)) Walker.doTraverse(child, [...stack, key], callback);
258
+ }
259
+ };
260
+ /**
261
+ * Given an operand of a comparison (e.g. the left side of `=`), check whether
262
+ * it is a JSONB path extraction expression such as `data->>'email'` or
263
+ * `(data->>'age')::int`. If so, return the root ColumnRef (for the walker to
264
+ * register) and the full expression string (for use in the expression index).
265
+ *
266
+ * Handles:
267
+ * - `data->>'email'` — simple extraction
268
+ * - `(data->>'age')::int` — extraction with cast
269
+ * - `data->'addr'->>'city'` — chained extraction
270
+ * - `t.data->>'email'` — table-qualified (strips qualifier from expression)
271
+ */
272
+ function extractJsonbPath(node) {
273
+ let exprNode = node;
274
+ if (require_ast_utils.is(exprNode, "TypeCast") && exprNode.TypeCast.arg) exprNode = exprNode.TypeCast.arg;
275
+ if (!require_ast_utils.is(exprNode, "A_Expr") || exprNode.A_Expr.kind !== "AEXPR_OP") return;
276
+ const innerOp = exprNode.A_Expr.name?.[0] && require_ast_utils.is(exprNode.A_Expr.name[0], "String") && exprNode.A_Expr.name[0].String.sval;
277
+ if (!innerOp || !JSONB_EXTRACTION_OPS.has(innerOp)) return;
278
+ const rootCol = findRootColumnRef(exprNode);
279
+ if (!rootCol) return;
280
+ const cloned = JSON.parse(JSON.stringify(node));
281
+ stripTableQualifiers(cloned);
282
+ return {
283
+ columnRef: rootCol,
284
+ expression: (0, pgsql_deparser.deparseSync)(cloned)
285
+ };
286
+ }
287
+ /**
288
+ * Walk the left side of a chain of `->` / `->>` operators to find the
289
+ * root ColumnRef (the JSONB column itself).
290
+ */
291
+ function findRootColumnRef(node) {
292
+ if (require_ast_utils.is(node, "ColumnRef")) return node;
293
+ if (require_ast_utils.is(node, "A_Expr") && node.A_Expr.lexpr) return findRootColumnRef(node.A_Expr.lexpr);
294
+ if (require_ast_utils.is(node, "TypeCast") && node.TypeCast.arg) return findRootColumnRef(node.TypeCast.arg);
295
+ }
296
+ /**
297
+ * Remove table/schema qualifiers from ColumnRef nodes inside the
298
+ * expression so the deparsed expression contains only the column name.
299
+ * e.g. `t.data->>'email'` → `data->>'email'`
300
+ */
301
+ function stripTableQualifiers(node) {
302
+ if (typeof node !== "object" || node === null) return;
303
+ if ("ColumnRef" in node && node.ColumnRef?.fields) {
304
+ const fields = node.ColumnRef.fields;
305
+ if (fields.length > 1) node.ColumnRef.fields = [fields[fields.length - 1]];
306
+ return;
307
+ }
308
+ for (const value of Object.values(node)) if (Array.isArray(value)) for (const item of value) stripTableQualifiers(item);
309
+ else if (typeof value === "object" && value !== null) stripTableQualifiers(value);
310
+ }
311
+ //#endregion
312
+ exports.Walker = Walker;
313
+
314
+ //# sourceMappingURL=walker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.cjs","names":["parseNudges","is","isANode","getNodeKind"],"sources":["../../src/sql/walker.ts"],"sourcesContent":["import type { Node, NullTestType, RangeVar } from \"@pgsql/types\";\nimport { deparseSync } from \"pgsql-deparser\";\nimport type {\n DiscoveredColumnReference,\n JsonbOperator,\n SortContext,\n} from \"./analyzer.js\";\nimport { getNodeKind, is, isANode, type KeysOfUnion } from \"./ast-utils.js\";\nimport { parseNudges } from \"./nudges.js\";\nimport type { Nudge } from \"./nudges.js\";\n\nconst JSONB_EXTRACTION_OPS = new Set([\"->\", \"->>\"]);\nconst COMPARISON_OPS = new Set([\n \"=\",\n \"<>\",\n \"!=\",\n \"<\",\n \"<=\",\n \">\",\n \">=\",\n \"~~\",\n \"~~*\",\n \"!~~\",\n \"!~~*\",\n]);\n\n/** Information about tables that appear in the query */\nexport type TableMappings = Map<string, ColumnReferencePart>;\ntype SeenReferences = Map<string, number>;\n\n/**\n * Walks the AST of a sql query and extracts query metadata.\n * This pattern is used to segregate the mutable state that's more common for the\n * AST walking process from the rest of the analyzer.\n */\nexport class Walker {\n private tableMappings: TableMappings = new Map();\n private tempTables = new Set<string>();\n private highlights: DiscoveredColumnReference[] = [];\n private indexRepresentations = new Set<string>();\n private indexesToCheck: DiscoveredColumnReference[] = [];\n private highlightPositions = new Set<number>();\n // used for tallying the amount of times we see stuff so\n // we have a better idea of what to start off the algorithm with\n private seenReferences: SeenReferences = new Map();\n private shadowedAliases: ColumnReferencePart[] = [];\n private nudges: Nudge[] = [];\n\n constructor(private readonly query: string) {}\n\n walk(root: Node) {\n // reset state in case the class instance is reused\n // reassigning vars here instead of using `map.clear()` to prevent\n // accidentally mutating existing references\n this.tableMappings = new Map();\n this.tempTables = new Set<string>();\n this.highlights = [];\n this.indexRepresentations = new Set<string>();\n this.indexesToCheck = [];\n this.highlightPositions = new Set<number>();\n this.seenReferences = new Map();\n this.shadowedAliases = [];\n this.nudges = [];\n\n Walker.traverse(root, (node, stack) => {\n const nodeNudges = parseNudges(node, stack);\n this.nudges = [...this.nudges, ...nodeNudges];\n\n // comments are not parsed here as they seem to be ignored.\n //\n // results cannot be indexed in any way because they alias a CTE\n // with alias as (select ...)\n // ^^^^^\n if (is(node, \"CommonTableExpr\")) {\n if (node.CommonTableExpr.ctename) {\n this.tempTables.add(node.CommonTableExpr.ctename);\n }\n }\n // results cannot be indexed in any way because they alias a subquery\n // select ... from (...) as alias\n // ^^^^^\n if (is(node, \"RangeSubselect\")) {\n if (node.RangeSubselect.alias?.aliasname) {\n this.tempTables.add(node.RangeSubselect.alias.aliasname);\n }\n }\n // select ... from (...) where col is null\n // ^^^^^^^\n if (is(node, \"NullTest\")) {\n if (\n node.NullTest.arg &&\n node.NullTest.nulltesttype &&\n is(node.NullTest.arg, \"ColumnRef\")\n ) {\n this.add(node.NullTest.arg, {\n where: { nulltest: node.NullTest.nulltesttype },\n });\n }\n }\n // The parser does not wrap the `relation` field of UpdateStmt\n // in a { RangeVar: ... } node (it's a raw RangeVar struct), so the\n // generic RangeVar handler below never sees it. Handle it explicitly.\n if (is(node, \"UpdateStmt\")) {\n if (node.UpdateStmt.relation) {\n this.registerTable(node.UpdateStmt.relation);\n }\n }\n // Same as UpdateStmt: DeleteStmt.relation is a raw RangeVar struct.\n if (is(node, \"DeleteStmt\")) {\n if (node.DeleteStmt.relation) {\n this.registerTable(node.DeleteStmt.relation);\n }\n }\n // can be indexed as the alias refers to a regular table\n // but the alias has to be mapped to the original table name\n // select ... from table as alias\n // ^^^^^\n if (is(node, \"RangeVar\") && node.RangeVar.relname) {\n this.registerTable(node.RangeVar);\n }\n // select ... from table order by col asc\n // ^^^^^^^^^^^^^^^^\n if (is(node, \"SortBy\")) {\n // we don't care about sorting by anything that's not a column reference\n // because it couldn't be indexed anyway.\n // TODO: mark that expression as unindexable? It's just better for debugging\n if (node.SortBy.node && is(node.SortBy.node, \"ColumnRef\")) {\n this.add(node.SortBy.node, {\n sort: {\n dir: node.SortBy.sortby_dir ?? \"SORTBY_DEFAULT\",\n nulls: node.SortBy.sortby_nulls ?? \"SORTBY_NULLS_DEFAULT\",\n },\n });\n }\n }\n // select ... from table1 join table2 t2 on table1.col = t2.col\n // ^^\n if (is(node, \"JoinExpr\") && node.JoinExpr.quals) {\n if (is(node.JoinExpr.quals, \"A_Expr\")) {\n if (\n node.JoinExpr.quals.A_Expr.lexpr &&\n is(node.JoinExpr.quals.A_Expr.lexpr, \"ColumnRef\")\n ) {\n this.add(node.JoinExpr.quals.A_Expr.lexpr);\n }\n if (\n node.JoinExpr.quals.A_Expr.rexpr &&\n is(node.JoinExpr.quals.A_Expr.rexpr, \"ColumnRef\")\n ) {\n this.add(node.JoinExpr.quals.A_Expr.rexpr);\n }\n }\n }\n // select ... from table where data @> '{\"key\": \"val\"}'\n // ^^^^\n if (is(node, \"A_Expr\") && node.A_Expr.kind === \"AEXPR_OP\") {\n const opName =\n node.A_Expr.name?.[0] &&\n is(node.A_Expr.name[0], \"String\") &&\n node.A_Expr.name[0].String.sval;\n if (\n opName &&\n (opName === \"@>\" ||\n opName === \"?\" ||\n opName === \"?|\" ||\n opName === \"?&\" ||\n opName === \"@@\" ||\n opName === \"@?\")\n ) {\n const jsonbOperator = opName as JsonbOperator;\n if (node.A_Expr.lexpr && is(node.A_Expr.lexpr, \"ColumnRef\")) {\n this.add(node.A_Expr.lexpr, { jsonbOperator });\n }\n if (node.A_Expr.rexpr && is(node.A_Expr.rexpr, \"ColumnRef\")) {\n this.add(node.A_Expr.rexpr, { jsonbOperator });\n }\n }\n // select ... from table where data->>'email' = 'alice@example.com'\n // ^^^^^^^^^^^^^^\n if (opName && COMPARISON_OPS.has(opName)) {\n for (const operand of [node.A_Expr.lexpr, node.A_Expr.rexpr]) {\n if (!operand) continue;\n const extraction = extractJsonbPath(operand);\n if (extraction) {\n this.add(extraction.columnRef, {\n jsonbExtraction: extraction.expression,\n });\n }\n }\n }\n }\n // any column reference anywhere\n if (is(node, \"ColumnRef\")) {\n // TODO: this approach needs refinement\n for (let i = 0; i < stack.length; i++) {\n const inReturningList =\n stack[i] === \"returningList\" &&\n stack[i + 1] === \"ResTarget\" &&\n stack[i + 2] === \"val\" &&\n stack[i + 3] === \"ColumnRef\";\n if (inReturningList) {\n this.add(node, { ignored: true });\n return;\n }\n if (\n // stack[i] === \"SelectStmt\" &&\n stack[i + 1] === \"targetList\" &&\n stack[i + 2] === \"ResTarget\" &&\n stack[i + 3] === \"val\" &&\n stack[i + 4] === \"ColumnRef\"\n ) {\n // we don't want to index the columns that are being selected\n this.add(node, { ignored: true });\n return;\n }\n\n // TODO: add functional index support here\n if (stack[i] === \"FuncCall\" && stack[i + 1] === \"args\") {\n // args of a function call can't be indexed (without functional indexes)\n this.add(node, { ignored: true });\n return;\n }\n }\n this.add(node);\n }\n });\n\n return {\n highlights: this.highlights,\n indexRepresentations: this.indexRepresentations,\n indexesToCheck: this.indexesToCheck,\n shadowedAliases: this.shadowedAliases,\n tempTables: this.tempTables,\n tableMappings: this.tableMappings,\n nudges: this.nudges,\n };\n }\n\n private add(\n node: Extract<Node, { ColumnRef: unknown }>,\n options?: {\n ignored?: boolean;\n sort?: SortContext;\n where?: { nulltest?: NullTestType };\n jsonbOperator?: JsonbOperator;\n jsonbExtraction?: string;\n },\n ) {\n if (!node.ColumnRef.location) {\n console.error(`Node did not have a location. Skipping`, node);\n return;\n }\n if (!node.ColumnRef.fields) {\n console.error(node);\n throw new Error(\"Column reference must have fields\");\n }\n let ignored = options?.ignored ?? false;\n let runningLength: number = node.ColumnRef.location;\n const parts: ColumnReferencePart[] = node.ColumnRef.fields.map(\n (field, i, length) => {\n if (!is(field, \"String\") || !field.String.sval) {\n const out = deparseSync(field);\n ignored = true;\n return {\n quoted: out.startsWith('\"'),\n text: out,\n start: runningLength,\n };\n }\n const start = runningLength;\n const size = field.String.sval?.length ?? 0;\n let quoted = false;\n if (node.ColumnRef.location !== undefined) {\n const boundary = this.query[runningLength];\n if (boundary === '\"') {\n quoted = true;\n }\n }\n // +1 for the dot that comes after\n const isLastIteration = i === length.length - 1;\n runningLength += size + (isLastIteration ? 0 : 1) + (quoted ? 2 : 0);\n return {\n text: field.String.sval,\n start,\n quoted,\n };\n },\n );\n const end = runningLength;\n if (this.highlightPositions.has(node.ColumnRef.location)) {\n return;\n }\n this.highlightPositions.add(node.ColumnRef.location);\n const highlighted = `${this.query.slice(node.ColumnRef.location, end)}`;\n const seen = this.seenReferences.get(highlighted);\n if (!ignored) {\n this.seenReferences.set(highlighted, (seen ?? 0) + 1);\n }\n const ref: DiscoveredColumnReference = {\n frequency: seen ?? 1,\n representation: highlighted,\n parts,\n ignored: ignored ?? false,\n position: {\n start: node.ColumnRef.location,\n end,\n },\n };\n if (options?.sort) {\n ref.sort = options.sort;\n }\n if (options?.where) {\n ref.where = options.where;\n }\n if (options?.jsonbOperator) {\n ref.jsonbOperator = options.jsonbOperator;\n }\n if (options?.jsonbExtraction) {\n ref.jsonbExtraction = options.jsonbExtraction;\n }\n this.highlights.push(ref);\n }\n\n private registerTable(rangeVar: RangeVar) {\n if (!rangeVar.relname) return;\n\n const columnReference: ColumnReferencePart = {\n text: rangeVar.relname,\n start: rangeVar.location,\n quoted: false,\n };\n if (rangeVar.schemaname) {\n columnReference.schema = rangeVar.schemaname;\n }\n this.tableMappings.set(rangeVar.relname, columnReference);\n\n if (rangeVar.alias?.aliasname) {\n const aliasName = rangeVar.alias.aliasname;\n const existingMapping = this.tableMappings.get(aliasName);\n const part: ColumnReferencePart = {\n text: rangeVar.relname,\n start: rangeVar.location,\n quoted: true,\n alias: aliasName,\n };\n if (rangeVar.schemaname) {\n part.schema = rangeVar.schemaname;\n }\n if (existingMapping) {\n const isSystemCatalog = rangeVar.relname?.startsWith(\"pg_\") ?? false;\n if (!isSystemCatalog) {\n console.warn(\n `Ignoring alias ${aliasName} as it shadows an existing mapping for ${existingMapping.text}. We currently do not support alias shadowing.`,\n );\n }\n this.shadowedAliases.push(part);\n return;\n }\n this.tableMappings.set(aliasName, part);\n }\n }\n\n /**\n * Descend only into shallow combinators of a node such as\n * - And\n * - Or\n * - Not\n * - ::typecast\n * without deep traversing into subqueries. Useful for checking members\n * of a `WHERE` clause\n */\n static shallowMatch<K extends KeysOfUnion<Node>>(\n expr: Node,\n kind: K,\n callback: (node: Extract<Node, Record<K, unknown>>) => void,\n ) {\n if (is(expr, kind)) {\n callback(expr as Extract<Node, Record<K, unknown>>);\n return;\n }\n if (is(expr, \"BoolExpr\") && expr.BoolExpr.args) {\n for (const arg of expr.BoolExpr.args) {\n Walker.shallowMatch(arg, kind, callback);\n }\n return;\n }\n if (is(expr, \"A_Expr\")) {\n if (expr.A_Expr.lexpr)\n Walker.shallowMatch(expr.A_Expr.lexpr, kind, callback);\n if (expr.A_Expr.rexpr)\n Walker.shallowMatch(expr.A_Expr.rexpr, kind, callback);\n return;\n }\n if (is(expr, \"NullTest\") && expr.NullTest.arg) {\n Walker.shallowMatch(expr.NullTest.arg, kind, callback);\n return;\n }\n if (is(expr, \"BooleanTest\") && expr.BooleanTest.arg) {\n Walker.shallowMatch(expr.BooleanTest.arg, kind, callback);\n return;\n }\n if (is(expr, \"SubLink\") && expr.SubLink.testexpr) {\n Walker.shallowMatch(expr.SubLink.testexpr, kind, callback);\n return;\n }\n if (is(expr, \"TypeCast\") && expr.TypeCast.arg) {\n Walker.shallowMatch(expr.TypeCast.arg, kind, callback);\n return;\n }\n }\n\n static traverse(\n node: Node,\n callback: (node: Node, stack: (KeysOfUnion<Node> | string)[]) => void,\n ) {\n Walker.doTraverse(node, [], callback);\n }\n\n private static doTraverse(\n node: unknown,\n stack: (KeysOfUnion<Node> | string)[],\n callback: (node: Node, stack: (KeysOfUnion<Node> | string)[]) => void,\n ) {\n if (isANode(node)) {\n callback(node, [...stack, getNodeKind(node)]);\n }\n if (typeof node !== \"object\" || node === null) {\n return;\n }\n if (Array.isArray(node)) {\n for (const item of node) {\n if (isANode(item)) {\n Walker.doTraverse(item, stack, callback);\n }\n }\n } else if (isANode(node)) {\n const keys = Object.keys(node);\n // @ts-expect-error | nodes don't allow dynamic access but it's the only way to do it\n Walker.doTraverse(node[keys[0]], [...stack, getNodeKind(node)], callback);\n } else {\n for (const [key, child] of Object.entries(node)) {\n Walker.doTraverse(\n child,\n [...stack, key as KeysOfUnion<Node>],\n callback,\n );\n }\n }\n }\n}\n\nexport type ColumnReferencePart = {\n schema?: string;\n /** the text of the column reference (excluding any potential quotes) */\n text: string;\n start?: number;\n quoted: boolean;\n alias?: string;\n};\n\ntype JsonbExtraction = {\n columnRef: Extract<Node, { ColumnRef: unknown }>;\n expression: string;\n};\n\n/**\n * Given an operand of a comparison (e.g. the left side of `=`), check whether\n * it is a JSONB path extraction expression such as `data->>'email'` or\n * `(data->>'age')::int`. If so, return the root ColumnRef (for the walker to\n * register) and the full expression string (for use in the expression index).\n *\n * Handles:\n * - `data->>'email'` — simple extraction\n * - `(data->>'age')::int` — extraction with cast\n * - `data->'addr'->>'city'` — chained extraction\n * - `t.data->>'email'` — table-qualified (strips qualifier from expression)\n */\nfunction extractJsonbPath(node: Node): JsonbExtraction | undefined {\n let exprNode = node;\n // Unwrap TypeCast (e.g. `(data->>'age')::int`)\n if (is(exprNode, \"TypeCast\") && exprNode.TypeCast.arg) {\n exprNode = exprNode.TypeCast.arg;\n }\n if (!is(exprNode, \"A_Expr\") || exprNode.A_Expr.kind !== \"AEXPR_OP\") {\n return undefined;\n }\n const innerOp =\n exprNode.A_Expr.name?.[0] &&\n is(exprNode.A_Expr.name[0], \"String\") &&\n exprNode.A_Expr.name[0].String.sval;\n if (!innerOp || !JSONB_EXTRACTION_OPS.has(innerOp)) {\n return undefined;\n }\n const rootCol = findRootColumnRef(exprNode);\n if (!rootCol) {\n return undefined;\n }\n // Deep-clone the whole outer node so we can strip qualifiers without\n // mutating the original AST.\n const cloned: Node = JSON.parse(JSON.stringify(node));\n stripTableQualifiers(cloned);\n const expression = deparseSync(cloned);\n return { columnRef: rootCol, expression };\n}\n\n/**\n * Walk the left side of a chain of `->` / `->>` operators to find the\n * root ColumnRef (the JSONB column itself).\n */\nfunction findRootColumnRef(\n node: Node,\n): Extract<Node, { ColumnRef: unknown }> | undefined {\n if (is(node, \"ColumnRef\")) {\n return node;\n }\n if (is(node, \"A_Expr\") && node.A_Expr.lexpr) {\n return findRootColumnRef(node.A_Expr.lexpr);\n }\n if (is(node, \"TypeCast\") && node.TypeCast.arg) {\n return findRootColumnRef(node.TypeCast.arg);\n }\n return undefined;\n}\n\n/**\n * Remove table/schema qualifiers from ColumnRef nodes inside the\n * expression so the deparsed expression contains only the column name.\n * e.g. `t.data->>'email'` → `data->>'email'`\n */\nfunction stripTableQualifiers(node: unknown): void {\n if (typeof node !== \"object\" || node === null) return;\n if (\n \"ColumnRef\" in (node as Record<string, unknown>) &&\n (node as any).ColumnRef?.fields\n ) {\n const fields: unknown[] = (node as any).ColumnRef.fields;\n if (fields.length > 1) {\n (node as any).ColumnRef.fields = [fields[fields.length - 1]];\n }\n return;\n }\n for (const value of Object.values(node as Record<string, unknown>)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n stripTableQualifiers(item);\n }\n } else if (typeof value === \"object\" && value !== null) {\n stripTableQualifiers(value);\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+
3
+ import { Node } from "@pgsql/types";
4
+
5
+ //#region src/sql/walker.d.ts
6
+ type ColumnReferencePart = {
7
+ schema?: string; /** the text of the column reference (excluding any potential quotes) */
8
+ text: string;
9
+ start?: number;
10
+ quoted: boolean;
11
+ alias?: string;
12
+ };
13
+ //#endregion
14
+ export { ColumnReferencePart };
15
+ //# sourceMappingURL=walker.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.d.cts","names":[],"sources":["../../src/sql/walker.ts"],"mappings":";;;;;KAmcY,mBAAA;EACV,MAAA;EAEA,IAAA;EACA,KAAA;EACA,MAAA;EACA,KAAA;AAAA"}
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+
3
+ import { Node } from "@pgsql/types";
4
+
5
+ //#region src/sql/walker.d.ts
6
+ type ColumnReferencePart = {
7
+ schema?: string; /** the text of the column reference (excluding any potential quotes) */
8
+ text: string;
9
+ start?: number;
10
+ quoted: boolean;
11
+ alias?: string;
12
+ };
13
+ //#endregion
14
+ export { ColumnReferencePart };
15
+ //# sourceMappingURL=walker.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"walker.d.mts","names":[],"sources":["../../src/sql/walker.ts"],"mappings":";;;;;KAmcY,mBAAA;EACV,MAAA;EAEA,IAAA;EACA,KAAA;EACA,MAAA;EACA,KAAA;AAAA"}