sqlstack 3.5.0 → 3.6.0-dev.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 (70) hide show
  1. package/dist/cjs/codegen/generateManifest.d.ts +3 -1
  2. package/dist/cjs/codegen/generateManifest.d.ts.map +1 -1
  3. package/dist/cjs/codegen/generateManifest.js +195 -3
  4. package/dist/cjs/codegen/generateManifest.js.map +1 -1
  5. package/dist/cjs/core/fileResolution.d.ts +7 -0
  6. package/dist/cjs/core/fileResolution.d.ts.map +1 -1
  7. package/dist/cjs/core/fileResolution.js +53 -14
  8. package/dist/cjs/core/fileResolution.js.map +1 -1
  9. package/dist/cjs/core/metadata.d.ts +5 -0
  10. package/dist/cjs/core/metadata.d.ts.map +1 -1
  11. package/dist/cjs/core/metadata.js.map +1 -1
  12. package/dist/cjs/core/resources.d.ts +36 -0
  13. package/dist/cjs/core/resources.d.ts.map +1 -0
  14. package/dist/cjs/core/resources.js +98 -0
  15. package/dist/cjs/core/resources.js.map +1 -0
  16. package/dist/cjs/core/sourceScanResolver.d.ts +8 -14
  17. package/dist/cjs/core/sourceScanResolver.d.ts.map +1 -1
  18. package/dist/cjs/core/sourceScanResolver.js +8 -20
  19. package/dist/cjs/core/sourceScanResolver.js.map +1 -1
  20. package/dist/cjs/decorators/query.d.ts.map +1 -1
  21. package/dist/cjs/decorators/query.js +96 -35
  22. package/dist/cjs/decorators/query.js.map +1 -1
  23. package/dist/cjs/family.d.ts.map +1 -1
  24. package/dist/cjs/family.js +3 -1
  25. package/dist/cjs/family.js.map +1 -1
  26. package/dist/cjs/index.d.ts +2 -0
  27. package/dist/cjs/index.d.ts.map +1 -1
  28. package/dist/cjs/index.js +4 -1
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/cjs/run.d.ts +44 -4
  31. package/dist/cjs/run.d.ts.map +1 -1
  32. package/dist/cjs/run.js +38 -7
  33. package/dist/cjs/run.js.map +1 -1
  34. package/dist/cjs/runtime.d.ts +6 -0
  35. package/dist/cjs/runtime.d.ts.map +1 -1
  36. package/dist/cjs/runtime.js +18 -0
  37. package/dist/cjs/runtime.js.map +1 -1
  38. package/dist/cjs/stack.d.ts +14 -0
  39. package/dist/cjs/stack.d.ts.map +1 -1
  40. package/dist/cjs/stack.js +20 -0
  41. package/dist/cjs/stack.js.map +1 -1
  42. package/dist/cjs/transactions.d.ts +52 -0
  43. package/dist/cjs/transactions.d.ts.map +1 -1
  44. package/dist/cjs/transactions.js +557 -3
  45. package/dist/cjs/transactions.js.map +1 -1
  46. package/dist/esm/codegen/generateManifest.js +195 -3
  47. package/dist/esm/codegen/generateManifest.js.map +1 -1
  48. package/dist/esm/core/fileResolution.js +52 -14
  49. package/dist/esm/core/fileResolution.js.map +1 -1
  50. package/dist/esm/core/metadata.js.map +1 -1
  51. package/dist/esm/core/resources.js +91 -0
  52. package/dist/esm/core/resources.js.map +1 -0
  53. package/dist/esm/core/sourceScanResolver.js +8 -19
  54. package/dist/esm/core/sourceScanResolver.js.map +1 -1
  55. package/dist/esm/decorators/query.js +101 -40
  56. package/dist/esm/decorators/query.js.map +1 -1
  57. package/dist/esm/family.js +3 -1
  58. package/dist/esm/family.js.map +1 -1
  59. package/dist/esm/index.js +1 -0
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/run.js +38 -8
  62. package/dist/esm/run.js.map +1 -1
  63. package/dist/esm/runtime.js +17 -0
  64. package/dist/esm/runtime.js.map +1 -1
  65. package/dist/esm/stack.js +21 -1
  66. package/dist/esm/stack.js.map +1 -1
  67. package/dist/esm/transactions.js +554 -3
  68. package/dist/esm/transactions.js.map +1 -1
  69. package/package.json +1 -1
  70. package/readme.md +74 -133
@@ -0,0 +1,36 @@
1
+ import type { Dialect } from '../registry';
2
+ /**
3
+ * Packaged SQL resources: a path-keyed map `{ '<path>/<method>.sql': '<sql>' }`
4
+ * installed by a bundled/packaged runtime (Electron asar, Cloudflare Worker,
5
+ * @noego/app node runner) via `SqlStack.useResources(map)`.
6
+ *
7
+ * Keys are file paths — absolute, or relative to the project root (the shape
8
+ * `import.meta.glob('/server/**\/*.sql', { eager: true, query: '?raw' })`
9
+ * produces). Lookups match by path suffix: the decorator's guessed directory
10
+ * plus `<method>.sql` must END WITH a key. That makes the same map valid
11
+ * whether modules load from `/repo/server/...`, `app.asar/out/server/...`
12
+ * or a Worker's `modules/<project>/server/...` tree, as long as the module
13
+ * tree is not flattened.
14
+ */
15
+ export type SqlResources = Record<string, string>;
16
+ /** Forward slashes, no `file://`, no leading `./`, exactly one leading `/`. */
17
+ export declare function normalizeResourcePath(p: string): string;
18
+ /** Install (or clear with undefined) the process-wide packaged SQL resources. */
19
+ export declare function setResources(map: SqlResources | undefined): void;
20
+ export declare function getResources(): SqlResources | undefined;
21
+ /**
22
+ * Resolve one absolute (or module-tree) candidate path against the installed
23
+ * resources. Order: exact key; the longest key that is a path suffix of the
24
+ * candidate; the unique key sharing the candidate's `<folder>/<file>` tail.
25
+ */
26
+ export declare function lookupResource(candidatePath: string): string | undefined;
27
+ /**
28
+ * Resolve a decorated method's SQL from the installed resources: the
29
+ * dialect-specific `<dir>/<method>.<ext>.sql` first, then `<dir>/<method>.sql`.
30
+ * Returns the tried candidate paths so a miss can be reported precisely.
31
+ */
32
+ export declare function resolveSqlFromResources(dir: string, methodName: string, dialect: Dialect): {
33
+ sql: string | undefined;
34
+ tried: string[];
35
+ };
36
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../src/core/resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAwBlD,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAMvD;AAOD,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAchE;AAED,wBAAgB,YAAY,IAAI,YAAY,GAAG,SAAS,CAEvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoBxE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf;IAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAQ9C"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeResourcePath = normalizeResourcePath;
4
+ exports.setResources = setResources;
5
+ exports.getResources = getResources;
6
+ exports.lookupResource = lookupResource;
7
+ exports.resolveSqlFromResources = resolveSqlFromResources;
8
+ const g = globalThis;
9
+ if (!g.__SQLSTACK_RESOURCES_STATE__) {
10
+ g.__SQLSTACK_RESOURCES_STATE__ = {
11
+ resources: undefined,
12
+ byKey: new Map(),
13
+ byTail: new Map(),
14
+ lookups: new Map(),
15
+ };
16
+ }
17
+ const state = g.__SQLSTACK_RESOURCES_STATE__;
18
+ const DIALECT_EXT = { postgres: 'pg', mysql: 'mysql', sqlite: 'sqlite' };
19
+ /** Forward slashes, no `file://`, no leading `./`, exactly one leading `/`. */
20
+ function normalizeResourcePath(p) {
21
+ let s = p.replace(/\\/g, '/');
22
+ if (s.startsWith('file://'))
23
+ s = s.slice('file://'.length);
24
+ s = s.replace(/^(\.\/)+/, '');
25
+ s = s.replace(/^\/+/, '');
26
+ return '/' + s;
27
+ }
28
+ function tailOf(normalized) {
29
+ const parts = normalized.split('/');
30
+ return '/' + parts.slice(-2).join('/');
31
+ }
32
+ /** Install (or clear with undefined) the process-wide packaged SQL resources. */
33
+ function setResources(map) {
34
+ state.byKey = new Map();
35
+ state.byTail = new Map();
36
+ state.lookups = new Map();
37
+ state.resources = map;
38
+ if (!map)
39
+ return;
40
+ for (const [rawKey, sql] of Object.entries(map)) {
41
+ const key = normalizeResourcePath(rawKey);
42
+ state.byKey.set(key, sql);
43
+ const tail = tailOf(key);
44
+ const list = state.byTail.get(tail);
45
+ if (list)
46
+ list.push(key);
47
+ else
48
+ state.byTail.set(tail, [key]);
49
+ }
50
+ }
51
+ function getResources() {
52
+ return state.resources;
53
+ }
54
+ /**
55
+ * Resolve one absolute (or module-tree) candidate path against the installed
56
+ * resources. Order: exact key; the longest key that is a path suffix of the
57
+ * candidate; the unique key sharing the candidate's `<folder>/<file>` tail.
58
+ */
59
+ function lookupResource(candidatePath) {
60
+ if (!state.resources)
61
+ return undefined;
62
+ const candidate = normalizeResourcePath(candidatePath);
63
+ if (state.lookups.has(candidate))
64
+ return state.lookups.get(candidate);
65
+ let found = state.byKey.get(candidate);
66
+ if (found === undefined) {
67
+ let bestLen = -1;
68
+ for (const [key, sql] of state.byKey) {
69
+ if (key.length > bestLen && candidate.endsWith(key)) {
70
+ found = sql;
71
+ bestLen = key.length;
72
+ }
73
+ }
74
+ }
75
+ if (found === undefined) {
76
+ const hits = state.byTail.get(tailOf(candidate));
77
+ if (hits && hits.length === 1)
78
+ found = state.byKey.get(hits[0]);
79
+ }
80
+ state.lookups.set(candidate, found);
81
+ return found;
82
+ }
83
+ /**
84
+ * Resolve a decorated method's SQL from the installed resources: the
85
+ * dialect-specific `<dir>/<method>.<ext>.sql` first, then `<dir>/<method>.sql`.
86
+ * Returns the tried candidate paths so a miss can be reported precisely.
87
+ */
88
+ function resolveSqlFromResources(dir, methodName, dialect) {
89
+ const base = normalizeResourcePath(dir).replace(/\/+$/, '');
90
+ const tried = [`${base}/${methodName}.${DIALECT_EXT[dialect]}.sql`, `${base}/${methodName}.sql`];
91
+ for (const candidate of tried) {
92
+ const sql = lookupResource(candidate);
93
+ if (sql !== undefined)
94
+ return { sql, tried };
95
+ }
96
+ return { sql: undefined, tried };
97
+ }
98
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/core/resources.ts"],"names":[],"mappings":";;AAwCA,sDAMC;AAQD,oCAcC;AAED,oCAEC;AAOD,wCAoBC;AAOD,0DAYC;AA5FD,MAAM,CAAC,GAAG,UAAiB,CAAC;AAC5B,IAAI,CAAC,CAAC,CAAC,4BAA4B,EAAE,CAAC;IACpC,CAAC,CAAC,4BAA4B,GAAG;QAC/B,SAAS,EAAE,SAAS;QACpB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,OAAO,EAAE,IAAI,GAAG,EAAE;KACD,CAAC;AACtB,CAAC;AACD,MAAM,KAAK,GAAmB,CAAC,CAAC,4BAA4B,CAAC;AAE7D,MAAM,WAAW,GAA4B,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAElG,+EAA+E;AAC/E,SAAgB,qBAAqB,CAAC,CAAS;IAC7C,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3D,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC1B,OAAO,GAAG,GAAG,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,MAAM,CAAC,UAAkB;IAChC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,CAAC;AAED,iFAAiF;AACjF,SAAgB,YAAY,CAAC,GAA6B;IACxD,KAAK,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IACxB,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;IACzB,KAAK,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;IAC1B,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC;IACtB,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,KAAK,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAC1C,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;YACpB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,SAAgB,YAAY;IAC1B,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,SAAgB,cAAc,CAAC,aAAqB;IAClD,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACvC,MAAM,SAAS,GAAG,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACvD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtE,IAAI,KAAK,GAAuB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;QACjB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,GAAG,CAAC,MAAM,GAAG,OAAO,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpD,KAAK,GAAG,GAAG,CAAC;gBACZ,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACjD,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CACrC,GAAW,EACX,UAAkB,EAClB,OAAgB;IAEhB,MAAM,IAAI,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,IAAI,UAAU,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,IAAI,UAAU,MAAM,CAAC,CAAC;IACjG,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACnC,CAAC","sourcesContent":["import type { Dialect } from '../registry';\n\n/**\n * Packaged SQL resources: a path-keyed map `{ '<path>/<method>.sql': '<sql>' }`\n * installed by a bundled/packaged runtime (Electron asar, Cloudflare Worker,\n * @noego/app node runner) via `SqlStack.useResources(map)`.\n *\n * Keys are file paths — absolute, or relative to the project root (the shape\n * `import.meta.glob('/server/**\\/*.sql', { eager: true, query: '?raw' })`\n * produces). Lookups match by path suffix: the decorator's guessed directory\n * plus `<method>.sql` must END WITH a key. That makes the same map valid\n * whether modules load from `/repo/server/...`, `app.asar/out/server/...`\n * or a Worker's `modules/<project>/server/...` tree, as long as the module\n * tree is not flattened.\n */\nexport type SqlResources = Record<string, string>;\n\ntype ResourcesState = {\n resources: SqlResources | undefined;\n /** normalized key → sql */\n byKey: Map<string, string>;\n /** `<folder>/<file>` tail → normalized keys sharing that tail */\n byTail: Map<string, string[]>;\n lookups: Map<string, string | undefined>;\n};\n\nconst g = globalThis as any;\nif (!g.__SQLSTACK_RESOURCES_STATE__) {\n g.__SQLSTACK_RESOURCES_STATE__ = {\n resources: undefined,\n byKey: new Map(),\n byTail: new Map(),\n lookups: new Map(),\n } as ResourcesState;\n}\nconst state: ResourcesState = g.__SQLSTACK_RESOURCES_STATE__;\n\nconst DIALECT_EXT: Record<Dialect, string> = { postgres: 'pg', mysql: 'mysql', sqlite: 'sqlite' };\n\n/** Forward slashes, no `file://`, no leading `./`, exactly one leading `/`. */\nexport function normalizeResourcePath(p: string): string {\n let s = p.replace(/\\\\/g, '/');\n if (s.startsWith('file://')) s = s.slice('file://'.length);\n s = s.replace(/^(\\.\\/)+/, '');\n s = s.replace(/^\\/+/, '');\n return '/' + s;\n}\n\nfunction tailOf(normalized: string): string {\n const parts = normalized.split('/');\n return '/' + parts.slice(-2).join('/');\n}\n\n/** Install (or clear with undefined) the process-wide packaged SQL resources. */\nexport function setResources(map: SqlResources | undefined): void {\n state.byKey = new Map();\n state.byTail = new Map();\n state.lookups = new Map();\n state.resources = map;\n if (!map) return;\n for (const [rawKey, sql] of Object.entries(map)) {\n const key = normalizeResourcePath(rawKey);\n state.byKey.set(key, sql);\n const tail = tailOf(key);\n const list = state.byTail.get(tail);\n if (list) list.push(key);\n else state.byTail.set(tail, [key]);\n }\n}\n\nexport function getResources(): SqlResources | undefined {\n return state.resources;\n}\n\n/**\n * Resolve one absolute (or module-tree) candidate path against the installed\n * resources. Order: exact key; the longest key that is a path suffix of the\n * candidate; the unique key sharing the candidate's `<folder>/<file>` tail.\n */\nexport function lookupResource(candidatePath: string): string | undefined {\n if (!state.resources) return undefined;\n const candidate = normalizeResourcePath(candidatePath);\n if (state.lookups.has(candidate)) return state.lookups.get(candidate);\n let found: string | undefined = state.byKey.get(candidate);\n if (found === undefined) {\n let bestLen = -1;\n for (const [key, sql] of state.byKey) {\n if (key.length > bestLen && candidate.endsWith(key)) {\n found = sql;\n bestLen = key.length;\n }\n }\n }\n if (found === undefined) {\n const hits = state.byTail.get(tailOf(candidate));\n if (hits && hits.length === 1) found = state.byKey.get(hits[0]);\n }\n state.lookups.set(candidate, found);\n return found;\n}\n\n/**\n * Resolve a decorated method's SQL from the installed resources: the\n * dialect-specific `<dir>/<method>.<ext>.sql` first, then `<dir>/<method>.sql`.\n * Returns the tried candidate paths so a miss can be reported precisely.\n */\nexport function resolveSqlFromResources(\n dir: string,\n methodName: string,\n dialect: Dialect\n): { sql: string | undefined; tried: string[] } {\n const base = normalizeResourcePath(dir).replace(/\\/+$/, '');\n const tried = [`${base}/${methodName}.${DIALECT_EXT[dialect]}.sql`, `${base}/${methodName}.sql`];\n for (const candidate of tried) {\n const sql = lookupResource(candidate);\n if (sql !== undefined) return { sql, tried };\n }\n return { sql: undefined, tried };\n}\n"]}
@@ -1,14 +1,14 @@
1
1
  import type { SqlResolver, SqlResolutionRequest } from './resolver';
2
2
  /**
3
- * Zero-config Node resolution for bare @Query(): lazily scans the project
4
- * tree (process.cwd(), or an explicit rootDir) for @Query classes and their
5
- * sibling .sql files, then answers Contract A lookups from the in-memory
6
- * manifest. The scan runs once, on the first bare-@Query execution.
3
+ * Opt-in Node resolution that scans a project tree (process.cwd(), or an
4
+ * explicit rootDir) for @Query classes and their sibling .sql files, then
5
+ * answers Contract A lookups from the in-memory manifest. The scan runs once
6
+ * per instance, on first resolve.
7
7
  *
8
- * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig
9
- * or the deprecated global) always take precedence, and bundled runtimes
10
- * (Cloudflare Workers) never reach it because their entrypoints install a
11
- * ManifestResolver.
8
+ * This is NOT a default. Bare @Query() resolves its own module directory
9
+ * (stack guess at decoration time) against `SqlStack.useResources(...)` or
10
+ * the filesystem; nothing walks the tree unless this resolver is installed
11
+ * explicitly via `SqlStack.useResolver` / `SqlStackConfig.resolver`.
12
12
  */
13
13
  export declare class SourceScanResolver implements SqlResolver {
14
14
  #private;
@@ -16,10 +16,4 @@ export declare class SourceScanResolver implements SqlResolver {
16
16
  constructor(rootDir?: string | undefined);
17
17
  resolve(request: SqlResolutionRequest): string | undefined;
18
18
  }
19
- /**
20
- * @internal Process-wide default used by the @Query call path when no
21
- * resolver is installed and the decorator captured no filesystem root.
22
- * Node-only: returns undefined where the filesystem is unavailable.
23
- */
24
- export declare function defaultSourceScanResolver(): SourceScanResolver | undefined;
25
19
  //# sourceMappingURL=sourceScanResolver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sourceScanResolver.d.ts","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIpE;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,YAAW,WAAW;;IAGxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAR,OAAO,CAAC,EAAE,MAAM,YAAA;IAE7C,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;CAO3D;AAID;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,kBAAkB,GAAG,SAAS,CAG1E"}
1
+ {"version":3,"file":"sourceScanResolver.d.ts","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIpE;;;;;;;;;;GAUG;AACH,qBAAa,kBAAmB,YAAW,WAAW;;IAGxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAR,OAAO,CAAC,EAAE,MAAM,YAAA;IAE7C,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,GAAG,SAAS;CAO3D"}
@@ -13,19 +13,18 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
13
13
  var _SourceScanResolver_inner;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.SourceScanResolver = void 0;
16
- exports.defaultSourceScanResolver = defaultSourceScanResolver;
17
16
  const resolver_1 = require("./resolver");
18
17
  const generateManifest_1 = require("../codegen/generateManifest");
19
18
  /**
20
- * Zero-config Node resolution for bare @Query(): lazily scans the project
21
- * tree (process.cwd(), or an explicit rootDir) for @Query classes and their
22
- * sibling .sql files, then answers Contract A lookups from the in-memory
23
- * manifest. The scan runs once, on the first bare-@Query execution.
19
+ * Opt-in Node resolution that scans a project tree (process.cwd(), or an
20
+ * explicit rootDir) for @Query classes and their sibling .sql files, then
21
+ * answers Contract A lookups from the in-memory manifest. The scan runs once
22
+ * per instance, on first resolve.
24
23
  *
25
- * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig
26
- * or the deprecated global) always take precedence, and bundled runtimes
27
- * (Cloudflare Workers) never reach it because their entrypoints install a
28
- * ManifestResolver.
24
+ * This is NOT a default. Bare @Query() resolves its own module directory
25
+ * (stack guess at decoration time) against `SqlStack.useResources(...)` or
26
+ * the filesystem; nothing walks the tree unless this resolver is installed
27
+ * explicitly via `SqlStack.useResolver` / `SqlStackConfig.resolver`.
29
28
  */
30
29
  class SourceScanResolver {
31
30
  constructor(rootDir) {
@@ -42,15 +41,4 @@ class SourceScanResolver {
42
41
  }
43
42
  exports.SourceScanResolver = SourceScanResolver;
44
43
  _SourceScanResolver_inner = new WeakMap();
45
- let defaultInstance;
46
- /**
47
- * @internal Process-wide default used by the @Query call path when no
48
- * resolver is installed and the decorator captured no filesystem root.
49
- * Node-only: returns undefined where the filesystem is unavailable.
50
- */
51
- function defaultSourceScanResolver() {
52
- if (typeof process === 'undefined' || typeof process.cwd !== 'function')
53
- return undefined;
54
- return (defaultInstance ?? (defaultInstance = new SourceScanResolver()));
55
- }
56
44
  //# sourceMappingURL=sourceScanResolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sourceScanResolver.js","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAoCA,8DAGC;AAtCD,yCAA8C;AAC9C,kEAAkE;AAElE;;;;;;;;;;GAUG;AACH,MAAa,kBAAkB;IAG7B,YAA6B,OAAgB;QAAhB,YAAO,GAAP,OAAO,CAAS;QAF7C,4CAAqC;IAEW,CAAC;IAEjD,OAAO,CAAC,OAA6B;QACnC,IAAI,CAAC,uBAAA,IAAI,iCAAO,EAAE,CAAC;YACjB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,sCAAmB,EAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,2BAAgB,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,MAAA,CAAC;QAClE,CAAC;QACD,OAAO,uBAAA,IAAI,iCAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF;AAZD,gDAYC;;AAED,IAAI,eAA+C,CAAC;AAEpD;;;;GAIG;AACH,SAAgB,yBAAyB;IACvC,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAC1F,OAAO,CAAC,eAAe,KAAf,eAAe,GAAK,IAAI,kBAAkB,EAAE,EAAC,CAAC;AACxD,CAAC","sourcesContent":["import type { SqlResolver, SqlResolutionRequest } from './resolver';\nimport { ManifestResolver } from './resolver';\nimport { scanSqlManifestSync } from '../codegen/generateManifest';\n\n/**\n * Zero-config Node resolution for bare @Query(): lazily scans the project\n * tree (process.cwd(), or an explicit rootDir) for @Query classes and their\n * sibling .sql files, then answers Contract A lookups from the in-memory\n * manifest. The scan runs once, on the first bare-@Query execution.\n *\n * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig\n * or the deprecated global) always take precedence, and bundled runtimes\n * (Cloudflare Workers) never reach it because their entrypoints install a\n * ManifestResolver.\n */\nexport class SourceScanResolver implements SqlResolver {\n #inner: ManifestResolver | undefined;\n\n constructor(private readonly rootDir?: string) {}\n\n resolve(request: SqlResolutionRequest): string | undefined {\n if (!this.#inner) {\n const { manifest } = scanSqlManifestSync(this.rootDir ?? process.cwd());\n this.#inner = new ManifestResolver(manifest, { assert: false });\n }\n return this.#inner.resolve(request);\n }\n}\n\nlet defaultInstance: SourceScanResolver | undefined;\n\n/**\n * @internal Process-wide default used by the @Query call path when no\n * resolver is installed and the decorator captured no filesystem root.\n * Node-only: returns undefined where the filesystem is unavailable.\n */\nexport function defaultSourceScanResolver(): SourceScanResolver | undefined {\n if (typeof process === 'undefined' || typeof process.cwd !== 'function') return undefined;\n return (defaultInstance ??= new SourceScanResolver());\n}\n"]}
1
+ {"version":3,"file":"sourceScanResolver.js","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AACA,yCAA8C;AAC9C,kEAAkE;AAElE;;;;;;;;;;GAUG;AACH,MAAa,kBAAkB;IAG7B,YAA6B,OAAgB;QAAhB,YAAO,GAAP,OAAO,CAAS;QAF7C,4CAAqC;IAEW,CAAC;IAEjD,OAAO,CAAC,OAA6B;QACnC,IAAI,CAAC,uBAAA,IAAI,iCAAO,EAAE,CAAC;YACjB,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,sCAAmB,EAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,2BAAgB,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,MAAA,CAAC;QAClE,CAAC;QACD,OAAO,uBAAA,IAAI,iCAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF;AAZD,gDAYC","sourcesContent":["import type { SqlResolver, SqlResolutionRequest } from './resolver';\nimport { ManifestResolver } from './resolver';\nimport { scanSqlManifestSync } from '../codegen/generateManifest';\n\n/**\n * Opt-in Node resolution that scans a project tree (process.cwd(), or an\n * explicit rootDir) for @Query classes and their sibling .sql files, then\n * answers Contract A lookups from the in-memory manifest. The scan runs once\n * per instance, on first resolve.\n *\n * This is NOT a default. Bare @Query() resolves its own module directory\n * (stack guess at decoration time) against `SqlStack.useResources(...)` or\n * the filesystem; nothing walks the tree unless this resolver is installed\n * explicitly via `SqlStack.useResolver` / `SqlStackConfig.resolver`.\n */\nexport class SourceScanResolver implements SqlResolver {\n #inner: ManifestResolver | undefined;\n\n constructor(private readonly rootDir?: string) {}\n\n resolve(request: SqlResolutionRequest): string | undefined {\n if (!this.#inner) {\n const { manifest } = scanSqlManifestSync(this.rootDir ?? process.cwd());\n this.#inner = new ManifestResolver(manifest, { assert: false });\n }\n return this.#inner.resolve(request);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"AAsBA,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,IAC9B,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,kBAAkB,wBAqW/E"}
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"AAyBA,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,IAC9B,SAAS,GAAG,EAAE,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,kBAAkB,wBA6Y/E"}
@@ -8,7 +8,7 @@ const runtime_1 = require("../runtime");
8
8
  const sqlBinder_1 = require("../binders/sqlBinder");
9
9
  const fileResolution_1 = require("../core/fileResolution");
10
10
  const resolver_1 = require("../core/resolver");
11
- const sourceScanResolver_1 = require("../core/sourceScanResolver");
11
+ const resources_1 = require("../core/resources");
12
12
  const transactions_1 = require("../transactions");
13
13
  const sql_1 = require("../sql");
14
14
  const run_1 = require("../run");
@@ -39,14 +39,20 @@ function Query(arg) {
39
39
  (0, metadata_1.setMethodLabels)(_target, prop, { source: { kind: 'inline', sql: options.sql } });
40
40
  }
41
41
  else {
42
- // FS-based resolution: only an EXPLICIT path argument pins a directory.
43
- // Bare @Query() resolves through the active resolver (or the default
44
- // SourceScanResolver) — no stack-based directory guessing, which breaks
45
- // under bundlers and test transforms.
42
+ // An EXPLICIT path argument pins a filesystem directory. Bare @Query()
43
+ // records the directory of the decorating module (first non-sqlstack
44
+ // stack frame at decoration time); at call time that directory is
45
+ // resolved against the packaged resources map when one is installed
46
+ // (SqlStack.useResources), else read from the filesystem. No tree scan.
46
47
  const { rootDir } = (0, fileResolution_1.coerceRootPath)(rootArg);
47
48
  if (rootDir) {
48
49
  (0, metadata_1.setMethodLabels)(_target, prop, { source: { kind: 'fs', rootDir } });
49
50
  }
51
+ else {
52
+ const dir = (0, fileResolution_1.guessDecoratorDir)();
53
+ if (dir)
54
+ (0, metadata_1.setMethodLabels)(_target, prop, { source: { kind: 'guess', dir } });
55
+ }
50
56
  }
51
57
  // Record for resolver coverage checks: immutable class metadata (the
52
58
  // canonical, environment-local source) plus the deprecated global list
@@ -83,26 +89,25 @@ function Query(arg) {
83
89
  }
84
90
  const db = target.db;
85
91
  const dialect = options?.dialect ?? db.dialect ?? 'sqlite';
86
- // 3) load SQL source (inline, environment resolver, v1 fs fallback,
87
- // or the zero-config source scan — bare @Query() with nothing installed)
92
+ // 3) load SQL source: inline; else an installed resolver (the
93
+ // instance's, else the process-global one — a build-time manifest
94
+ // registered by a host runner applies even when the SqlStack itself
95
+ // came from an IoC root); else the decorator's directory (explicit
96
+ // path or guessed module dir) against the packaged resources /
97
+ // filesystem.
98
+ const className = this?.constructor?.name ?? '<anonymous>';
99
+ const resolver = activeResolver ?? (0, resolver_1.getActiveResolver)();
88
100
  const sql = labels?.source?.kind === 'inline'
89
101
  ? labels.source.sql
90
- : activeResolver
91
- ? activeResolver.resolve({
92
- className: this?.constructor?.name ?? '<anonymous>',
93
- methodName: String(prop),
94
- dialect,
95
- rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,
96
- })
97
- : labels?.source?.kind === 'fs'
98
- ? (0, fileResolution_1.resolveSqlFromFs)(labels.source.rootDir, String(prop), dialect).sql
99
- : (0, sourceScanResolver_1.defaultSourceScanResolver)()?.resolve({
100
- className: this?.constructor?.name ?? '<anonymous>',
101
- methodName: String(prop),
102
- dialect,
103
- });
102
+ : (resolver?.resolve({
103
+ className,
104
+ methodName: String(prop),
105
+ dialect,
106
+ rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,
107
+ }) ?? resolveSourceSql(labels?.source, className, String(prop), dialect));
104
108
  if (!sql) {
105
- throw new errors_1.SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);
109
+ throw new errors_1.SqlStackError(`No SQL source for ${className}.${String(prop)}: the decorating module's directory could not be ` +
110
+ 'determined from the stack. Use @Query() with a file/folder path or inline sql.');
106
111
  }
107
112
  onSql(sql);
108
113
  // 4) bind placeholders
@@ -314,11 +319,43 @@ function Query(arg) {
314
319
  const resolved = await (0, runtime_1.resolveExecution)(dbName);
315
320
  return {
316
321
  db: resolved.entry.db,
317
- tx: (0, transactions_1.getActiveTransaction)(resolved.entry),
322
+ tx: (0, transactions_1.getTransactionTarget)(resolved.entry),
318
323
  resolver: resolved.resolver,
319
324
  byName: true,
320
325
  };
321
326
  };
327
+ // The method's own leading database argument: a handle (object with
328
+ // query()) or a registered database name. It selects run()'s target
329
+ // and is never bound as a value.
330
+ const leadingDb = async () => {
331
+ if (callArgs.length === 0)
332
+ return undefined;
333
+ const first = callArgs[0];
334
+ if ((0, run_1.isRunDatabaseHandle)(first))
335
+ return first;
336
+ if (typeof first === 'string' && first.length > 0 && (await (0, runtime_1.isRegisteredDatabaseName)(first)))
337
+ return first;
338
+ return undefined;
339
+ };
340
+ // A database chosen by run's argument or the method's leading argument.
341
+ const explicitTarget = async (db) => {
342
+ const target = await (0, run_1.resolveRunTarget)(db);
343
+ // Inline SQL needs no resolver; only look one up for file-based SQL.
344
+ const resolver = target.byName
345
+ ? target.resolver
346
+ : labels?.source?.kind === 'inline'
347
+ ? undefined
348
+ : await (0, runtime_1.resolveSqlResolver)();
349
+ return { target, resolver };
350
+ };
351
+ // run() (and the legacy fallback): the method's arguments minus a
352
+ // leading database, on that database or the decorator context.
353
+ const executeDefault = async (onSql) => {
354
+ const lead = await leadingDb();
355
+ if (lead === undefined)
356
+ return executeMethodSql(callArgs, undefined, onSql);
357
+ return executeMethodSql(callArgs.slice(1), await explicitTarget(lead), onSql);
358
+ };
322
359
  // run's argument-taking forms: return the adapter's raw result.
323
360
  const executeInvocation = async (invocation, onSql) => {
324
361
  if (invocation.kind === 'fragment') {
@@ -330,17 +367,19 @@ function Query(arg) {
330
367
  onSql(boundSql);
331
368
  return (0, run_1.executeOnTarget)(target, boundSql, params);
332
369
  }
333
- // run(db, params): the method's own SQL against db, bound from params
334
- // only (an object for :named, an array for :argN).
335
- const target = await (0, run_1.resolveRunTarget)(invocation.db);
336
- // Inline SQL needs no resolver; only look one up for file-based SQL.
337
- const resolver = target.byName
338
- ? target.resolver
339
- : labels?.source?.kind === 'inline'
340
- ? undefined
341
- : await (0, runtime_1.resolveSqlResolver)();
370
+ if (invocation.kind === 'db') {
371
+ // run(db): the method's own SQL against db, bound from the method's
372
+ // arguments minus a leading database argument.
373
+ const lead = await leadingDb();
374
+ const bindArgs = lead === undefined ? callArgs : callArgs.slice(1);
375
+ return executeMethodSql(bindArgs, await explicitTarget(invocation.db), onSql);
376
+ }
377
+ // run(db, params) / run(params): the method's own SQL bound from params
378
+ // only (an object for :named, an array for :argN), against run's db,
379
+ // else the method's leading database, else the decorator context.
342
380
  const bindArgs = Array.isArray(invocation.params) ? [...invocation.params] : [invocation.params];
343
- return executeMethodSql(bindArgs, { target, resolver }, onSql);
381
+ const db = invocation.db ?? (await leadingDb());
382
+ return executeMethodSql(bindArgs, db !== undefined ? await explicitTarget(db) : undefined, onSql);
344
383
  };
345
384
  // The full pipeline: execute, then — if rows were returned
346
385
  // (SELECT/CTE/RETURNING) — shape + transform + validate; a write result
@@ -352,7 +391,7 @@ function Query(arg) {
352
391
  // DatabaseError with the original error in `.cause`.
353
392
  const pipeline = async (invocation) => {
354
393
  if (invocation === undefined || invocation.kind === 'default') {
355
- const out = await executeMethodSql(callArgs, undefined, () => { });
394
+ const out = await executeDefault(() => { });
356
395
  return finishResult(out, labels, this, prop);
357
396
  }
358
397
  let sqlText = invocation.kind === 'fragment' ? (0, run_1.fragmentText)(invocation.fragment) : '';
@@ -396,7 +435,7 @@ function Query(arg) {
396
435
  const db = entry.db;
397
436
  let out;
398
437
  try {
399
- const tx = (0, transactions_1.getActiveTransaction)(entry);
438
+ const tx = (0, transactions_1.getTransactionTarget)(entry);
400
439
  out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);
401
440
  }
402
441
  catch (dbError) {
@@ -409,6 +448,28 @@ function Query(arg) {
409
448
  return desc;
410
449
  };
411
450
  }
451
+ // Directory-based SQL for a decorated method. An explicit @Query('<path>')
452
+ // is always the filesystem. A bare @Query() uses the packaged resources map
453
+ // when one is installed (bundled/packaged runtimes), else the filesystem next
454
+ // to the decorating module (tests, plain Node). Misses name every key tried.
455
+ function resolveSourceSql(source, className, methodName, dialect) {
456
+ if (!source || source.kind === 'inline')
457
+ return undefined;
458
+ if (source.kind === 'fs')
459
+ return (0, fileResolution_1.resolveSqlFromFs)(source.rootDir, methodName, dialect).sql;
460
+ const packaged = (0, resources_1.getResources)();
461
+ const fromResources = packaged ? (0, resources_1.resolveSqlFromResources)(source.dir, methodName, dialect) : undefined;
462
+ if (fromResources?.sql !== undefined)
463
+ return fromResources.sql;
464
+ try {
465
+ return (0, fileResolution_1.resolveSqlFromFs)(source.dir, methodName, dialect).sql;
466
+ }
467
+ catch (fsError) {
468
+ const triedResources = fromResources ? `\npackaged resources tried:\n${fromResources.tried.join('\n')}` : '';
469
+ throw new errors_1.SqlStackError(`sqlstack: no SQL for ${className}.${methodName}.${triedResources}\n` +
470
+ `${fsError?.message ?? String(fsError)}`);
471
+ }
472
+ }
412
473
  // Deprecated (removal in the next major version): a @Query body that RETURNS
413
474
  // an sql`` fragment. It only type-checks when the method's declared return
414
475
  // type is bent to admit SqlFragment (an `as any`-style hole). One warning per