@query-doctor/core 0.1.7 → 0.1.10

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/dist/index.js CHANGED
@@ -139,6 +139,23 @@ function parseNudges(node, stack) {
139
139
  });
140
140
  }
141
141
  }
142
+ if (is(node, "A_Expr")) {
143
+ if (node.A_Expr.kind === "AEXPR_IN") {
144
+ let list;
145
+ if (node.A_Expr.lexpr && is(node.A_Expr.lexpr, "List")) {
146
+ list = node.A_Expr.lexpr.List;
147
+ } else if (node.A_Expr.rexpr && is(node.A_Expr.rexpr, "List")) {
148
+ list = node.A_Expr.rexpr.List;
149
+ }
150
+ if (list?.items && list.items.length >= 10) {
151
+ nudges.push({
152
+ kind: "REPLACE_LARGE_IN_TUPLE_WITH_ANY_ARRAY",
153
+ message: "`in (...)` queries with large tuples can often be replaced with `= ANY($1)` using a single parameter",
154
+ severity: "INFO"
155
+ });
156
+ }
157
+ }
158
+ }
142
159
  return nudges;
143
160
  }
144
161
  function containsColumnRef(args) {
@@ -294,9 +311,12 @@ var Walker = class _Walker {
294
311
  part.schema = node.RangeVar.schemaname;
295
312
  }
296
313
  if (existingMapping) {
297
- console.warn(
298
- `Ignoring alias ${aliasName} as it shadows an existing mapping for ${existingMapping.text}. We currently do not support alias shadowing.`
299
- );
314
+ const isSystemCatalog = node.RangeVar.relname?.startsWith("pg_") ?? false;
315
+ if (!isSystemCatalog) {
316
+ console.warn(
317
+ `Ignoring alias ${aliasName} as it shadows an existing mapping for ${existingMapping.text}. We currently do not support alias shadowing.`
318
+ );
319
+ }
300
320
  this.shadowedAliases.push(part);
301
321
  return;
302
322
  }
@@ -694,7 +714,7 @@ var Analyzer = class {
694
714
  return { tags: [], queryWithoutTags: trimmedQuery };
695
715
  }
696
716
  const queryWithoutTags = trimmedQuery.slice(0, startPosition);
697
- const tagString = trimmedQuery.slice(startPosition + 2, endPosition);
717
+ const tagString = trimmedQuery.slice(startPosition + 2, endPosition).trim();
698
718
  if (!tagString || typeof tagString !== "string") {
699
719
  return { tags: [], queryWithoutTags };
700
720
  }
@@ -702,7 +722,11 @@ var Analyzer = class {
702
722
  for (const match of tagString.split(",")) {
703
723
  const [key, value] = match.split("=");
704
724
  if (!key || !value) {
705
- console.warn(`Invalid sqlcommenter tag: ${match}. Ignoring`);
725
+ if (tags.length > 0) {
726
+ console.warn(
727
+ `Invalid sqlcommenter tag: ${match} in comment: ${tagString}. Ignoring`
728
+ );
729
+ }
706
730
  continue;
707
731
  }
708
732
  try {
@@ -1108,6 +1132,24 @@ var _IndexOptimizer = class _IndexOptimizer {
1108
1132
  await this.dropExistingIndexes(tx);
1109
1133
  });
1110
1134
  }
1135
+ /**
1136
+ * Given the current indexes in the optimizer, transform them in some
1137
+ * way to change which indexes will be assumed to exist when optimizing
1138
+ *
1139
+ * @example
1140
+ * ```
1141
+ * // resets indexes
1142
+ * optimizer.transformIndexes(() => [])
1143
+ *
1144
+ * // adds new index
1145
+ * optimizer.transformIndexes(indexes => [...indexes, newIndex])
1146
+ * ```
1147
+ */
1148
+ transformIndexes(f) {
1149
+ const newIndexes = f(this.existingIndexes);
1150
+ this.existingIndexes = newIndexes;
1151
+ return this;
1152
+ }
1111
1153
  /**
1112
1154
  * Postgres has a limit of 63 characters for index names.
1113
1155
  * So we use this to make sure we don't derive it from a list of columns that can