@query-doctor/core 0.2.4 → 0.3.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/dist/index.cjs +58 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +57 -32
- package/dist/index.js.map +1 -1
- package/dist/optimizer/genalgo.d.ts +1 -6
- package/dist/optimizer/genalgo.d.ts.map +1 -1
- package/dist/sql/builder.d.ts +6 -0
- package/dist/sql/builder.d.ts.map +1 -1
- package/dist/sql/permutations.d.ts +10 -0
- package/dist/sql/permutations.d.ts.map +1 -0
- package/dist/sql/pg-identifier.d.ts.map +1 -1
- package/package.json +7 -4
- package/dist/optimizer/pss-rewriter.test.d.ts +0 -2
- package/dist/optimizer/pss-rewriter.test.d.ts.map +0 -1
- package/dist/sql/analyzer.test.d.ts +0 -2
- package/dist/sql/analyzer.test.d.ts.map +0 -1
- package/dist/sql/permutations.test.d.ts +0 -2
- package/dist/sql/permutations.test.d.ts.map +0 -1
- package/dist/sql/pg-identifier.test.d.ts +0 -2
- package/dist/sql/pg-identifier.test.d.ts.map +0 -1
- package/dist/sql/walker.test.d.ts +0 -2
- package/dist/sql/walker.test.d.ts.map +0 -1
- package/tsconfig.json +0 -12
package/dist/index.js
CHANGED
|
@@ -780,6 +780,9 @@ var PostgresQueryBuilder = class _PostgresQueryBuilder {
|
|
|
780
780
|
__publicField(this, "isIntrospection", false);
|
|
781
781
|
__publicField(this, "explainFlags", []);
|
|
782
782
|
__publicField(this, "_preamble", 0);
|
|
783
|
+
__publicField(this, "parameters", {});
|
|
784
|
+
// substitution for `limit $1` -> `limit 5`
|
|
785
|
+
__publicField(this, "limitSubstitution");
|
|
783
786
|
}
|
|
784
787
|
get preamble() {
|
|
785
788
|
return this._preamble;
|
|
@@ -813,6 +816,14 @@ var PostgresQueryBuilder = class _PostgresQueryBuilder {
|
|
|
813
816
|
this.explainFlags = flags;
|
|
814
817
|
return this;
|
|
815
818
|
}
|
|
819
|
+
parameterize(parameters) {
|
|
820
|
+
Object.assign(this.parameters, parameters);
|
|
821
|
+
return this;
|
|
822
|
+
}
|
|
823
|
+
replaceLimit(limit) {
|
|
824
|
+
this.limitSubstitution = limit;
|
|
825
|
+
return this;
|
|
826
|
+
}
|
|
816
827
|
build() {
|
|
817
828
|
let commands = this.generateSetCommands();
|
|
818
829
|
commands += this.generateExplain().query;
|
|
@@ -841,14 +852,28 @@ var PostgresQueryBuilder = class _PostgresQueryBuilder {
|
|
|
841
852
|
return commands;
|
|
842
853
|
}
|
|
843
854
|
generateExplain() {
|
|
844
|
-
let
|
|
855
|
+
let finalQuery = "";
|
|
845
856
|
if (this.explainFlags.length > 0) {
|
|
846
|
-
|
|
857
|
+
finalQuery += `explain (${this.explainFlags.join(", ")}) `;
|
|
858
|
+
}
|
|
859
|
+
const query = this.substituteQuery();
|
|
860
|
+
const semicolon = query.endsWith(";") ? "" : ";";
|
|
861
|
+
const preamble = finalQuery.length;
|
|
862
|
+
finalQuery += `${query}${semicolon}`;
|
|
863
|
+
return { query: finalQuery, preamble };
|
|
864
|
+
}
|
|
865
|
+
substituteQuery() {
|
|
866
|
+
let query = this.query;
|
|
867
|
+
if (this.limitSubstitution !== void 0) {
|
|
868
|
+
query = query.replace(
|
|
869
|
+
/limit\s+\$\d+/g,
|
|
870
|
+
`limit ${this.limitSubstitution}`
|
|
871
|
+
);
|
|
847
872
|
}
|
|
848
|
-
const
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
return
|
|
873
|
+
for (const [key, value] of Object.entries(this.parameters)) {
|
|
874
|
+
query = query.replaceAll(`\\$${key}`, value.toString());
|
|
875
|
+
}
|
|
876
|
+
return query;
|
|
852
877
|
}
|
|
853
878
|
};
|
|
854
879
|
|
|
@@ -866,7 +891,9 @@ var _PgIdentifier = class _PgIdentifier {
|
|
|
866
891
|
const identifierRegex = /^[a-z_][a-zA-Z0-9_]*$/;
|
|
867
892
|
const match = identifier.match(/^"(.+)"$/);
|
|
868
893
|
if (match) {
|
|
869
|
-
|
|
894
|
+
const value = match[1];
|
|
895
|
+
const quoted2 = !identifierRegex.test(value) || this.reservedKeywords.has(value.toLowerCase());
|
|
896
|
+
return new _PgIdentifier(value, quoted2);
|
|
870
897
|
}
|
|
871
898
|
const quoted = !identifierRegex.test(identifier) || this.reservedKeywords.has(identifier.toLowerCase());
|
|
872
899
|
return new _PgIdentifier(identifier, quoted);
|
|
@@ -1071,6 +1098,24 @@ var PgIdentifier = _PgIdentifier;
|
|
|
1071
1098
|
|
|
1072
1099
|
// src/optimizer/genalgo.ts
|
|
1073
1100
|
import { blue as blue2, gray, green, magenta, red, yellow } from "colorette";
|
|
1101
|
+
|
|
1102
|
+
// src/sql/permutations.ts
|
|
1103
|
+
function permutationsWithDescendingLength(arr) {
|
|
1104
|
+
const collected = [];
|
|
1105
|
+
function collect(path, rest) {
|
|
1106
|
+
for (let i = 0; i < rest.length; i++) {
|
|
1107
|
+
const nextRest = [...rest.slice(0, i), ...rest.slice(i + 1)];
|
|
1108
|
+
const nextPath = [...path, rest[i]];
|
|
1109
|
+
collected.push(nextPath);
|
|
1110
|
+
collect(nextPath, nextRest);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
collect([], arr);
|
|
1114
|
+
collected.sort((a, b) => b.length - a.length);
|
|
1115
|
+
return collected;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
// src/optimizer/genalgo.ts
|
|
1074
1119
|
var _IndexOptimizer = class _IndexOptimizer {
|
|
1075
1120
|
constructor(db, statistics, existingIndexes, config = {}) {
|
|
1076
1121
|
this.db = db;
|
|
@@ -1203,14 +1248,12 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
1203
1248
|
* Derive the list of indexes [tableA(X, Y, Z), tableB(H, I, J)]
|
|
1204
1249
|
**/
|
|
1205
1250
|
indexesToCreate(rootCandidates) {
|
|
1206
|
-
const permutedIndexes = this.
|
|
1251
|
+
const permutedIndexes = this.groupPotentialIndexColumnsByTable(rootCandidates);
|
|
1207
1252
|
const nextStage = [];
|
|
1208
1253
|
for (const permutation of permutedIndexes.values()) {
|
|
1209
1254
|
const { table: rawTable, schema: rawSchema, columns } = permutation;
|
|
1210
|
-
const permutations =
|
|
1211
|
-
|
|
1212
|
-
while (!iter.done) {
|
|
1213
|
-
const columns2 = iter.value;
|
|
1255
|
+
const permutations = permutationsWithDescendingLength(columns);
|
|
1256
|
+
for (const columns2 of permutations) {
|
|
1214
1257
|
const schema = PgIdentifier.fromString(rawSchema);
|
|
1215
1258
|
const table = PgIdentifier.fromString(rawTable);
|
|
1216
1259
|
const existingIndex = this.indexAlreadyExists(
|
|
@@ -1218,12 +1261,10 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
1218
1261
|
columns2
|
|
1219
1262
|
);
|
|
1220
1263
|
if (existingIndex) {
|
|
1221
|
-
iter = permutations.next(PROCEED);
|
|
1222
1264
|
continue;
|
|
1223
1265
|
}
|
|
1224
1266
|
const indexName = this.indexName();
|
|
1225
1267
|
const definition = this.toDefinition({ table, schema, columns: columns2 }).raw;
|
|
1226
|
-
iter = permutations.next(PROCEED);
|
|
1227
1268
|
nextStage.push({
|
|
1228
1269
|
name: indexName,
|
|
1229
1270
|
schema: schema.toString(),
|
|
@@ -1355,7 +1396,7 @@ var _IndexOptimizer = class _IndexOptimizer {
|
|
|
1355
1396
|
}
|
|
1356
1397
|
throw new Error("Unreachable");
|
|
1357
1398
|
}
|
|
1358
|
-
|
|
1399
|
+
groupPotentialIndexColumnsByTable(indexes) {
|
|
1359
1400
|
const tableColumns = /* @__PURE__ */ new Map();
|
|
1360
1401
|
for (const index of indexes) {
|
|
1361
1402
|
const existing = tableColumns.get(`${index.schema}.${index.table}`);
|
|
@@ -1425,21 +1466,6 @@ var RollbackError = class {
|
|
|
1425
1466
|
};
|
|
1426
1467
|
var PROCEED = Symbol("PROCEED");
|
|
1427
1468
|
var SKIP = Symbol("SKIP");
|
|
1428
|
-
function* permuteWithFeedback(arr) {
|
|
1429
|
-
function* helper(path, rest) {
|
|
1430
|
-
let i = 0;
|
|
1431
|
-
while (i < rest.length) {
|
|
1432
|
-
const nextPath = [...path, rest[i]];
|
|
1433
|
-
const nextRest = [...rest.slice(0, i), ...rest.slice(i + 1)];
|
|
1434
|
-
const input = yield nextPath;
|
|
1435
|
-
if (input === PROCEED) {
|
|
1436
|
-
yield* helper(nextPath, nextRest);
|
|
1437
|
-
}
|
|
1438
|
-
i++;
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
yield* helper([], arr);
|
|
1442
|
-
}
|
|
1443
1469
|
|
|
1444
1470
|
// src/optimizer/statistics.ts
|
|
1445
1471
|
import { gray as gray2 } from "colorette";
|
|
@@ -2155,7 +2181,6 @@ export {
|
|
|
2155
2181
|
ignoredIdentifier,
|
|
2156
2182
|
isIndexProbablyDroppable,
|
|
2157
2183
|
isIndexSupported,
|
|
2158
|
-
parseNudges
|
|
2159
|
-
permuteWithFeedback
|
|
2184
|
+
parseNudges
|
|
2160
2185
|
};
|
|
2161
2186
|
//# sourceMappingURL=index.js.map
|