sqlstack 1.0.25 → 2.0.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 (46) hide show
  1. package/dist/cjs/adapters/mysql.d.ts.map +1 -1
  2. package/dist/cjs/adapters/mysql.js +3 -3
  3. package/dist/cjs/adapters/mysql.js.map +1 -1
  4. package/dist/cjs/adapters/pg.d.ts.map +1 -1
  5. package/dist/cjs/adapters/pg.js +3 -3
  6. package/dist/cjs/adapters/pg.js.map +1 -1
  7. package/dist/cjs/codegen/cli.d.ts +3 -0
  8. package/dist/cjs/codegen/cli.d.ts.map +1 -0
  9. package/dist/cjs/codegen/cli.js +50 -0
  10. package/dist/cjs/codegen/cli.js.map +1 -0
  11. package/dist/cjs/codegen/generateManifest.d.ts +60 -0
  12. package/dist/cjs/codegen/generateManifest.d.ts.map +1 -0
  13. package/dist/cjs/codegen/generateManifest.js +181 -0
  14. package/dist/cjs/codegen/generateManifest.js.map +1 -0
  15. package/dist/cjs/core/loadNodeModule.d.ts +17 -0
  16. package/dist/cjs/core/loadNodeModule.d.ts.map +1 -0
  17. package/dist/cjs/core/loadNodeModule.js +36 -0
  18. package/dist/cjs/core/loadNodeModule.js.map +1 -0
  19. package/dist/cjs/core/resolver.d.ts +81 -0
  20. package/dist/cjs/core/resolver.d.ts.map +1 -0
  21. package/dist/cjs/core/resolver.js +99 -0
  22. package/dist/cjs/core/resolver.js.map +1 -0
  23. package/dist/cjs/decorators/query.d.ts.map +1 -1
  24. package/dist/cjs/decorators/query.js +19 -4
  25. package/dist/cjs/decorators/query.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 +6 -1
  29. package/dist/cjs/index.js.map +1 -1
  30. package/dist/esm/adapters/mysql.js +3 -3
  31. package/dist/esm/adapters/mysql.js.map +1 -1
  32. package/dist/esm/adapters/pg.js +3 -3
  33. package/dist/esm/adapters/pg.js.map +1 -1
  34. package/dist/esm/codegen/cli.js +48 -0
  35. package/dist/esm/codegen/cli.js.map +1 -0
  36. package/dist/esm/codegen/generateManifest.js +174 -0
  37. package/dist/esm/codegen/generateManifest.js.map +1 -0
  38. package/dist/esm/core/loadNodeModule.js +33 -0
  39. package/dist/esm/core/loadNodeModule.js.map +1 -0
  40. package/dist/esm/core/resolver.js +92 -0
  41. package/dist/esm/core/resolver.js.map +1 -0
  42. package/dist/esm/decorators/query.js +19 -4
  43. package/dist/esm/decorators/query.js.map +1 -1
  44. package/dist/esm/index.js +1 -0
  45. package/dist/esm/index.js.map +1 -1
  46. package/package.json +12 -3
@@ -0,0 +1,174 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { MANIFEST_DIALECT_EXT } from '../core/resolver.js';
4
+ /**
5
+ * Build-time SQL manifest generation (Contract A).
6
+ *
7
+ * Scans a source tree for @Query-decorated class methods, pairs each with its
8
+ * sibling `.sql` files (same directory as the declaring source file, filename =
9
+ * method name, optional dialect suffix), and emits a generated module:
10
+ *
11
+ * export const sqlManifest = {
12
+ * '<ClassName>.<methodName>.<dialectExt>': '<sql>',
13
+ * '<ClassName>.<methodName>': '<sql>',
14
+ * };
15
+ *
16
+ * The `.sql` files on disk remain the source of truth — the generated module
17
+ * inlines their text and is never hand-edited.
18
+ *
19
+ * Requirements policed here:
20
+ * - Class names must be unique across the scanned tree (manifest keys are
21
+ * class-name scoped) — duplicates are a build error.
22
+ * - Consumers must not minify class names away (esbuild `keepNames`,
23
+ * terser `keep_classnames`) — documented in docs/codegen.md.
24
+ */
25
+ const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs']);
26
+ const DEFAULT_EXCLUDES = new Set(['node_modules', 'dist', 'build', 'coverage', '.git']);
27
+ function walkSourceFiles(rootDir, exclude) {
28
+ const out = [];
29
+ const stack = [rootDir];
30
+ while (stack.length) {
31
+ const dir = stack.pop();
32
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
33
+ if (entry.isDirectory()) {
34
+ if (!exclude.has(entry.name))
35
+ stack.push(path.join(dir, entry.name));
36
+ continue;
37
+ }
38
+ const ext = path.extname(entry.name);
39
+ if (!SOURCE_EXTENSIONS.has(ext))
40
+ continue;
41
+ if (entry.name.endsWith('.d.ts'))
42
+ continue;
43
+ out.push(path.join(dir, entry.name));
44
+ }
45
+ }
46
+ return out.sort();
47
+ }
48
+ const CLASS_RE = /(?:^|[\s;{}(])class\s+([A-Za-z_$][\w$]*)/g;
49
+ const QUERY_RE = /@Query\s*(?:\(([^)]*)\))?\s*(?:public\s+|private\s+|protected\s+)?(?:async\s+)?([A-Za-z_$][\w$]*)\s*[(<]/g;
50
+ /**
51
+ * Regex-based discovery: each @Query method is attributed to the nearest
52
+ * preceding `class` declaration in the same file. Inline queries are detected
53
+ * by a `sql:` property in the decorator arguments (see docs/codegen.md for the
54
+ * documented limitations of this heuristic).
55
+ */
56
+ export function scanSourceForQueryMethods(source, sourcePath) {
57
+ const classes = [];
58
+ for (const m of source.matchAll(CLASS_RE)) {
59
+ classes.push({ name: m[1], index: m.index ?? 0 });
60
+ }
61
+ if (!classes.length)
62
+ return [];
63
+ const found = [];
64
+ for (const m of source.matchAll(QUERY_RE)) {
65
+ const at = m.index ?? 0;
66
+ let owner;
67
+ for (const c of classes) {
68
+ if (c.index < at)
69
+ owner = c.name;
70
+ else
71
+ break;
72
+ }
73
+ if (!owner)
74
+ continue;
75
+ const args = m[1] ?? '';
76
+ found.push({
77
+ className: owner,
78
+ methodName: m[2],
79
+ inline: /\bsql\s*:/.test(args),
80
+ sourcePath,
81
+ });
82
+ }
83
+ return found;
84
+ }
85
+ function renderModule(manifest, entries, format, rootDir) {
86
+ const byKey = new Map(entries.map((e) => [e.key, e]));
87
+ const lines = [
88
+ '// GENERATED by sqlstack-codegen. DO NOT EDIT.',
89
+ '// Source of truth: the .sql files referenced beside each entry.',
90
+ format === 'ts'
91
+ ? 'export const sqlManifest: Record<string, string> = {'
92
+ : 'export const sqlManifest = {',
93
+ ];
94
+ for (const key of Object.keys(manifest).sort()) {
95
+ const entry = byKey.get(key);
96
+ const from = entry ? path.relative(rootDir, entry.sqlPath) : '';
97
+ lines.push(` ${JSON.stringify(key)}: ${JSON.stringify(manifest[key])},${from ? ` // ${from}` : ''}`);
98
+ }
99
+ lines.push('};', '');
100
+ return lines.join('\n');
101
+ }
102
+ /**
103
+ * Programmatic entry point — also used by the CLI (`sqlstack-codegen`) and
104
+ * callable from application build pipelines.
105
+ */
106
+ export async function generateSqlManifest(options) {
107
+ const rootDir = path.resolve(options.rootDir);
108
+ if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {
109
+ throw new Error(`sqlstack-codegen: rootDir is not a directory: ${rootDir}`);
110
+ }
111
+ const exclude = new Set([...DEFAULT_EXCLUDES, ...(options.exclude ?? [])]);
112
+ // 1) discover @Query methods
113
+ const discovered = [];
114
+ for (const file of walkSourceFiles(rootDir, exclude)) {
115
+ discovered.push(...scanSourceForQueryMethods(fs.readFileSync(file, 'utf8'), file));
116
+ }
117
+ // 2) police duplicate class names (manifest keys are class-scoped)
118
+ const filesByClass = new Map();
119
+ for (const d of discovered) {
120
+ if (!filesByClass.has(d.className))
121
+ filesByClass.set(d.className, new Set());
122
+ filesByClass.get(d.className).add(d.sourcePath);
123
+ }
124
+ const duplicates = [...filesByClass.entries()].filter(([, files]) => files.size > 1);
125
+ if (duplicates.length) {
126
+ throw new Error('sqlstack-codegen: duplicate @Query class names (manifest keys are class-name scoped; rename one):\n' +
127
+ duplicates
128
+ .map(([name, files]) => ` - ${name}:\n${[...files].map((f) => ` ${f}`).join('\n')}`)
129
+ .join('\n'));
130
+ }
131
+ // 3) pair each non-inline method with sibling .sql files
132
+ const manifest = {};
133
+ const entries = [];
134
+ const missing = [];
135
+ const seen = new Set();
136
+ for (const d of discovered) {
137
+ if (d.inline)
138
+ continue;
139
+ const id = `${d.className}.${d.methodName}`;
140
+ if (seen.has(id))
141
+ continue;
142
+ seen.add(id);
143
+ const dir = path.dirname(d.sourcePath);
144
+ let matched = false;
145
+ const genericPath = path.join(dir, `${d.methodName}.sql`);
146
+ if (fs.existsSync(genericPath)) {
147
+ manifest[id] = fs.readFileSync(genericPath, 'utf8');
148
+ entries.push({ key: id, className: d.className, methodName: d.methodName, sqlPath: genericPath });
149
+ matched = true;
150
+ }
151
+ for (const ext of Object.values(MANIFEST_DIALECT_EXT)) {
152
+ const dialectPath = path.join(dir, `${d.methodName}.${ext}.sql`);
153
+ if (fs.existsSync(dialectPath)) {
154
+ const key = `${id}.${ext}`;
155
+ manifest[key] = fs.readFileSync(dialectPath, 'utf8');
156
+ entries.push({ key, className: d.className, methodName: d.methodName, dialectExt: ext, sqlPath: dialectPath });
157
+ matched = true;
158
+ }
159
+ }
160
+ if (!matched)
161
+ missing.push({ className: d.className, methodName: d.methodName, sourcePath: d.sourcePath });
162
+ }
163
+ // 4) emit
164
+ const outFile = path.resolve(options.outFile ?? path.join(rootDir, 'sql-manifest.mjs'));
165
+ const format = options.format ?? (outFile.endsWith('.ts') ? 'ts' : 'mjs');
166
+ const code = renderModule(manifest, entries, format, rootDir);
167
+ if (options.write !== false) {
168
+ fs.mkdirSync(path.dirname(outFile), { recursive: true });
169
+ fs.writeFileSync(outFile, code);
170
+ return { manifest, entries, missing, code, outFile };
171
+ }
172
+ return { manifest, entries, missing, code };
173
+ }
174
+ //# sourceMappingURL=generateManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateManifest.js","sourceRoot":"","sources":["../../../src/codegen/generateManifest.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { MANIFEST_DIALECT_EXT } from '../core/resolver';\n\n/**\n * Build-time SQL manifest generation (Contract A).\n *\n * Scans a source tree for @Query-decorated class methods, pairs each with its\n * sibling `.sql` files (same directory as the declaring source file, filename =\n * method name, optional dialect suffix), and emits a generated module:\n *\n * export const sqlManifest = {\n * '<ClassName>.<methodName>.<dialectExt>': '<sql>',\n * '<ClassName>.<methodName>': '<sql>',\n * };\n *\n * The `.sql` files on disk remain the source of truth — the generated module\n * inlines their text and is never hand-edited.\n *\n * Requirements policed here:\n * - Class names must be unique across the scanned tree (manifest keys are\n * class-name scoped) — duplicates are a build error.\n * - Consumers must not minify class names away (esbuild `keepNames`,\n * terser `keep_classnames`) — documented in docs/codegen.md.\n */\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.mts', '.cts', '.js', '.mjs', '.cjs']);\nconst DEFAULT_EXCLUDES = new Set(['node_modules', 'dist', 'build', 'coverage', '.git']);\n\nexport type GenerateSqlManifestOptions = {\n /** Directory to scan recursively for @Query classes and sibling .sql files. */\n rootDir: string;\n /**\n * Output path for the generated module. Default: `<rootDir>/sql-manifest.mjs`.\n * Extension selects the format when `format` is not given (.ts → ts, else mjs).\n */\n outFile?: string;\n /** 'mjs' (default) emits an ES module; 'ts' emits a typed TS source variant. */\n format?: 'mjs' | 'ts';\n /** Write the generated module to outFile. Default true; false = dry run. */\n write?: boolean;\n /** Directory names to skip while walking. Defaults to node_modules/dist/build/coverage/.git. */\n exclude?: string[];\n};\n\nexport type SqlManifestEntry = {\n key: string;\n className: string;\n methodName: string;\n /** pg | mysql | sqlite for dialect-specific entries; undefined for generic. */\n dialectExt?: string;\n /** Absolute path of the .sql source file. */\n sqlPath: string;\n};\n\nexport type MissingSqlMethod = {\n className: string;\n methodName: string;\n /** Source file that declares the @Query method. */\n sourcePath: string;\n};\n\nexport type GenerateSqlManifestResult = {\n manifest: Record<string, string>;\n entries: SqlManifestEntry[];\n /** Non-inline @Query methods with no sibling .sql file (assertion will catch at startup). */\n missing: MissingSqlMethod[];\n /** The generated module source. */\n code: string;\n /** Absolute path written to (present when write !== false). */\n outFile?: string;\n};\n\ntype DiscoveredMethod = {\n className: string;\n methodName: string;\n inline: boolean;\n sourcePath: string;\n};\n\nfunction walkSourceFiles(rootDir: string, exclude: Set<string>): string[] {\n const out: string[] = [];\n const stack = [rootDir];\n while (stack.length) {\n const dir = stack.pop()!;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!exclude.has(entry.name)) stack.push(path.join(dir, entry.name));\n continue;\n }\n const ext = path.extname(entry.name);\n if (!SOURCE_EXTENSIONS.has(ext)) continue;\n if (entry.name.endsWith('.d.ts')) continue;\n out.push(path.join(dir, entry.name));\n }\n }\n return out.sort();\n}\n\nconst CLASS_RE = /(?:^|[\\s;{}(])class\\s+([A-Za-z_$][\\w$]*)/g;\nconst QUERY_RE =\n /@Query\\s*(?:\\(([^)]*)\\))?\\s*(?:public\\s+|private\\s+|protected\\s+)?(?:async\\s+)?([A-Za-z_$][\\w$]*)\\s*[(<]/g;\n\n/**\n * Regex-based discovery: each @Query method is attributed to the nearest\n * preceding `class` declaration in the same file. Inline queries are detected\n * by a `sql:` property in the decorator arguments (see docs/codegen.md for the\n * documented limitations of this heuristic).\n */\nexport function scanSourceForQueryMethods(source: string, sourcePath: string): DiscoveredMethod[] {\n const classes: { name: string; index: number }[] = [];\n for (const m of source.matchAll(CLASS_RE)) {\n classes.push({ name: m[1]!, index: m.index ?? 0 });\n }\n if (!classes.length) return [];\n\n const found: DiscoveredMethod[] = [];\n for (const m of source.matchAll(QUERY_RE)) {\n const at = m.index ?? 0;\n let owner: string | undefined;\n for (const c of classes) {\n if (c.index < at) owner = c.name;\n else break;\n }\n if (!owner) continue;\n const args = m[1] ?? '';\n found.push({\n className: owner,\n methodName: m[2]!,\n inline: /\\bsql\\s*:/.test(args),\n sourcePath,\n });\n }\n return found;\n}\n\nfunction renderModule(\n manifest: Record<string, string>,\n entries: SqlManifestEntry[],\n format: 'mjs' | 'ts',\n rootDir: string\n): string {\n const byKey = new Map(entries.map((e) => [e.key, e]));\n const lines: string[] = [\n '// GENERATED by sqlstack-codegen. DO NOT EDIT.',\n '// Source of truth: the .sql files referenced beside each entry.',\n format === 'ts'\n ? 'export const sqlManifest: Record<string, string> = {'\n : 'export const sqlManifest = {',\n ];\n for (const key of Object.keys(manifest).sort()) {\n const entry = byKey.get(key);\n const from = entry ? path.relative(rootDir, entry.sqlPath) : '';\n lines.push(` ${JSON.stringify(key)}: ${JSON.stringify(manifest[key])},${from ? ` // ${from}` : ''}`);\n }\n lines.push('};', '');\n return lines.join('\\n');\n}\n\n/**\n * Programmatic entry point — also used by the CLI (`sqlstack-codegen`) and\n * callable from application build pipelines.\n */\nexport async function generateSqlManifest(\n options: GenerateSqlManifestOptions\n): Promise<GenerateSqlManifestResult> {\n const rootDir = path.resolve(options.rootDir);\n if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {\n throw new Error(`sqlstack-codegen: rootDir is not a directory: ${rootDir}`);\n }\n const exclude = new Set([...DEFAULT_EXCLUDES, ...(options.exclude ?? [])]);\n\n // 1) discover @Query methods\n const discovered: DiscoveredMethod[] = [];\n for (const file of walkSourceFiles(rootDir, exclude)) {\n discovered.push(...scanSourceForQueryMethods(fs.readFileSync(file, 'utf8'), file));\n }\n\n // 2) police duplicate class names (manifest keys are class-scoped)\n const filesByClass = new Map<string, Set<string>>();\n for (const d of discovered) {\n if (!filesByClass.has(d.className)) filesByClass.set(d.className, new Set());\n filesByClass.get(d.className)!.add(d.sourcePath);\n }\n const duplicates = [...filesByClass.entries()].filter(([, files]) => files.size > 1);\n if (duplicates.length) {\n throw new Error(\n 'sqlstack-codegen: duplicate @Query class names (manifest keys are class-name scoped; rename one):\\n' +\n duplicates\n .map(([name, files]) => ` - ${name}:\\n${[...files].map((f) => ` ${f}`).join('\\n')}`)\n .join('\\n')\n );\n }\n\n // 3) pair each non-inline method with sibling .sql files\n const manifest: Record<string, string> = {};\n const entries: SqlManifestEntry[] = [];\n const missing: MissingSqlMethod[] = [];\n const seen = new Set<string>();\n for (const d of discovered) {\n if (d.inline) continue;\n const id = `${d.className}.${d.methodName}`;\n if (seen.has(id)) continue;\n seen.add(id);\n\n const dir = path.dirname(d.sourcePath);\n let matched = false;\n\n const genericPath = path.join(dir, `${d.methodName}.sql`);\n if (fs.existsSync(genericPath)) {\n manifest[id] = fs.readFileSync(genericPath, 'utf8');\n entries.push({ key: id, className: d.className, methodName: d.methodName, sqlPath: genericPath });\n matched = true;\n }\n for (const ext of Object.values(MANIFEST_DIALECT_EXT)) {\n const dialectPath = path.join(dir, `${d.methodName}.${ext}.sql`);\n if (fs.existsSync(dialectPath)) {\n const key = `${id}.${ext}`;\n manifest[key] = fs.readFileSync(dialectPath, 'utf8');\n entries.push({ key, className: d.className, methodName: d.methodName, dialectExt: ext, sqlPath: dialectPath });\n matched = true;\n }\n }\n if (!matched) missing.push({ className: d.className, methodName: d.methodName, sourcePath: d.sourcePath });\n }\n\n // 4) emit\n const outFile = path.resolve(options.outFile ?? path.join(rootDir, 'sql-manifest.mjs'));\n const format = options.format ?? (outFile.endsWith('.ts') ? 'ts' : 'mjs');\n const code = renderModule(manifest, entries, format, rootDir);\n\n if (options.write !== false) {\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\n fs.writeFileSync(outFile, code);\n return { manifest, entries, missing, code, outFile };\n }\n return { manifest, entries, missing, code };\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Synchronously load an optional Node module (database driver) from both
3
+ * build flavors:
4
+ * - CJS build: plain `require`.
5
+ * - ESM build: `require` does not exist, and the loading functions are
6
+ * synchronous so dynamic `import()` is not an option. Node >= 20.16 / 22.3
7
+ * exposes `process.getBuiltinModule`, which lets us reach
8
+ * `module.createRequire` without a static `node:` import — keeping this
9
+ * file portable to non-Node bundlers (Cloudflare Workers), where neither
10
+ * branch activates and the caller's error message stands.
11
+ *
12
+ * Resolution base under ESM is the process working directory, which is the
13
+ * application root in normal usage — the same node_modules that would host
14
+ * an optional driver dependency.
15
+ */
16
+ export function loadNodeModule(specifier) {
17
+ if (typeof require === 'function') {
18
+ return require(specifier);
19
+ }
20
+ const getBuiltin = globalThis?.process?.getBuiltinModule;
21
+ if (typeof getBuiltin === 'function') {
22
+ const nodeModule = getBuiltin('module');
23
+ const nodePath = getBuiltin('path');
24
+ const nodeUrl = getBuiltin('url');
25
+ if (nodeModule?.createRequire && nodePath && nodeUrl) {
26
+ const base = nodeUrl.pathToFileURL(nodePath.join(process.cwd(), '__sqlstack_resolver__.js')).href;
27
+ return nodeModule.createRequire(base)(specifier);
28
+ }
29
+ }
30
+ throw new Error(`sqlstack: cannot load "${specifier}" in this runtime (no require/createRequire available). ` +
31
+ 'Construct the driver connection yourself and pass it in instead of a connection string.');
32
+ }
33
+ //# sourceMappingURL=loadNodeModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadNodeModule.js","sourceRoot":"","sources":["../../../src/core/loadNodeModule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,UAAU,GAAI,UAAkB,EAAE,OAAO,EAAE,gBAAgB,CAAC;IAClE,IAAI,OAAO,UAAU,KAAK,UAAU,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,UAAU,EAAE,aAAa,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;YACrD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAC,IAAI,CAAC;YAClG,OAAO,UAAU,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CACb,0BAA0B,SAAS,0DAA0D;QAC3F,yFAAyF,CAC5F,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Synchronously load an optional Node module (database driver) from both\n * build flavors:\n * - CJS build: plain `require`.\n * - ESM build: `require` does not exist, and the loading functions are\n * synchronous so dynamic `import()` is not an option. Node >= 20.16 / 22.3\n * exposes `process.getBuiltinModule`, which lets us reach\n * `module.createRequire` without a static `node:` import — keeping this\n * file portable to non-Node bundlers (Cloudflare Workers), where neither\n * branch activates and the caller's error message stands.\n *\n * Resolution base under ESM is the process working directory, which is the\n * application root in normal usage — the same node_modules that would host\n * an optional driver dependency.\n */\nexport function loadNodeModule(specifier: string): any {\n if (typeof require === 'function') {\n return require(specifier);\n }\n const getBuiltin = (globalThis as any)?.process?.getBuiltinModule;\n if (typeof getBuiltin === 'function') {\n const nodeModule = getBuiltin('module');\n const nodePath = getBuiltin('path');\n const nodeUrl = getBuiltin('url');\n if (nodeModule?.createRequire && nodePath && nodeUrl) {\n const base = nodeUrl.pathToFileURL(nodePath.join(process.cwd(), '__sqlstack_resolver__.js')).href;\n return nodeModule.createRequire(base)(specifier);\n }\n }\n throw new Error(\n `sqlstack: cannot load \"${specifier}\" in this runtime (no require/createRequire available). ` +\n 'Construct the driver connection yourself and pass it in instead of a connection string.'\n );\n}\n"]}
@@ -0,0 +1,92 @@
1
+ import { resolveSqlFromFs } from './fileResolution.js';
2
+ /**
3
+ * Dialect → manifest key suffix. Mirrors the on-disk file convention
4
+ * (`findByEmail.pg.sql` → key `UsersRepo.findByEmail.pg`).
5
+ */
6
+ export const MANIFEST_DIALECT_EXT = {
7
+ postgres: 'pg',
8
+ mysql: 'mysql',
9
+ sqlite: 'sqlite',
10
+ };
11
+ /**
12
+ * Node filesystem resolution — the v1 behavior, unchanged: dialect-specific
13
+ * `<method>.<ext>.sql` first, then generic `<method>.sql`, from the rootDir
14
+ * the decorator captured (explicit argument or stack-based directory guess).
15
+ */
16
+ export class FsResolver {
17
+ resolve({ rootDir, methodName, dialect }) {
18
+ if (!rootDir)
19
+ return undefined;
20
+ return resolveSqlFromFs(rootDir, methodName, dialect).sql;
21
+ }
22
+ }
23
+ /**
24
+ * Build-time manifest resolution — bundling-proof (Cloudflare Workers).
25
+ * Lookup order per Contract A:
26
+ * 1. `${className}.${methodName}.${dialectExt}`
27
+ * 2. `${className}.${methodName}` (generic fallback)
28
+ */
29
+ export class ManifestResolver {
30
+ constructor(manifest, options = {}) {
31
+ this.manifest = manifest;
32
+ this.options = options;
33
+ }
34
+ resolve({ className, methodName, dialect }) {
35
+ const ext = MANIFEST_DIALECT_EXT[dialect];
36
+ return (this.manifest[`${className}.${methodName}.${ext}`] ??
37
+ this.manifest[`${className}.${methodName}`]);
38
+ }
39
+ /** True when the manifest has a generic or any dialect-specific entry. */
40
+ hasEntryFor(className, methodName) {
41
+ const generic = `${className}.${methodName}`;
42
+ if (generic in this.manifest)
43
+ return true;
44
+ return Object.values(MANIFEST_DIALECT_EXT).some((ext) => `${generic}.${ext}` in this.manifest);
45
+ }
46
+ }
47
+ // Single shared state across module copies (same pattern as SqlStackDB).
48
+ const g = globalThis;
49
+ if (!g.__SQLSTACK_RESOLVER_STATE__) {
50
+ g.__SQLSTACK_RESOLVER_STATE__ = { resolver: undefined, decorated: [] };
51
+ }
52
+ const state = g.__SQLSTACK_RESOLVER_STATE__;
53
+ /** @internal Called by the @Query decorator at class-definition time. */
54
+ export function registerDecoratedMethod(entry) {
55
+ state.decorated.push(entry);
56
+ }
57
+ /** @internal Read by the @Query call path. */
58
+ export function getActiveResolver() {
59
+ return state.resolver;
60
+ }
61
+ function assertManifestCovers(resolver) {
62
+ const missing = state.decorated
63
+ .filter((m) => !m.inline)
64
+ .filter((m) => !resolver.hasEntryFor(m.className, m.methodName))
65
+ .map((m) => `${m.className}.${m.methodName}`);
66
+ if (missing.length) {
67
+ throw new Error('sqlstack: ManifestResolver has no SQL for these @Query methods:\n' +
68
+ missing.map((k) => ` - ${k}`).join('\n') +
69
+ '\nRegenerate the manifest (see docs/codegen.md), or pass ' +
70
+ '{ assert: false } if these methods return a SqlFragment from their body.');
71
+ }
72
+ }
73
+ /**
74
+ * Resolver registration surface (Contract A):
75
+ * SqlStack.useResolver(new ManifestResolver(sqlManifest))
76
+ * Call at app startup, after repository classes have been imported
77
+ * (decoration populates the coverage check).
78
+ * With no resolver registered, @Query resolves via the filesystem exactly
79
+ * as in v1.
80
+ */
81
+ export const SqlStack = {
82
+ useResolver(resolver) {
83
+ if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {
84
+ assertManifestCovers(resolver);
85
+ }
86
+ state.resolver = resolver;
87
+ },
88
+ clearResolver() {
89
+ state.resolver = undefined;
90
+ },
91
+ };
92
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../src/core/resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Dialect } from '../registry';\nimport { resolveSqlFromFs } from './fileResolution';\n\n/**\n * Dialect → manifest key suffix. Mirrors the on-disk file convention\n * (`findByEmail.pg.sql` → key `UsersRepo.findByEmail.pg`).\n */\nexport const MANIFEST_DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\n/**\n * Generated SQL manifest shape (see docs/resolver_architecture.md, Contract A):\n * { '<ClassName>.<methodName>.<dialectExt>': '<sql>', '<ClassName>.<methodName>': '<sql>' }\n */\nexport type SqlManifest = Record<string, string>;\n\nexport type SqlResolutionRequest = {\n className: string;\n methodName: string;\n dialect: Dialect;\n /** Present when the @Query decorator resolved a filesystem root (Node only). */\n rootDir?: string;\n};\n\n/**\n * Strategy for turning a decorated @Query method into a SQL string.\n * The public @Query API is identical under every resolver.\n */\nexport interface SqlResolver {\n /** Return the SQL for the request, or undefined when this resolver has none. */\n resolve(request: SqlResolutionRequest): string | undefined;\n}\n\n/**\n * Node filesystem resolution — the v1 behavior, unchanged: dialect-specific\n * `<method>.<ext>.sql` first, then generic `<method>.sql`, from the rootDir\n * the decorator captured (explicit argument or stack-based directory guess).\n */\nexport class FsResolver implements SqlResolver {\n resolve({ rootDir, methodName, dialect }: SqlResolutionRequest): string | undefined {\n if (!rootDir) return undefined;\n return resolveSqlFromFs(rootDir, methodName, dialect).sql;\n }\n}\n\nexport type ManifestResolverOptions = {\n /**\n * Validate at registration time that every decorated @Query method has a\n * manifest entry (fail fast, earlier than v1's lazy fs lookup).\n * Default true. Set false when some @Query methods build their SQL by\n * returning a SqlFragment from the method body — those never consult the\n * manifest and cannot be distinguished statically.\n */\n assert?: boolean;\n};\n\n/**\n * Build-time manifest resolution — bundling-proof (Cloudflare Workers).\n * Lookup order per Contract A:\n * 1. `${className}.${methodName}.${dialectExt}`\n * 2. `${className}.${methodName}` (generic fallback)\n */\nexport class ManifestResolver implements SqlResolver {\n constructor(\n private readonly manifest: SqlManifest,\n readonly options: ManifestResolverOptions = {}\n ) {}\n\n resolve({ className, methodName, dialect }: SqlResolutionRequest): string | undefined {\n const ext = MANIFEST_DIALECT_EXT[dialect];\n return (\n this.manifest[`${className}.${methodName}.${ext}`] ??\n this.manifest[`${className}.${methodName}`]\n );\n }\n\n /** True when the manifest has a generic or any dialect-specific entry. */\n hasEntryFor(className: string, methodName: string): boolean {\n const generic = `${className}.${methodName}`;\n if (generic in this.manifest) return true;\n return Object.values(MANIFEST_DIALECT_EXT).some((ext) => `${generic}.${ext}` in this.manifest);\n }\n}\n\ntype DecoratedMethod = { className: string; methodName: string; inline: boolean };\n\ntype ResolverState = {\n resolver: SqlResolver | undefined;\n decorated: DecoratedMethod[];\n};\n\n// Single shared state across module copies (same pattern as SqlStackDB).\nconst g = globalThis as any;\nif (!g.__SQLSTACK_RESOLVER_STATE__) {\n g.__SQLSTACK_RESOLVER_STATE__ = { resolver: undefined, decorated: [] } as ResolverState;\n}\nconst state: ResolverState = g.__SQLSTACK_RESOLVER_STATE__;\n\n/** @internal Called by the @Query decorator at class-definition time. */\nexport function registerDecoratedMethod(entry: DecoratedMethod): void {\n state.decorated.push(entry);\n}\n\n/** @internal Read by the @Query call path. */\nexport function getActiveResolver(): SqlResolver | undefined {\n return state.resolver;\n}\n\nfunction assertManifestCovers(resolver: ManifestResolver): void {\n const missing = state.decorated\n .filter((m) => !m.inline)\n .filter((m) => !resolver.hasEntryFor(m.className, m.methodName))\n .map((m) => `${m.className}.${m.methodName}`);\n if (missing.length) {\n throw new Error(\n 'sqlstack: ManifestResolver has no SQL for these @Query methods:\\n' +\n missing.map((k) => ` - ${k}`).join('\\n') +\n '\\nRegenerate the manifest (see docs/codegen.md), or pass ' +\n '{ assert: false } if these methods return a SqlFragment from their body.'\n );\n }\n}\n\n/**\n * Resolver registration surface (Contract A):\n * SqlStack.useResolver(new ManifestResolver(sqlManifest))\n * Call at app startup, after repository classes have been imported\n * (decoration populates the coverage check).\n * With no resolver registered, @Query resolves via the filesystem exactly\n * as in v1.\n */\nexport const SqlStack = {\n useResolver(resolver: SqlResolver): void {\n if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {\n assertManifestCovers(resolver);\n }\n state.resolver = resolver;\n },\n clearResolver(): void {\n state.resolver = undefined;\n },\n};\n"]}
@@ -4,6 +4,7 @@ import { isValidationDisabled, validateOutput } from '../core/validator.js';
4
4
  import { SqlStackDB } from '../registry.js';
5
5
  import { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder.js';
6
6
  import { coerceRootPath, guessDecoratorDir, resolveSqlFromFs } from '../core/fileResolution.js';
7
+ import { getActiveResolver, registerDecoratedMethod } from '../core/resolver.js';
7
8
  import { getActiveTransaction } from '../transactions.js';
8
9
  import { SqlFragment } from '../sql.js';
9
10
  export function Query(arg) {
@@ -26,6 +27,12 @@ export function Query(arg) {
26
27
  setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir: dir } });
27
28
  }
28
29
  }
30
+ // Record for resolver coverage checks (ManifestResolver startup assertion).
31
+ registerDecoratedMethod({
32
+ className: _target?.constructor?.name ?? '<anonymous>',
33
+ methodName: String(prop),
34
+ inline: !!options?.sql,
35
+ });
29
36
  const original = desc.value;
30
37
  desc.value = async function (...callArgs) {
31
38
  const labels = getMethodLabels(this, prop);
@@ -73,12 +80,20 @@ export function Query(arg) {
73
80
  const dbName = labels.db ?? options?.db ?? classLabels?.db;
74
81
  const { name: resolvedDbName, db } = SqlStackDB.getEntry(dbName);
75
82
  const dialect = options?.dialect ?? db.dialect ?? 'sqlite';
76
- // 3) load SQL source (inline or fs)
83
+ // 3) load SQL source (inline, active resolver, or v1 fs fallback)
84
+ const activeResolver = getActiveResolver();
77
85
  const sql = labels?.source?.kind === 'inline'
78
86
  ? labels.source.sql
79
- : labels?.source?.kind === 'fs'
80
- ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql
81
- : undefined;
87
+ : activeResolver
88
+ ? activeResolver.resolve({
89
+ className: this?.constructor?.name ?? '<anonymous>',
90
+ methodName: String(prop),
91
+ dialect,
92
+ rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,
93
+ })
94
+ : labels?.source?.kind === 'fs'
95
+ ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql
96
+ : undefined;
82
97
  if (!sql) {
83
98
  throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);
84
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata';\nimport { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError, DatabaseError } from '../core/errors';\nimport { isValidationDisabled, validateOutput } from '../core/validator';\nimport { SqlStackDB } from '../registry';\nimport { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder';\nimport { coerceRootPath, guessDecoratorDir, resolveSqlFromFs } from '../core/fileResolution';\nimport { getActiveTransaction } from '../transactions';\nimport { SqlFragment } from '../sql';\n\ntype QueryOptions = {\n sql?: string; // optional inline SQL for testing; otherwise, future: load from file\n db?: string; // optional override DB name\n dialect?: 'sqlite' | 'mysql' | 'postgres';\n};\n\nexport function Query(arg?: string | QueryOptions) {\n return function (_target: any, prop: string | symbol, desc: PropertyDescriptor) {\n const options: QueryOptions | undefined = typeof arg === 'string' ? undefined : arg;\n const rootArg: string | undefined = typeof arg === 'string' ? arg : undefined;\n // Store method-level db override if provided\n if (options?.db) {\n setMethodLabels(_target, prop, { db: options.db });\n }\n // Store inline SQL if provided\n if (options?.sql) {\n setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });\n } else {\n // FS-based resolution\n const { rootDir } = coerceRootPath(rootArg);\n const dir = rootDir ?? guessDecoratorDir();\n if (dir) {\n setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir: dir } });\n }\n }\n\n const original = desc.value;\n desc.value = async function (...callArgs: any[]) {\n const labels = getMethodLabels(this, prop);\n const classLabels = getClassLabels(this);\n\n // 0) Check if the method body returns a SqlFragment (template literal path)\n let fragmentResult: unknown;\n try {\n fragmentResult = await original.apply(this, callArgs);\n } catch {\n // Method body threw (e.g. placeholder `throw new Error('replaced')`) — fall through to file/inline SQL\n fragmentResult = undefined;\n }\n if (fragmentResult instanceof SqlFragment) {\n const { sql: boundSql, params } = fragmentResult.toSQL();\n\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { name: resolvedDbName, db } = SqlStackDB.getEntry(dbName);\n\n let out;\n try {\n const tx = getActiveTransaction(resolvedDbName);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n return out;\n }\n\n // 1) prepare args with defaults\n const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array\n\n // 2) choose database and dialect\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { name: resolvedDbName, db } = SqlStackDB.getEntry(dbName);\n const dialect = options?.dialect ?? db.dialect ?? 'sqlite';\n\n // 3) load SQL source (inline or fs)\n const sql = labels?.source?.kind === 'inline'\n ? labels.source.sql\n : labels?.source?.kind === 'fs'\n ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql\n : undefined;\n if (!sql) {\n throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);\n }\n\n // 4) bind placeholders\n // Decide argument mode: positional if SQL contains :argN\n let workingSql = sql;\n const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);\n\n // Prepare args for binder\n let args: any;\n if (hasPositional) {\n args = callArgs;\n } else {\n const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;\n args = applyDefaults(labels.defaults, namedBase ?? {});\n }\n\n // Compute paging and inject :offset/:limit (named mode) or rewrite to positional\n const pageCfg = labels.page;\n if (pageCfg) {\n const { size, zeroBase } = pageCfg;\n const base = zeroBase ? 0 : 1;\n\n // Extract page number from input (object) or a trailing options object in positional mode\n const pageFromObject = (val: any): number | undefined => {\n if (val && typeof val === 'object' && !Array.isArray(val) && typeof (val as any).page !== 'undefined') {\n const p = (val as any).page;\n if (typeof p === 'number' && isFinite(p)) return p;\n }\n return undefined;\n };\n\n let pageNum: number | undefined;\n if (hasPositional) {\n // Variadic-style: only the LAST argument may carry `{ page }`\n if (callArgs.length > 0) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n } else {\n // Prefer last-arg options if provided; otherwise read from named object\n if (callArgs.length > 1) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n if (pageNum === undefined) {\n pageNum = pageFromObject(args);\n }\n }\n\n const effectivePage = typeof pageNum === 'number' ? pageNum : base;\n const offset = (effectivePage - base) * size;\n const limit = size;\n\n if (hasPositional) {\n // Replace occurrences of :offset and :limit with new :argN tokens appended to args\n const baseIndex = callArgs.length; // start numbering after user args\n let nextIndex = baseIndex + 1;\n const additions: unknown[] = [];\n\n const rewrite = (sqlText: string) => {\n const out: string[] = [];\n let i = 0;\n let inSQ = false, inDQ = false, inLC = false, inBC = false;\n const len = sqlText.length;\n while (i < len) {\n const ch = sqlText[i];\n const next = i + 1 < len ? sqlText[i + 1] : '';\n if (inLC) { out.push(ch); if (ch === '\\n') inLC = false; i++; continue; }\n if (inBC) { out.push(ch); if (ch === '*' && next === '/') { out.push(next); i++; inBC = false; } i++; continue; }\n if (inSQ) {\n out.push(ch);\n if (ch === \"'\" && next === \"'\") { out.push(next); i += 2; continue; }\n if (ch === \"'\") inSQ = false;\n i++;\n continue;\n }\n if (inDQ) {\n out.push(ch);\n if (ch === '\"' && next === '\"') { out.push(next); i += 2; continue; }\n if (ch === '\"') inDQ = false;\n i++;\n continue;\n }\n if (ch === '-' && next === '-') { out.push(ch, next); i += 2; inLC = true; continue; }\n if (ch === '/' && next === '*') { out.push(ch, next); i += 2; inBC = true; continue; }\n if (ch === '\"') { out.push(ch); inDQ = true; i++; continue; }\n if (ch === \"'\") { out.push(ch); inSQ = true; i++; continue; }\n if (ch === ':' && next === ':') { out.push('::'); i += 2; continue; }\n if (ch === ':') {\n // parse token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sqlText[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') j++; else break;\n }\n const name = sqlText.slice(start, j);\n if (name === 'offset') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(offset);\n i = j;\n continue;\n }\n if (name === 'limit') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(limit);\n i = j;\n continue;\n }\n // otherwise leave untouched\n out.push(':');\n i++;\n continue;\n }\n out.push(ch);\n i++;\n }\n return out.join('');\n };\n\n const rewritten = rewrite(workingSql);\n if (rewritten !== workingSql) {\n workingSql = rewritten;\n // append values so :argK map correctly\n (args as unknown[]).push(...additions);\n }\n } else {\n // Named-mode: attach computed values (override any provided)\n args = { ...(args as Record<string, unknown>), offset, limit };\n }\n }\n const binder =\n dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();\n const { sql: boundSql, params } = binder.bind(workingSql, args as any);\n\n // 5) execute query via registry DB\n let out;\n try {\n const tx = getActiveTransaction(resolvedDbName);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n // Attach SQL query (with placeholders) to error for debugging\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n // 6) If rows were returned (SELECT/CTE), shape + transform + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n\n // Non-SELECT: return the write result as-is\n return out;\n };\n\n return desc;\n };\n}\n\nfunction applyDefaults(defaults: Record<string, unknown> | undefined, input: any) {\n if (!defaults) return input;\n if (Array.isArray(input)) return input; // defaults only apply to named-object args\n return { ...defaults, ...(input || {}) };\n}\n\nfunction applyShape<T>(rows: T[], shape?: 'single' | 'only' | 'exist' | 'none'): any {\n switch (shape) {\n case 'single':\n return rows.length > 0 ? rows[0] : null;\n case 'only':\n if (rows.length !== 1) throw new ExactlyOneRowError(rows.length);\n return rows[0];\n case 'exist':\n if (rows.length < 1) throw new NoRowsError();\n return rows[0];\n case 'none':\n if (rows.length > 0) throw new RowsExistError(rows.length);\n return null;\n default:\n return rows;\n }\n}\n"]}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/decorators/query.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata';\nimport { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError, DatabaseError } from '../core/errors';\nimport { isValidationDisabled, validateOutput } from '../core/validator';\nimport { SqlStackDB } from '../registry';\nimport { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder';\nimport { coerceRootPath, guessDecoratorDir, resolveSqlFromFs } from '../core/fileResolution';\nimport { getActiveResolver, registerDecoratedMethod } from '../core/resolver';\nimport { getActiveTransaction } from '../transactions';\nimport { SqlFragment } from '../sql';\n\ntype QueryOptions = {\n sql?: string; // optional inline SQL for testing; otherwise, future: load from file\n db?: string; // optional override DB name\n dialect?: 'sqlite' | 'mysql' | 'postgres';\n};\n\nexport function Query(arg?: string | QueryOptions) {\n return function (_target: any, prop: string | symbol, desc: PropertyDescriptor) {\n const options: QueryOptions | undefined = typeof arg === 'string' ? undefined : arg;\n const rootArg: string | undefined = typeof arg === 'string' ? arg : undefined;\n // Store method-level db override if provided\n if (options?.db) {\n setMethodLabels(_target, prop, { db: options.db });\n }\n // Store inline SQL if provided\n if (options?.sql) {\n setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });\n } else {\n // FS-based resolution\n const { rootDir } = coerceRootPath(rootArg);\n const dir = rootDir ?? guessDecoratorDir();\n if (dir) {\n setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir: dir } });\n }\n }\n\n // Record for resolver coverage checks (ManifestResolver startup assertion).\n registerDecoratedMethod({\n className: _target?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n inline: !!options?.sql,\n });\n\n const original = desc.value;\n desc.value = async function (...callArgs: any[]) {\n const labels = getMethodLabels(this, prop);\n const classLabels = getClassLabels(this);\n\n // 0) Check if the method body returns a SqlFragment (template literal path)\n let fragmentResult: unknown;\n try {\n fragmentResult = await original.apply(this, callArgs);\n } catch {\n // Method body threw (e.g. placeholder `throw new Error('replaced')`) — fall through to file/inline SQL\n fragmentResult = undefined;\n }\n if (fragmentResult instanceof SqlFragment) {\n const { sql: boundSql, params } = fragmentResult.toSQL();\n\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { name: resolvedDbName, db } = SqlStackDB.getEntry(dbName);\n\n let out;\n try {\n const tx = getActiveTransaction(resolvedDbName);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n return out;\n }\n\n // 1) prepare args with defaults\n const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array\n\n // 2) choose database and dialect\n const dbName = labels.db ?? options?.db ?? classLabels?.db;\n const { name: resolvedDbName, db } = SqlStackDB.getEntry(dbName);\n const dialect = options?.dialect ?? db.dialect ?? 'sqlite';\n\n // 3) load SQL source (inline, active resolver, or v1 fs fallback)\n const activeResolver = getActiveResolver();\n const sql = labels?.source?.kind === 'inline'\n ? labels.source.sql\n : activeResolver\n ? activeResolver.resolve({\n className: this?.constructor?.name ?? '<anonymous>',\n methodName: String(prop),\n dialect,\n rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,\n })\n : labels?.source?.kind === 'fs'\n ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql\n : undefined;\n if (!sql) {\n throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);\n }\n\n // 4) bind placeholders\n // Decide argument mode: positional if SQL contains :argN\n let workingSql = sql;\n const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);\n\n // Prepare args for binder\n let args: any;\n if (hasPositional) {\n args = callArgs;\n } else {\n const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;\n args = applyDefaults(labels.defaults, namedBase ?? {});\n }\n\n // Compute paging and inject :offset/:limit (named mode) or rewrite to positional\n const pageCfg = labels.page;\n if (pageCfg) {\n const { size, zeroBase } = pageCfg;\n const base = zeroBase ? 0 : 1;\n\n // Extract page number from input (object) or a trailing options object in positional mode\n const pageFromObject = (val: any): number | undefined => {\n if (val && typeof val === 'object' && !Array.isArray(val) && typeof (val as any).page !== 'undefined') {\n const p = (val as any).page;\n if (typeof p === 'number' && isFinite(p)) return p;\n }\n return undefined;\n };\n\n let pageNum: number | undefined;\n if (hasPositional) {\n // Variadic-style: only the LAST argument may carry `{ page }`\n if (callArgs.length > 0) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n } else {\n // Prefer last-arg options if provided; otherwise read from named object\n if (callArgs.length > 1) {\n const last = callArgs[callArgs.length - 1];\n pageNum = pageFromObject(last);\n }\n if (pageNum === undefined) {\n pageNum = pageFromObject(args);\n }\n }\n\n const effectivePage = typeof pageNum === 'number' ? pageNum : base;\n const offset = (effectivePage - base) * size;\n const limit = size;\n\n if (hasPositional) {\n // Replace occurrences of :offset and :limit with new :argN tokens appended to args\n const baseIndex = callArgs.length; // start numbering after user args\n let nextIndex = baseIndex + 1;\n const additions: unknown[] = [];\n\n const rewrite = (sqlText: string) => {\n const out: string[] = [];\n let i = 0;\n let inSQ = false, inDQ = false, inLC = false, inBC = false;\n const len = sqlText.length;\n while (i < len) {\n const ch = sqlText[i];\n const next = i + 1 < len ? sqlText[i + 1] : '';\n if (inLC) { out.push(ch); if (ch === '\\n') inLC = false; i++; continue; }\n if (inBC) { out.push(ch); if (ch === '*' && next === '/') { out.push(next); i++; inBC = false; } i++; continue; }\n if (inSQ) {\n out.push(ch);\n if (ch === \"'\" && next === \"'\") { out.push(next); i += 2; continue; }\n if (ch === \"'\") inSQ = false;\n i++;\n continue;\n }\n if (inDQ) {\n out.push(ch);\n if (ch === '\"' && next === '\"') { out.push(next); i += 2; continue; }\n if (ch === '\"') inDQ = false;\n i++;\n continue;\n }\n if (ch === '-' && next === '-') { out.push(ch, next); i += 2; inLC = true; continue; }\n if (ch === '/' && next === '*') { out.push(ch, next); i += 2; inBC = true; continue; }\n if (ch === '\"') { out.push(ch); inDQ = true; i++; continue; }\n if (ch === \"'\") { out.push(ch); inSQ = true; i++; continue; }\n if (ch === ':' && next === ':') { out.push('::'); i += 2; continue; }\n if (ch === ':') {\n // parse token\n let j = i + 1;\n const start = j;\n while (j < len) {\n const c = sqlText[j];\n if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_') j++; else break;\n }\n const name = sqlText.slice(start, j);\n if (name === 'offset') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(offset);\n i = j;\n continue;\n }\n if (name === 'limit') {\n const token = `:arg${nextIndex++}`;\n out.push(token);\n additions.push(limit);\n i = j;\n continue;\n }\n // otherwise leave untouched\n out.push(':');\n i++;\n continue;\n }\n out.push(ch);\n i++;\n }\n return out.join('');\n };\n\n const rewritten = rewrite(workingSql);\n if (rewritten !== workingSql) {\n workingSql = rewritten;\n // append values so :argK map correctly\n (args as unknown[]).push(...additions);\n }\n } else {\n // Named-mode: attach computed values (override any provided)\n args = { ...(args as Record<string, unknown>), offset, limit };\n }\n }\n const binder =\n dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();\n const { sql: boundSql, params } = binder.bind(workingSql, args as any);\n\n // 5) execute query via registry DB\n let out;\n try {\n const tx = getActiveTransaction(resolvedDbName);\n out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);\n } catch (dbError: any) {\n // Attach SQL query (with placeholders) to error for debugging\n throw new DatabaseError(\n dbError?.message || String(dbError),\n boundSql,\n dbError instanceof Error ? dbError : undefined\n );\n }\n\n // 6) If rows were returned (SELECT/CTE), shape + transform + validate\n if (Array.isArray(out)) {\n const shaped = applyShape(out, labels.shape);\n const transformed = labels.transform ? labels.transform(shaped) : shaped;\n\n // 7) validate result via JSON Schema, if provided\n if (labels.validateSchema && !isValidationDisabled()) {\n if (Array.isArray(transformed)) {\n for (const row of transformed) validateOutput(labels.validateSchema, row);\n } else if (transformed !== null && transformed !== undefined) {\n validateOutput(labels.validateSchema, transformed);\n }\n }\n return transformed;\n }\n\n // Non-SELECT: return the write result as-is\n return out;\n };\n\n return desc;\n };\n}\n\nfunction applyDefaults(defaults: Record<string, unknown> | undefined, input: any) {\n if (!defaults) return input;\n if (Array.isArray(input)) return input; // defaults only apply to named-object args\n return { ...defaults, ...(input || {}) };\n}\n\nfunction applyShape<T>(rows: T[], shape?: 'single' | 'only' | 'exist' | 'none'): any {\n switch (shape) {\n case 'single':\n return rows.length > 0 ? rows[0] : null;\n case 'only':\n if (rows.length !== 1) throw new ExactlyOneRowError(rows.length);\n return rows[0];\n case 'exist':\n if (rows.length < 1) throw new NoRowsError();\n return rows[0];\n case 'none':\n if (rows.length > 0) throw new RowsExistError(rows.length);\n return null;\n default:\n return rows;\n }\n}\n"]}
package/dist/esm/index.js CHANGED
@@ -18,6 +18,7 @@ export * from './core/validator.js';
18
18
  // DTO Helper
19
19
  export * from './utils/dto.js';
20
20
  export { SqlStackDB } from './registry.js';
21
+ export { SqlStack, FsResolver, ManifestResolver, MANIFEST_DIALECT_EXT } from './core/resolver.js';
21
22
  // Legacy exports (kept for backward compatibility)
22
23
  export * from './binders/sqlBinder.js';
23
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEzC,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,eAAe;AACf,cAAc,gBAAgB,CAAC;AAE/B,WAAW;AACX,cAAc,YAAY,CAAC;AAE3B,wBAAwB;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AAEjC,aAAa;AACb,cAAc,aAAa,CAAC;AAI5B,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAElD,mDAAmD;AACnD,cAAc,qBAAqB,CAAC","sourcesContent":["// SQL Template Strings\nexport { sql, SqlFragment } from './sql';\n\n// Decorators\nexport * from './decorators/queryBinder';\nexport * from './decorators/query';\nexport * from './decorators/defaults';\nexport * from './decorators/resultShape';\nexport * from './decorators/validateResult';\nexport * from './decorators/transform';\nexport * from './decorators/page';\n\n// Transactions\nexport * from './transactions';\n\n// Adapters\nexport * from './adapters';\n\n// Errors and Validation\nexport * from './core/errors';\nexport * from './core/validator';\n\n// DTO Helper\nexport * from './utils/dto';\n\n// Database Registry and Types\nexport type { Dialect, WriteResult, PostgresWriteResult, QueryResult, Database } from './registry';\nexport { SqlStackDB, IStackDB } from './registry';\n\n// Legacy exports (kept for backward compatibility)\nexport * from './binders/sqlBinder';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEzC,aAAa;AACb,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAElC,eAAe;AACf,cAAc,gBAAgB,CAAC;AAE/B,WAAW;AACX,cAAc,YAAY,CAAC;AAE3B,wBAAwB;AACxB,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AAEjC,aAAa;AACb,cAAc,aAAa,CAAC;AAI5B,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAIlD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE/F,mDAAmD;AACnD,cAAc,qBAAqB,CAAC","sourcesContent":["// SQL Template Strings\nexport { sql, SqlFragment } from './sql';\n\n// Decorators\nexport * from './decorators/queryBinder';\nexport * from './decorators/query';\nexport * from './decorators/defaults';\nexport * from './decorators/resultShape';\nexport * from './decorators/validateResult';\nexport * from './decorators/transform';\nexport * from './decorators/page';\n\n// Transactions\nexport * from './transactions';\n\n// Adapters\nexport * from './adapters';\n\n// Errors and Validation\nexport * from './core/errors';\nexport * from './core/validator';\n\n// DTO Helper\nexport * from './utils/dto';\n\n// Database Registry and Types\nexport type { Dialect, WriteResult, PostgresWriteResult, QueryResult, Database } from './registry';\nexport { SqlStackDB, IStackDB } from './registry';\n\n// SQL Resolvers (v2): pluggable SQL source resolution\nexport type { SqlResolver, SqlManifest, SqlResolutionRequest, ManifestResolverOptions } from './core/resolver';\nexport { SqlStack, FsResolver, ManifestResolver, MANIFEST_DIALECT_EXT } from './core/resolver';\n\n// Legacy exports (kept for backward compatibility)\nexport * from './binders/sqlBinder';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlstack",
3
- "version": "1.0.25",
3
+ "version": "2.0.0",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -30,10 +30,18 @@
30
30
  "types": "./dist/cjs/core/errors.d.ts",
31
31
  "require": "./dist/cjs/core/errors.js",
32
32
  "import": "./dist/esm/core/errors.js"
33
+ },
34
+ "./codegen": {
35
+ "types": "./dist/cjs/codegen/generateManifest.d.ts",
36
+ "require": "./dist/cjs/codegen/generateManifest.js",
37
+ "import": "./dist/esm/codegen/generateManifest.js"
33
38
  }
34
39
  },
40
+ "bin": {
41
+ "sqlstack-codegen": "./dist/cjs/codegen/cli.js"
42
+ },
35
43
  "scripts": {
36
- "prepublish": "npm run build",
44
+ "prepublishOnly": "npm run build",
37
45
  "build": "npm-run-all clean build:cjs build:esm",
38
46
  "build:cjs": "tsc -p tsconfig.json",
39
47
  "build:esm": "tsc -p tsconfig.esm.json && node scripts/fix-esm-extensions.js && node scripts/create-esm-package.cjs",
@@ -56,6 +64,7 @@
56
64
  "better-sqlite3": "^12.3.0",
57
65
  "jest": "^29.7.0",
58
66
  "npm-run-all": "^4.1.5",
67
+ "pg": "^8.23.0",
59
68
  "rimraf": "^5.0.5",
60
69
  "ts-jest": "^29.2.5",
61
70
  "ts-node": "^10.9.2",
@@ -67,10 +76,10 @@
67
76
  "reflect-metadata": "^0.1.13"
68
77
  },
69
78
  "peerDependencies": {
70
- "sqlite": "*",
71
79
  "better-sqlite3": "*",
72
80
  "mysql2": "*",
73
81
  "pg": "*",
82
+ "sqlite": "*",
74
83
  "sqlite3": "*"
75
84
  },
76
85
  "peerDependenciesMeta": {