@query-doctor/core 0.8.9 → 0.10.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.
Files changed (57) hide show
  1. package/dist/index.cjs +21 -1
  2. package/dist/index.d.cts +8 -5
  3. package/dist/index.d.mts +8 -5
  4. package/dist/index.mjs +5 -3
  5. package/dist/optimizer/genalgo.cjs +5 -5
  6. package/dist/optimizer/genalgo.cjs.map +1 -1
  7. package/dist/optimizer/genalgo.d.cts +6 -5
  8. package/dist/optimizer/genalgo.d.cts.map +1 -1
  9. package/dist/optimizer/genalgo.d.mts +6 -5
  10. package/dist/optimizer/genalgo.d.mts.map +1 -1
  11. package/dist/optimizer/genalgo.mjs +5 -5
  12. package/dist/optimizer/genalgo.mjs.map +1 -1
  13. package/dist/optimizer/statistics.cjs +1 -61
  14. package/dist/optimizer/statistics.cjs.map +1 -1
  15. package/dist/optimizer/statistics.d.cts +1 -20
  16. package/dist/optimizer/statistics.d.cts.map +1 -1
  17. package/dist/optimizer/statistics.d.mts +1 -20
  18. package/dist/optimizer/statistics.d.mts.map +1 -1
  19. package/dist/optimizer/statistics.mjs +1 -61
  20. package/dist/optimizer/statistics.mjs.map +1 -1
  21. package/dist/query.cjs +33 -0
  22. package/dist/query.cjs.map +1 -0
  23. package/dist/query.d.cts +105 -0
  24. package/dist/query.d.cts.map +1 -0
  25. package/dist/query.d.mts +105 -0
  26. package/dist/query.d.mts.map +1 -0
  27. package/dist/query.mjs +31 -0
  28. package/dist/query.mjs.map +1 -0
  29. package/dist/schema-dump.cjs +365 -0
  30. package/dist/schema-dump.cjs.map +1 -0
  31. package/dist/schema-dump.mjs +365 -0
  32. package/dist/schema-dump.mjs.map +1 -0
  33. package/dist/schema.cjs +172 -0
  34. package/dist/schema.cjs.map +1 -0
  35. package/dist/schema.d.cts +352 -0
  36. package/dist/schema.d.cts.map +1 -0
  37. package/dist/schema.d.mts +352 -0
  38. package/dist/schema.d.mts.map +1 -0
  39. package/dist/schema.mjs +157 -0
  40. package/dist/schema.mjs.map +1 -0
  41. package/dist/sql/database.d.cts +1 -1
  42. package/dist/sql/database.d.mts +1 -1
  43. package/dist/sql/indexes.cjs +51 -2
  44. package/dist/sql/indexes.cjs.map +1 -1
  45. package/dist/sql/indexes.d.cts +20 -4
  46. package/dist/sql/indexes.d.cts.map +1 -1
  47. package/dist/sql/indexes.d.mts +20 -4
  48. package/dist/sql/indexes.d.mts.map +1 -1
  49. package/dist/sql/indexes.mjs +51 -3
  50. package/dist/sql/indexes.mjs.map +1 -1
  51. package/dist/sql/walker.cjs +1 -1
  52. package/dist/sql/walker.mjs +1 -1
  53. package/dist/websocket-server.d.cts +68 -0
  54. package/dist/websocket-server.d.cts.map +1 -0
  55. package/dist/websocket-server.d.mts +68 -0
  56. package/dist/websocket-server.d.mts.map +1 -0
  57. package/package.json +4 -2
@@ -1,14 +1,30 @@
1
1
  'use client';
2
2
 
3
- import { IndexedTable } from "../optimizer/statistics.cjs";
3
+ import { FullSchemaIndex } from "../schema.cjs";
4
4
 
5
5
  //#region src/sql/indexes.d.ts
6
- declare function isIndexSupported(index: IndexedTable): boolean;
6
+ type IndexTypeHint = {
7
+ indexType: string;
8
+ };
9
+ type IndexDropHint = {
10
+ isPrimary: boolean;
11
+ isUnique: boolean;
12
+ };
13
+ declare function isIndexSupported(index: IndexTypeHint): boolean;
7
14
  /**
8
15
  * Doesn't necessarily decide whether the index can be dropped but can be
9
16
  * used to not even try dropping indexes that _definitely_ cannot be dropped
10
17
  */
11
- declare function isIndexProbablyDroppable(index: IndexedTable): boolean;
18
+ declare function isIndexProbablyDroppable(index: IndexDropHint): boolean;
19
+ type DuplicateIndexGroup = {
20
+ kind: "exact";
21
+ indexes: FullSchemaIndex[];
22
+ } | {
23
+ kind: "prefix";
24
+ indexes: FullSchemaIndex[];
25
+ sharedPrefix: FullSchemaIndex["keyColumns"];
26
+ };
27
+ declare function groupDuplicateIndexes(indexes: FullSchemaIndex[]): DuplicateIndexGroup[];
12
28
  //#endregion
13
- export { isIndexProbablyDroppable, isIndexSupported };
29
+ export { DuplicateIndexGroup, groupDuplicateIndexes, isIndexProbablyDroppable, isIndexSupported };
14
30
  //# sourceMappingURL=indexes.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexes.d.cts","names":[],"sources":["../../src/sql/indexes.ts"],"mappings":";;;;;iBAEgB,gBAAA,CAAiB,KAAA,EAAO,YAAA;;;AAAxC;;iBAQgB,wBAAA,CAAyB,KAAA,EAAO,YAAA"}
1
+ {"version":3,"file":"indexes.d.cts","names":[],"sources":["../../src/sql/indexes.ts"],"mappings":";;;;;KAEK,aAAA;EAAkB,SAAA;AAAA;AAAA,KAClB,aAAA;EAAkB,SAAA;EAAoB,QAAA;AAAA;AAAA,iBAE3B,gBAAA,CAAiB,KAAA,EAAO,aAAA;AAHR;;;;AAAA,iBAWhB,wBAAA,CAAyB,KAAA,EAAO,aAAA;AAAA,KAMpC,mBAAA;EACN,IAAA;EAAe,OAAA,EAAS,eAAA;AAAA;EAExB,IAAA;EACA,OAAA,EAAS,eAAA;EACT,YAAA,EAAc,eAAA;AAAA;AAAA,iBA2DJ,qBAAA,CACd,OAAA,EAAS,eAAA,KACR,mBAAA"}
@@ -1,14 +1,30 @@
1
1
  'use client';
2
2
 
3
- import { IndexedTable } from "../optimizer/statistics.mjs";
3
+ import { FullSchemaIndex } from "../schema.mjs";
4
4
 
5
5
  //#region src/sql/indexes.d.ts
6
- declare function isIndexSupported(index: IndexedTable): boolean;
6
+ type IndexTypeHint = {
7
+ indexType: string;
8
+ };
9
+ type IndexDropHint = {
10
+ isPrimary: boolean;
11
+ isUnique: boolean;
12
+ };
13
+ declare function isIndexSupported(index: IndexTypeHint): boolean;
7
14
  /**
8
15
  * Doesn't necessarily decide whether the index can be dropped but can be
9
16
  * used to not even try dropping indexes that _definitely_ cannot be dropped
10
17
  */
11
- declare function isIndexProbablyDroppable(index: IndexedTable): boolean;
18
+ declare function isIndexProbablyDroppable(index: IndexDropHint): boolean;
19
+ type DuplicateIndexGroup = {
20
+ kind: "exact";
21
+ indexes: FullSchemaIndex[];
22
+ } | {
23
+ kind: "prefix";
24
+ indexes: FullSchemaIndex[];
25
+ sharedPrefix: FullSchemaIndex["keyColumns"];
26
+ };
27
+ declare function groupDuplicateIndexes(indexes: FullSchemaIndex[]): DuplicateIndexGroup[];
12
28
  //#endregion
13
- export { isIndexProbablyDroppable, isIndexSupported };
29
+ export { DuplicateIndexGroup, groupDuplicateIndexes, isIndexProbablyDroppable, isIndexSupported };
14
30
  //# sourceMappingURL=indexes.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexes.d.mts","names":[],"sources":["../../src/sql/indexes.ts"],"mappings":";;;;;iBAEgB,gBAAA,CAAiB,KAAA,EAAO,YAAA;;;AAAxC;;iBAQgB,wBAAA,CAAyB,KAAA,EAAO,YAAA"}
1
+ {"version":3,"file":"indexes.d.mts","names":[],"sources":["../../src/sql/indexes.ts"],"mappings":";;;;;KAEK,aAAA;EAAkB,SAAA;AAAA;AAAA,KAClB,aAAA;EAAkB,SAAA;EAAoB,QAAA;AAAA;AAAA,iBAE3B,gBAAA,CAAiB,KAAA,EAAO,aAAA;AAHR;;;;AAAA,iBAWhB,wBAAA,CAAyB,KAAA,EAAO,aAAA;AAAA,KAMpC,mBAAA;EACN,IAAA;EAAe,OAAA,EAAS,eAAA;AAAA;EAExB,IAAA;EACA,OAAA,EAAS,eAAA;EACT,YAAA,EAAc,eAAA;AAAA;AAAA,iBA2DJ,qBAAA,CACd,OAAA,EAAS,eAAA,KACR,mBAAA"}
@@ -1,16 +1,64 @@
1
1
  "use client";
2
2
  //#region src/sql/indexes.ts
3
3
  function isIndexSupported(index) {
4
- return index.index_type === "btree" || index.index_type === "gin";
4
+ return index.indexType === "btree" || index.indexType === "gin";
5
5
  }
6
6
  /**
7
7
  * Doesn't necessarily decide whether the index can be dropped but can be
8
8
  * used to not even try dropping indexes that _definitely_ cannot be dropped
9
9
  */
10
10
  function isIndexProbablyDroppable(index) {
11
- return !index.is_primary && !index.is_unique;
11
+ return !index.isPrimary && !index.isUnique;
12
+ }
13
+ function columnsEqual(a, b) {
14
+ if (a.length !== b.length) return false;
15
+ for (let i = 0; i < a.length; i++) if (a[i].name.toString() !== b[i].name.toString() || (a[i].order ?? null) !== (b[i].order ?? null) || (a[i].opclass ?? null) !== (b[i].opclass ?? null)) return false;
16
+ return true;
17
+ }
18
+ function indexesAreEqual(a, b) {
19
+ return a.schemaName.toString() === b.schemaName.toString() && a.tableName.toString() === b.tableName.toString() && a.indexType === b.indexType && (a.wherePredicate ?? null) === (b.wherePredicate ?? null) && columnsEqual(a.keyColumns, b.keyColumns);
20
+ }
21
+ function sharedPrefixColumns(shorter, longer) {
22
+ if (shorter.schemaName.toString() !== longer.schemaName.toString() || shorter.tableName.toString() !== longer.tableName.toString() || shorter.indexType !== longer.indexType || shorter.indexType !== "btree" || shorter.wherePredicate !== void 0 || longer.wherePredicate !== void 0 || shorter.keyColumns.length >= longer.keyColumns.length) return null;
23
+ for (let i = 0; i < shorter.keyColumns.length; i++) {
24
+ const s = shorter.keyColumns[i];
25
+ const l = longer.keyColumns[i];
26
+ if (s.name.toString() !== l.name.toString() || (s.order ?? null) !== (l.order ?? null) || (s.opclass ?? null) !== (l.opclass ?? null)) return null;
27
+ }
28
+ return shorter.keyColumns;
29
+ }
30
+ function groupDuplicateIndexes(indexes) {
31
+ const groups = [];
32
+ for (const index of indexes) {
33
+ const existing = groups.find((g) => g.kind === "exact" && indexesAreEqual(g.indexes[0], index));
34
+ if (existing) existing.indexes.push(index);
35
+ else groups.push({
36
+ kind: "exact",
37
+ indexes: [index]
38
+ });
39
+ }
40
+ const exactGroups = groups.filter((g) => g.indexes.length > 1);
41
+ const representatives = groups.filter((g) => g.indexes.length === 1).map((g) => g.indexes[0]);
42
+ const prefixGroups = [];
43
+ for (const shorter of representatives) {
44
+ const existing = prefixGroups.find((g) => g.indexes.some((idx) => sharedPrefixColumns(shorter, idx) !== null || sharedPrefixColumns(idx, shorter) !== null));
45
+ if (existing) {
46
+ if (!existing.indexes.includes(shorter)) existing.indexes.push(shorter);
47
+ } else {
48
+ const longer = representatives.find((idx) => idx !== shorter && sharedPrefixColumns(shorter, idx) !== null);
49
+ if (longer) {
50
+ const sharedPrefix = sharedPrefixColumns(shorter, longer);
51
+ prefixGroups.push({
52
+ kind: "prefix",
53
+ indexes: [longer, shorter],
54
+ sharedPrefix
55
+ });
56
+ }
57
+ }
58
+ }
59
+ return [...exactGroups, ...prefixGroups];
12
60
  }
13
61
  //#endregion
14
- export { isIndexProbablyDroppable, isIndexSupported };
62
+ export { groupDuplicateIndexes, isIndexProbablyDroppable, isIndexSupported };
15
63
 
16
64
  //# sourceMappingURL=indexes.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"indexes.mjs","names":[],"sources":["../../src/sql/indexes.ts"],"sourcesContent":["import type { IndexedTable } from \"../optimizer/statistics.js\";\n\nexport function isIndexSupported(index: IndexedTable) {\n return index.index_type === \"btree\" || index.index_type === \"gin\";\n}\n\n/**\n * Doesn't necessarily decide whether the index can be dropped but can be\n * used to not even try dropping indexes that _definitely_ cannot be dropped\n */\nexport function isIndexProbablyDroppable(index: IndexedTable) {\n /* TODO: until we have a better solution, this is the best we have */\n /* The is_unique check is problematic only if the column is declared as unique */\n return !index.is_primary && !index.is_unique;\n}\n"],"mappings":";;AAEA,SAAgB,iBAAiB,OAAqB;AACpD,QAAO,MAAM,eAAe,WAAW,MAAM,eAAe;;;;;;AAO9D,SAAgB,yBAAyB,OAAqB;AAG5D,QAAO,CAAC,MAAM,cAAc,CAAC,MAAM"}
1
+ {"version":3,"file":"indexes.mjs","names":[],"sources":["../../src/sql/indexes.ts"],"sourcesContent":["import type { FullSchemaIndex } from \"../schema.js\";\n\ntype IndexTypeHint = { indexType: string };\ntype IndexDropHint = { isPrimary: boolean; isUnique: boolean };\n\nexport function isIndexSupported(index: IndexTypeHint) {\n return index.indexType === \"btree\" || index.indexType === \"gin\";\n}\n\n/**\n * Doesn't necessarily decide whether the index can be dropped but can be\n * used to not even try dropping indexes that _definitely_ cannot be dropped\n */\nexport function isIndexProbablyDroppable(index: IndexDropHint) {\n /* TODO: until we have a better solution, this is the best we have */\n /* The is_unique check is problematic only if the column is declared as unique */\n return !index.isPrimary && !index.isUnique;\n}\n\nexport type DuplicateIndexGroup =\n | { kind: \"exact\"; indexes: FullSchemaIndex[] }\n | {\n kind: \"prefix\";\n indexes: FullSchemaIndex[];\n sharedPrefix: FullSchemaIndex[\"keyColumns\"];\n };\n\nfunction columnsEqual(\n a: FullSchemaIndex[\"keyColumns\"],\n b: FullSchemaIndex[\"keyColumns\"],\n): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (\n a[i].name.toString() !== b[i].name.toString() ||\n (a[i].order ?? null) !== (b[i].order ?? null) ||\n (a[i].opclass ?? null) !== (b[i].opclass ?? null)\n ) {\n return false;\n }\n }\n return true;\n}\n\nfunction indexesAreEqual(a: FullSchemaIndex, b: FullSchemaIndex): boolean {\n return (\n a.schemaName.toString() === b.schemaName.toString() &&\n a.tableName.toString() === b.tableName.toString() &&\n a.indexType === b.indexType &&\n (a.wherePredicate ?? null) === (b.wherePredicate ?? null) &&\n columnsEqual(a.keyColumns, b.keyColumns)\n );\n}\n\nfunction sharedPrefixColumns(\n shorter: FullSchemaIndex,\n longer: FullSchemaIndex,\n): FullSchemaIndex[\"keyColumns\"] | null {\n if (\n shorter.schemaName.toString() !== longer.schemaName.toString() ||\n shorter.tableName.toString() !== longer.tableName.toString() ||\n shorter.indexType !== longer.indexType ||\n shorter.indexType !== \"btree\" ||\n shorter.wherePredicate !== undefined ||\n longer.wherePredicate !== undefined ||\n shorter.keyColumns.length >= longer.keyColumns.length\n ) {\n return null;\n }\n for (let i = 0; i < shorter.keyColumns.length; i++) {\n const s = shorter.keyColumns[i];\n const l = longer.keyColumns[i];\n if (\n s.name.toString() !== l.name.toString() ||\n (s.order ?? null) !== (l.order ?? null) ||\n (s.opclass ?? null) !== (l.opclass ?? null)\n ) {\n return null;\n }\n }\n return shorter.keyColumns;\n}\n\nexport function groupDuplicateIndexes(\n indexes: FullSchemaIndex[],\n): DuplicateIndexGroup[] {\n const groups: DuplicateIndexGroup[] = [];\n\n for (const index of indexes) {\n const existing = groups.find(\n (g) => g.kind === \"exact\" && indexesAreEqual(g.indexes[0], index),\n );\n if (existing) {\n existing.indexes.push(index);\n } else {\n groups.push({ kind: \"exact\", indexes: [index] });\n }\n }\n\n const exactGroups = groups.filter((g) => g.indexes.length > 1);\n\n const representatives = groups\n .filter((g) => g.indexes.length === 1)\n .map((g) => g.indexes[0]);\n\n const prefixGroups: Extract<DuplicateIndexGroup, { kind: \"prefix\" }>[] = [];\n\n for (const shorter of representatives) {\n const existing = prefixGroups.find((g) =>\n g.indexes.some(\n (idx) =>\n sharedPrefixColumns(shorter, idx) !== null ||\n sharedPrefixColumns(idx, shorter) !== null,\n ),\n );\n if (existing) {\n if (!existing.indexes.includes(shorter)) {\n existing.indexes.push(shorter);\n }\n } else {\n const longer = representatives.find(\n (idx) => idx !== shorter && sharedPrefixColumns(shorter, idx) !== null,\n );\n if (longer) {\n const sharedPrefix = sharedPrefixColumns(shorter, longer)!;\n prefixGroups.push({\n kind: \"prefix\",\n indexes: [longer, shorter],\n sharedPrefix,\n });\n }\n }\n }\n\n return [...exactGroups, ...prefixGroups];\n}\n"],"mappings":";;AAKA,SAAgB,iBAAiB,OAAsB;AACrD,QAAO,MAAM,cAAc,WAAW,MAAM,cAAc;;;;;;AAO5D,SAAgB,yBAAyB,OAAsB;AAG7D,QAAO,CAAC,MAAM,aAAa,CAAC,MAAM;;AAWpC,SAAS,aACP,GACA,GACS;AACT,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,IAC5B,KACE,EAAE,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG,KAAK,UAAU,KAC5C,EAAE,GAAG,SAAS,WAAW,EAAE,GAAG,SAAS,UACvC,EAAE,GAAG,WAAW,WAAW,EAAE,GAAG,WAAW,MAE5C,QAAO;AAGX,QAAO;;AAGT,SAAS,gBAAgB,GAAoB,GAA6B;AACxE,QACE,EAAE,WAAW,UAAU,KAAK,EAAE,WAAW,UAAU,IACnD,EAAE,UAAU,UAAU,KAAK,EAAE,UAAU,UAAU,IACjD,EAAE,cAAc,EAAE,cACjB,EAAE,kBAAkB,WAAW,EAAE,kBAAkB,SACpD,aAAa,EAAE,YAAY,EAAE,WAAW;;AAI5C,SAAS,oBACP,SACA,QACsC;AACtC,KACE,QAAQ,WAAW,UAAU,KAAK,OAAO,WAAW,UAAU,IAC9D,QAAQ,UAAU,UAAU,KAAK,OAAO,UAAU,UAAU,IAC5D,QAAQ,cAAc,OAAO,aAC7B,QAAQ,cAAc,WACtB,QAAQ,mBAAmB,KAAA,KAC3B,OAAO,mBAAmB,KAAA,KAC1B,QAAQ,WAAW,UAAU,OAAO,WAAW,OAE/C,QAAO;AAET,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,WAAW,QAAQ,KAAK;EAClD,MAAM,IAAI,QAAQ,WAAW;EAC7B,MAAM,IAAI,OAAO,WAAW;AAC5B,MACE,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,UAAU,KACtC,EAAE,SAAS,WAAW,EAAE,SAAS,UACjC,EAAE,WAAW,WAAW,EAAE,WAAW,MAEtC,QAAO;;AAGX,QAAO,QAAQ;;AAGjB,SAAgB,sBACd,SACuB;CACvB,MAAM,SAAgC,EAAE;AAExC,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,OAAO,MACrB,MAAM,EAAE,SAAS,WAAW,gBAAgB,EAAE,QAAQ,IAAI,MAAM,CAClE;AACD,MAAI,SACF,UAAS,QAAQ,KAAK,MAAM;MAE5B,QAAO,KAAK;GAAE,MAAM;GAAS,SAAS,CAAC,MAAM;GAAE,CAAC;;CAIpD,MAAM,cAAc,OAAO,QAAQ,MAAM,EAAE,QAAQ,SAAS,EAAE;CAE9D,MAAM,kBAAkB,OACrB,QAAQ,MAAM,EAAE,QAAQ,WAAW,EAAE,CACrC,KAAK,MAAM,EAAE,QAAQ,GAAG;CAE3B,MAAM,eAAmE,EAAE;AAE3E,MAAK,MAAM,WAAW,iBAAiB;EACrC,MAAM,WAAW,aAAa,MAAM,MAClC,EAAE,QAAQ,MACP,QACC,oBAAoB,SAAS,IAAI,KAAK,QACtC,oBAAoB,KAAK,QAAQ,KAAK,KACzC,CACF;AACD,MAAI;OACE,CAAC,SAAS,QAAQ,SAAS,QAAQ,CACrC,UAAS,QAAQ,KAAK,QAAQ;SAE3B;GACL,MAAM,SAAS,gBAAgB,MAC5B,QAAQ,QAAQ,WAAW,oBAAoB,SAAS,IAAI,KAAK,KACnE;AACD,OAAI,QAAQ;IACV,MAAM,eAAe,oBAAoB,SAAS,OAAO;AACzD,iBAAa,KAAK;KAChB,MAAM;KACN,SAAS,CAAC,QAAQ,QAAQ;KAC1B;KACD,CAAC;;;;AAKR,QAAO,CAAC,GAAG,aAAa,GAAG,aAAa"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  require("../_virtual/_rolldown/runtime.cjs");
3
+ const require_defineProperty = require("../_virtual/_@oxc-project_runtime@0.126.0/helpers/defineProperty.cjs");
3
4
  const require_ast_utils = require("./ast-utils.cjs");
4
5
  const require_nudges = require("./nudges.cjs");
5
- const require_defineProperty = require("../_virtual/_@oxc-project_runtime@0.126.0/helpers/defineProperty.cjs");
6
6
  let pgsql_deparser = require("pgsql-deparser");
7
7
  //#region src/sql/walker.ts
8
8
  const JSONB_EXTRACTION_OPS = new Set(["->", "->>"]);
@@ -1,7 +1,7 @@
1
1
  "use client";
2
+ import { _defineProperty } from "../_virtual/_@oxc-project_runtime@0.126.0/helpers/defineProperty.mjs";
2
3
  import { getNodeKind, is, isANode } from "./ast-utils.mjs";
3
4
  import { parseNudges } from "./nudges.mjs";
4
- import { _defineProperty } from "../_virtual/_@oxc-project_runtime@0.126.0/helpers/defineProperty.mjs";
5
5
  import { deparseSync } from "pgsql-deparser";
6
6
  //#region src/sql/walker.ts
7
7
  const JSONB_EXTRACTION_OPS = new Set(["->", "->>"]);
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+
3
+ import { ExportedStats } from "./optimizer/statistics.cjs";
4
+ import { OptimizedQuery } from "./query.cjs";
5
+ import { RpcStub } from "capnweb";
6
+
7
+ //#region src/websocket-server.d.ts
8
+ type IndexDefinition = {
9
+ schemaName: string;
10
+ tableName: string;
11
+ indexName: string;
12
+ indexType?: string;
13
+ isUnique?: boolean;
14
+ columns: Array<{
15
+ name: string;
16
+ order?: "ASC" | "DESC";
17
+ opclass?: string;
18
+ }>;
19
+ wherePredicate?: string;
20
+ };
21
+ type ExtensionPresence = {
22
+ type: "present";
23
+ extensionName: "pg_stat_statements" | "pg_stat_monitor";
24
+ needsRestart: boolean;
25
+ } | {
26
+ type: "missing";
27
+ };
28
+ type RepoConfig = {
29
+ minimumCost: number;
30
+ regressionThreshold: number;
31
+ ignoredQueryHashes: string[];
32
+ lastSeenQueryHashes: string[];
33
+ acknowledgedQueryHashes: string[];
34
+ comparisonBranch?: string;
35
+ };
36
+ interface ServerApi {
37
+ pushQuery(queries: OptimizedQuery[]): Promise<void>;
38
+ pushStats(stats: ExportedStats[]): Promise<void>;
39
+ pushSchema(schema: unknown): Promise<void>;
40
+ pushEncryptedStats(stats: Uint8Array): Promise<void>;
41
+ setExtensionPresence(presence: ExtensionPresence): Promise<void>;
42
+ log(line: string, process?: string): Promise<void>;
43
+ ping(): Promise<void>;
44
+ getRepoConfig(repo: string, branch: string): Promise<RepoConfig>;
45
+ }
46
+ interface ClientApi {
47
+ repull(): Promise<unknown>;
48
+ refreshQueries(): Promise<void>;
49
+ updateStatistics(stats: ExportedStats[]): Promise<void>;
50
+ hideIndex(indexName: string): Promise<void>;
51
+ addIndex(index: IndexDefinition): Promise<void>;
52
+ runQuery(query: string): Promise<void>;
53
+ }
54
+ type ConnectionMode = {
55
+ kind: "persistent";
56
+ environment?: string;
57
+ } | {
58
+ kind: "ci";
59
+ branch: string;
60
+ sha: string;
61
+ label?: string;
62
+ };
63
+ interface UnauthenticatedServerApi {
64
+ authenticate(token: string, client: RpcStub<ClientApi>, mode: ConnectionMode): Promise<ServerApi>;
65
+ }
66
+ //#endregion
67
+ export { ClientApi, ConnectionMode, ExtensionPresence, IndexDefinition, RepoConfig, ServerApi, UnauthenticatedServerApi };
68
+ //# sourceMappingURL=websocket-server.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-server.d.cts","names":[],"sources":["../src/websocket-server.ts"],"mappings":";;;;;;;KAIY,eAAA;EACV,UAAA;EACA,SAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;EACA,OAAA,EAAS,KAAA;IACP,IAAA;IACA,KAAA;IACA,OAAA;EAAA;EAEF,cAAA;AAAA;AAAA,KAGU,iBAAA;EAEN,IAAA;EACA,aAAA;EACA,YAAA;AAAA;EAGA,IAAA;AAAA;AAAA,KAGM,UAAA;EACV,WAAA;EACA,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,uBAAA;EACA,gBAAA;AAAA;AAAA,UAGe,SAAA;EACf,SAAA,CAAU,OAAA,EAAS,cAAA,KAAmB,OAAA;EACtC,SAAA,CAAU,KAAA,EAAO,aAAA,KAAkB,OAAA;EACnC,UAAA,CAAW,MAAA,YAAkB,OAAA;EAC7B,kBAAA,CAAmB,KAAA,EAAO,UAAA,GAAa,OAAA;EACvC,oBAAA,CAAqB,QAAA,EAAU,iBAAA,GAAoB,OAAA;EACnD,GAAA,CAAI,IAAA,UAAc,OAAA,YAAmB,OAAA;EACrC,IAAA,IAAQ,OAAA;EACR,aAAA,CAAc,IAAA,UAAc,MAAA,WAAiB,OAAA,CAAQ,UAAA;AAAA;AAAA,UAGtC,SAAA;EACf,MAAA,IAAU,OAAA;EACV,cAAA,IAAkB,OAAA;EAClB,gBAAA,CAAiB,KAAA,EAAO,aAAA,KAAkB,OAAA;EAC1C,SAAA,CAAU,SAAA,WAAoB,OAAA;EAC9B,QAAA,CAAS,KAAA,EAAO,eAAA,GAAkB,OAAA;EAClC,QAAA,CAAS,KAAA,WAAgB,OAAA;AAAA;AAAA,KAGf,cAAA;EACN,IAAA;EAAoB,WAAA;AAAA;EACpB,IAAA;EAAY,MAAA;EAAgB,GAAA;EAAa,KAAA;AAAA;AAAA,UAE9B,wBAAA;EACf,YAAA,CACE,KAAA,UACA,MAAA,EAAQ,OAAA,CAAQ,SAAA,GAChB,IAAA,EAAM,cAAA,GACL,OAAA,CAAQ,SAAA;AAAA"}
@@ -0,0 +1,68 @@
1
+ 'use client';
2
+
3
+ import { ExportedStats } from "./optimizer/statistics.mjs";
4
+ import { OptimizedQuery } from "./query.mjs";
5
+ import { RpcStub } from "capnweb";
6
+
7
+ //#region src/websocket-server.d.ts
8
+ type IndexDefinition = {
9
+ schemaName: string;
10
+ tableName: string;
11
+ indexName: string;
12
+ indexType?: string;
13
+ isUnique?: boolean;
14
+ columns: Array<{
15
+ name: string;
16
+ order?: "ASC" | "DESC";
17
+ opclass?: string;
18
+ }>;
19
+ wherePredicate?: string;
20
+ };
21
+ type ExtensionPresence = {
22
+ type: "present";
23
+ extensionName: "pg_stat_statements" | "pg_stat_monitor";
24
+ needsRestart: boolean;
25
+ } | {
26
+ type: "missing";
27
+ };
28
+ type RepoConfig = {
29
+ minimumCost: number;
30
+ regressionThreshold: number;
31
+ ignoredQueryHashes: string[];
32
+ lastSeenQueryHashes: string[];
33
+ acknowledgedQueryHashes: string[];
34
+ comparisonBranch?: string;
35
+ };
36
+ interface ServerApi {
37
+ pushQuery(queries: OptimizedQuery[]): Promise<void>;
38
+ pushStats(stats: ExportedStats[]): Promise<void>;
39
+ pushSchema(schema: unknown): Promise<void>;
40
+ pushEncryptedStats(stats: Uint8Array): Promise<void>;
41
+ setExtensionPresence(presence: ExtensionPresence): Promise<void>;
42
+ log(line: string, process?: string): Promise<void>;
43
+ ping(): Promise<void>;
44
+ getRepoConfig(repo: string, branch: string): Promise<RepoConfig>;
45
+ }
46
+ interface ClientApi {
47
+ repull(): Promise<unknown>;
48
+ refreshQueries(): Promise<void>;
49
+ updateStatistics(stats: ExportedStats[]): Promise<void>;
50
+ hideIndex(indexName: string): Promise<void>;
51
+ addIndex(index: IndexDefinition): Promise<void>;
52
+ runQuery(query: string): Promise<void>;
53
+ }
54
+ type ConnectionMode = {
55
+ kind: "persistent";
56
+ environment?: string;
57
+ } | {
58
+ kind: "ci";
59
+ branch: string;
60
+ sha: string;
61
+ label?: string;
62
+ };
63
+ interface UnauthenticatedServerApi {
64
+ authenticate(token: string, client: RpcStub<ClientApi>, mode: ConnectionMode): Promise<ServerApi>;
65
+ }
66
+ //#endregion
67
+ export { ClientApi, ConnectionMode, ExtensionPresence, IndexDefinition, RepoConfig, ServerApi, UnauthenticatedServerApi };
68
+ //# sourceMappingURL=websocket-server.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-server.d.mts","names":[],"sources":["../src/websocket-server.ts"],"mappings":";;;;;;;KAIY,eAAA;EACV,UAAA;EACA,SAAA;EACA,SAAA;EACA,SAAA;EACA,QAAA;EACA,OAAA,EAAS,KAAA;IACP,IAAA;IACA,KAAA;IACA,OAAA;EAAA;EAEF,cAAA;AAAA;AAAA,KAGU,iBAAA;EAEN,IAAA;EACA,aAAA;EACA,YAAA;AAAA;EAGA,IAAA;AAAA;AAAA,KAGM,UAAA;EACV,WAAA;EACA,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,uBAAA;EACA,gBAAA;AAAA;AAAA,UAGe,SAAA;EACf,SAAA,CAAU,OAAA,EAAS,cAAA,KAAmB,OAAA;EACtC,SAAA,CAAU,KAAA,EAAO,aAAA,KAAkB,OAAA;EACnC,UAAA,CAAW,MAAA,YAAkB,OAAA;EAC7B,kBAAA,CAAmB,KAAA,EAAO,UAAA,GAAa,OAAA;EACvC,oBAAA,CAAqB,QAAA,EAAU,iBAAA,GAAoB,OAAA;EACnD,GAAA,CAAI,IAAA,UAAc,OAAA,YAAmB,OAAA;EACrC,IAAA,IAAQ,OAAA;EACR,aAAA,CAAc,IAAA,UAAc,MAAA,WAAiB,OAAA,CAAQ,UAAA;AAAA;AAAA,UAGtC,SAAA;EACf,MAAA,IAAU,OAAA;EACV,cAAA,IAAkB,OAAA;EAClB,gBAAA,CAAiB,KAAA,EAAO,aAAA,KAAkB,OAAA;EAC1C,SAAA,CAAU,SAAA,WAAoB,OAAA;EAC9B,QAAA,CAAS,KAAA,EAAO,eAAA,GAAkB,OAAA;EAClC,QAAA,CAAS,KAAA,WAAgB,OAAA;AAAA;AAAA,KAGf,cAAA;EACN,IAAA;EAAoB,WAAA;AAAA;EACpB,IAAA;EAAY,MAAA;EAAgB,GAAA;EAAa,KAAA;AAAA;AAAA,UAE9B,wBAAA;EACf,YAAA,CACE,KAAA,UACA,MAAA,EAAQ,OAAA,CAAQ,SAAA,GAChB,IAAA,EAAM,cAAA,GACL,OAAA,CAAQ,SAAA;AAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@query-doctor/core",
3
- "version": "0.8.9",
3
+ "version": "0.10.0",
4
4
  "private": false,
5
5
  "description": "Core logic for Query Doctor",
6
6
  "license": "",
@@ -22,14 +22,16 @@
22
22
  "scripts": {
23
23
  "dev": "tsdown --watch",
24
24
  "build": "tsdown",
25
+ "typecheck": "tsc --noEmit",
25
26
  "test": "vitest"
26
27
  },
27
28
  "dependencies": {
28
29
  "@pgsql/types": "^17.6.2",
30
+ "capnweb": "^0.7.0",
29
31
  "colorette": "^2.0.20",
30
32
  "dedent": "^1.7.2",
31
33
  "pgsql-deparser": "^17.17.2",
32
- "zod": "^4.1.13"
34
+ "zod": "^4.3.6"
33
35
  },
34
36
  "devDependencies": {
35
37
  "@pgsql/parser": "^17.5.0",