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
@@ -1 +1 @@
1
- {"version":3,"file":"fileResolution.js","sourceRoot":"","sources":["../../../src/core/fileResolution.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { Dialect } from '../registry';\n\nconst DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\nconst contentCache = new Map<string, string>();\nconst pathCache = new Map<string, string>();\n\nfunction key(root: string, method: string, dialect: Dialect): string {\n return `${root}::${method}::${dialect}`;\n}\n\nexport function resolveSqlFromFs(rootDir: string, methodName: string, dialect: Dialect): { sql: string; tried: string[] } {\n const k = key(rootDir, methodName, dialect);\n const tried: string[] = [];\n const ext = DIALECT_EXT[dialect];\n const dialectPath = path.join(rootDir, `${methodName}.${ext}.sql`);\n const genericPath = path.join(rootDir, `${methodName}.sql`);\n\n // Cached path\n let chosen = pathCache.get(k);\n if (!chosen) {\n if (fs.existsSync(dialectPath)) {\n chosen = dialectPath;\n } else if (fs.existsSync(genericPath)) {\n chosen = genericPath;\n }\n if (chosen) pathCache.set(k, chosen);\n }\n\n if (!chosen) {\n tried.push(dialectPath, genericPath);\n throw new Error(\n `sqlstack: SQL file not found for ${methodName}\\ntried: ${tried.join(\"\\n\")}`\n );\n }\n\n // Cached content\n let sql = contentCache.get(chosen);\n if (!sql) {\n sql = fs.readFileSync(chosen, 'utf8');\n contentCache.set(chosen, sql);\n }\n return { sql, tried: [chosen] };\n}\n\nexport function coerceRootPath(input?: string): { rootDir?: string; from?: 'file' | 'folder' } {\n if (!input) return {};\n const stat = fs.existsSync(input) ? fs.statSync(input) : undefined;\n if (stat?.isDirectory()) return { rootDir: input, from: 'folder' };\n if (stat?.isFile()) return { rootDir: path.dirname(input), from: 'file' };\n // If not found, treat as folder hint anyway\n return { rootDir: input, from: 'folder' };\n}\n\nexport function guessDecoratorDir(): string | undefined {\n const err = new Error();\n const stack = (err.stack || '').split('\\n').slice(2);\n const packageRoot = PACKAGE_ROOT_NORMALIZED;\n\n // DEBUG: Uncomment to trace issues\n // console.log('[guessDecoratorDir] packageRoot:', packageRoot);\n // console.log('[guessDecoratorDir] stack:', stack.slice(0, 5));\n\n for (const line of stack) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n\n const resolved = toAbsolutePath(file);\n if (!resolved) continue;\n\n // Skip frames from node_modules (including sqlstack itself when used as dependency)\n if (resolved.includes('node_modules')) continue;\n\n const normalized = safeNormalize(resolved);\n if (!normalized) continue;\n\n // Skip frames from sqlstack's own package (when running from source)\n // Also skip if the path contains /sqlstack/ anywhere (linked package scenario)\n if (packageRoot && normalized.startsWith(packageRoot)) {\n continue;\n }\n\n // Additional check: skip if this is a sqlstack path (handles linked packages with relative paths)\n if (isSqlstackPath(resolved)) {\n continue;\n }\n\n // Return the first valid frame - this is where @Query is defined\n return path.dirname(resolved);\n }\n return undefined;\n}\n\nfunction toAbsolutePath(file: string): string | undefined {\n try {\n if (file.startsWith('file://')) {\n return fileURLToPath(file);\n }\n // Skip Node.js internal modules and bundler internals\n if (file.startsWith('node:') || file.startsWith('webpack://')) {\n return undefined;\n }\n if (!path.isAbsolute(file)) {\n return path.resolve(file);\n }\n return file;\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSep(p: string): string {\n return p.endsWith(path.sep) ? p : p + path.sep;\n}\n\nfunction safeNormalize(p?: string): string | undefined {\n if (!p) return undefined;\n const normalized = path.normalize(p);\n return process.platform === 'win32' ? normalized.toLowerCase() : normalized;\n}\n\n/**\n * Finds the package root from a starting directory by walking up to find package.json.\n * @internal Exported for testing\n */\nexport function findPackageRoot(startDir: string): string | undefined {\n let current = startDir;\n for (let i = 0; i < 6; i++) {\n const candidate = path.join(current, 'package.json');\n if (fs.existsSync(candidate)) {\n const root = path.dirname(candidate);\n const normalizedRoot = safeNormalize(root);\n return normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return undefined;\n}\n\n/**\n * Detects if a path belongs to sqlstack package.\n * Handles both source paths (contains 'sqlstack') and node_modules paths.\n * @internal Exported for testing\n */\nexport function isSqlstackPath(filePath: string): boolean {\n const normalized = filePath.toLowerCase();\n // Check for source development path (e.g., /path/to/sqlstack/src/...)\n if (normalized.includes(path.sep + 'sqlstack' + path.sep)) return true;\n // Check for node_modules installation\n if (normalized.includes('node_modules' + path.sep + 'sqlstack' + path.sep)) return true;\n // Check for scoped package (@noego/sqlstack or similar)\n if (normalized.includes('node_modules' + path.sep + '@') && normalized.includes('sqlstack' + path.sep)) return true;\n return false;\n}\n\n/**\n * Extracts sqlstack's location from a stack trace.\n * Handles absolute paths, file:// URLs, and relative paths (Vitest uses relative paths).\n * @internal Exported for testing\n */\nexport function findSqlstackFromStack(stackString: string): string | undefined {\n const lines = stackString.split('\\n');\n for (const line of lines) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n try {\n let resolved: string | undefined;\n if (file.startsWith('file://')) {\n resolved = fileURLToPath(file);\n } else if (path.isAbsolute(file)) {\n resolved = file;\n } else if (!file.startsWith('node:') && !file.startsWith('webpack://')) {\n // Relative path - resolve it (Vitest uses relative paths in stack traces)\n resolved = path.resolve(file);\n }\n if (resolved && resolved.includes('fileResolution')) {\n return path.dirname(resolved);\n }\n } catch {\n // Skip invalid paths\n }\n }\n return undefined;\n}\n\n/**\n * Computes the sqlstack package root directory.\n * Handles both CJS (__dirname) and ESM (stack trace) detection.\n * Validates that __dirname actually points to sqlstack (guards against Vitest injection).\n * @internal Exported for testing\n */\nexport function computePackageRoot(\n dirnameValue: string | undefined,\n filenameValue: string | undefined,\n getStack: () => string\n): string | undefined {\n const candidates: string[] = [];\n\n // CJS: use __dirname/__filename, but validate they actually point to sqlstack\n // (Vitest can inject __dirname incorrectly when transforming CJS modules)\n if (typeof dirnameValue === 'string' && isSqlstackPath(dirnameValue)) {\n candidates.push(dirnameValue);\n }\n if (typeof filenameValue === 'string' && isSqlstackPath(filenameValue)) {\n candidates.push(path.dirname(filenameValue));\n }\n\n // ESM fallback or when __dirname was incorrectly injected: parse stack trace\n if (candidates.length === 0) {\n const stackDir = findSqlstackFromStack(getStack());\n if (stackDir) {\n candidates.push(stackDir);\n }\n }\n\n // Find the package root from the first valid candidate\n for (const base of candidates) {\n const root = findPackageRoot(base);\n if (root) return root;\n }\n return undefined;\n}\n\nconst PACKAGE_ROOT_NORMALIZED = computePackageRoot(\n typeof __dirname === 'string' ? __dirname : undefined,\n typeof __filename === 'string' ? __filename : undefined,\n () => new Error().stack || ''\n);\n"]}
1
+ {"version":3,"file":"fileResolution.js","sourceRoot":"","sources":["../../../src/core/fileResolution.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { Dialect } from '../registry';\n\nconst DIALECT_EXT: Record<Dialect, string> = {\n postgres: 'pg',\n mysql: 'mysql',\n sqlite: 'sqlite',\n};\n\nconst contentCache = new Map<string, string>();\nconst pathCache = new Map<string, string>();\n\nfunction key(root: string, method: string, dialect: Dialect): string {\n return `${root}::${method}::${dialect}`;\n}\n\nexport function resolveSqlFromFs(rootDir: string, methodName: string, dialect: Dialect): { sql: string; tried: string[] } {\n const k = key(rootDir, methodName, dialect);\n const tried: string[] = [];\n const ext = DIALECT_EXT[dialect];\n const dialectPath = path.join(rootDir, `${methodName}.${ext}.sql`);\n const genericPath = path.join(rootDir, `${methodName}.sql`);\n\n // Cached path\n let chosen = pathCache.get(k);\n if (!chosen) {\n if (fs.existsSync(dialectPath)) {\n chosen = dialectPath;\n } else if (fs.existsSync(genericPath)) {\n chosen = genericPath;\n }\n if (chosen) pathCache.set(k, chosen);\n }\n\n if (!chosen) {\n tried.push(dialectPath, genericPath);\n throw new Error(\n `sqlstack: SQL file not found for ${methodName}\\ntried: ${tried.join(\"\\n\")}`\n );\n }\n\n // Cached content\n let sql = contentCache.get(chosen);\n if (!sql) {\n sql = fs.readFileSync(chosen, 'utf8');\n contentCache.set(chosen, sql);\n }\n return { sql, tried: [chosen] };\n}\n\nexport function coerceRootPath(input?: string): { rootDir?: string; from?: 'file' | 'folder' } {\n if (!input) return {};\n const stat = fs.existsSync(input) ? fs.statSync(input) : undefined;\n if (stat?.isDirectory()) return { rootDir: input, from: 'folder' };\n if (stat?.isFile()) return { rootDir: path.dirname(input), from: 'file' };\n // If not found, treat as folder hint anyway\n return { rootDir: input, from: 'folder' };\n}\n\nexport function guessDecoratorDir(): string | undefined {\n const err = new Error();\n const stack = (err.stack || '').split('\\n').slice(2);\n const packageRoot = PACKAGE_ROOT_NORMALIZED;\n const codeRoot = SQLSTACK_CODE_ROOT;\n\n // DEBUG: Uncomment to trace issues\n // console.log('[guessDecoratorDir] packageRoot:', packageRoot);\n // console.log('[guessDecoratorDir] stack:', stack.slice(0, 5));\n\n for (const line of stack) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n\n const resolved = toAbsolutePath(file);\n if (!resolved) continue;\n\n const normalized = safeNormalize(resolved);\n if (!normalized) continue;\n\n // Skip every node_modules frame (sqlstack as a dependency, decorator\n // helpers such as reflect-metadata, test runners) and sqlstack's own\n // src/ and dist/ under its package root (running from source or a linked\n // checkout). A consumer module under a node_modules-free path that merely\n // contains the word \"sqlstack\" — this package's own tests/fixtures — is\n // a consumer and is NOT skipped.\n if (normalized.includes(path.sep + 'node_modules' + path.sep)) continue;\n if (packageRoot && isSqlstackCodePath(normalized, packageRoot)) continue;\n // Filesystem-free: sqlstack's own code root (the directory holding\n // core/, decorators/, …) as the STACK names it — the only reliable\n // reference on hosts without fs (workerd) or with re-rooted trees.\n if (codeRoot && normalized.startsWith(codeRoot)) continue;\n\n // Return the first consumer frame - this is where @Query is applied\n return path.dirname(resolved);\n }\n return undefined;\n}\n\nfunction isSqlstackCodePath(normalized: string, packageRoot: string): boolean {\n const root = process.platform === 'win32' ? packageRoot.toLowerCase() : packageRoot;\n return normalized.startsWith(root + 'src' + path.sep) || normalized.startsWith(root + 'dist' + path.sep);\n}\n\nfunction toAbsolutePath(file: string): string | undefined {\n try {\n if (file.startsWith('file://')) {\n return fileURLToPath(file);\n }\n // Skip Node.js internal modules and bundler internals\n if (file.startsWith('node:') || file.startsWith('webpack://')) {\n return undefined;\n }\n if (!path.isAbsolute(file)) {\n return path.resolve(file);\n }\n return file;\n } catch {\n return undefined;\n }\n}\n\nfunction ensureTrailingSep(p: string): string {\n return p.endsWith(path.sep) ? p : p + path.sep;\n}\n\nfunction safeNormalize(p?: string): string | undefined {\n if (!p) return undefined;\n const normalized = path.normalize(p);\n return process.platform === 'win32' ? normalized.toLowerCase() : normalized;\n}\n\n/**\n * Finds the package root from a starting directory by walking up to find package.json.\n * @internal Exported for testing\n */\nexport function findPackageRoot(startDir: string): string | undefined {\n // The ESM build ships a nested dist/esm/package.json ({ type: module });\n // keep walking past any package.json that is not sqlstack's own so the\n // root is the real package directory (whose src/ and dist/ are skipped by\n // guessDecoratorDir). The first package.json found is the fallback.\n let current = startDir;\n let fallback: string | undefined;\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(current, 'package.json');\n if (fs.existsSync(candidate)) {\n const root = path.dirname(candidate);\n const normalizedRoot = safeNormalize(root);\n const asRoot = normalizedRoot ? ensureTrailingSep(normalizedRoot) : ensureTrailingSep(root);\n if (packageNameOf(candidate) === 'sqlstack') return asRoot;\n fallback ??= asRoot;\n }\n const parent = path.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return fallback;\n}\n\nfunction packageNameOf(packageJsonPath: string): string | undefined {\n try {\n return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))?.name;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Detects if a path belongs to sqlstack package.\n * Handles both source paths (contains 'sqlstack') and node_modules paths.\n * @internal Exported for testing\n */\nexport function isSqlstackPath(filePath: string): boolean {\n const normalized = filePath.toLowerCase();\n // Check for source development path (e.g., /path/to/sqlstack/src/...)\n if (normalized.includes(path.sep + 'sqlstack' + path.sep)) return true;\n // Check for node_modules installation\n if (normalized.includes('node_modules' + path.sep + 'sqlstack' + path.sep)) return true;\n // Check for scoped package (@noego/sqlstack or similar)\n if (normalized.includes('node_modules' + path.sep + '@') && normalized.includes('sqlstack' + path.sep)) return true;\n return false;\n}\n\n/**\n * Extracts sqlstack's location from a stack trace.\n * Handles absolute paths, file:// URLs, and relative paths (Vitest uses relative paths).\n * @internal Exported for testing\n */\nexport function findSqlstackFromStack(stackString: string): string | undefined {\n const lines = stackString.split('\\n');\n for (const line of lines) {\n const m = line.match(/\\((.*?):\\d+:\\d+\\)/) || line.match(/at (.*?):\\d+:\\d+/);\n const file = m?.[1];\n if (!file) continue;\n try {\n let resolved: string | undefined;\n if (file.startsWith('file://')) {\n resolved = fileURLToPath(file);\n } else if (path.isAbsolute(file)) {\n resolved = file;\n } else if (!file.startsWith('node:') && !file.startsWith('webpack://')) {\n // Relative path - resolve it (Vitest uses relative paths in stack traces)\n resolved = path.resolve(file);\n }\n if (resolved && resolved.includes('fileResolution')) {\n return path.dirname(resolved);\n }\n } catch {\n // Skip invalid paths\n }\n }\n return undefined;\n}\n\n/**\n * Computes the sqlstack package root directory.\n * Handles both CJS (__dirname) and ESM (stack trace) detection.\n * Validates that __dirname actually points to sqlstack (guards against Vitest injection).\n * @internal Exported for testing\n */\nexport function computePackageRoot(\n dirnameValue: string | undefined,\n filenameValue: string | undefined,\n getStack: () => string\n): string | undefined {\n const candidates: string[] = [];\n\n // CJS: use __dirname/__filename, but validate they actually point to sqlstack\n // (Vitest can inject __dirname incorrectly when transforming CJS modules)\n if (typeof dirnameValue === 'string' && isSqlstackPath(dirnameValue)) {\n candidates.push(dirnameValue);\n }\n if (typeof filenameValue === 'string' && isSqlstackPath(filenameValue)) {\n candidates.push(path.dirname(filenameValue));\n }\n\n // ESM fallback or when __dirname was incorrectly injected: parse stack trace\n if (candidates.length === 0) {\n const stackDir = findSqlstackFromStack(getStack());\n if (stackDir) {\n candidates.push(stackDir);\n }\n }\n\n // Find the package root from the first valid candidate\n for (const base of candidates) {\n const root = findPackageRoot(base);\n if (root) return root;\n }\n return undefined;\n}\n\nconst PACKAGE_ROOT_NORMALIZED = computePackageRoot(\n typeof __dirname === 'string' ? __dirname : undefined,\n typeof __filename === 'string' ? __filename : undefined,\n () => new Error().stack || ''\n);\n\n/**\n * sqlstack's code root as the runtime names this module in stack traces:\n * the parent of this file's directory (`src/`, `dist/cjs/`, `dist/esm/`, or\n * a bundler's re-rooted copy). Needs no filesystem.\n * @internal Exported for testing\n */\nexport function computeCodeRoot(getStack: () => string): string | undefined {\n const coreDir = findSqlstackFromStack(getStack());\n if (!coreDir) return undefined;\n const root = safeNormalize(path.dirname(coreDir));\n return root ? ensureTrailingSep(root) : undefined;\n}\n\nconst SQLSTACK_CODE_ROOT = computeCodeRoot(() => new Error().stack || '');\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAqBzC,MAAM,UAAU,OAAO,CAAC,MAAW;IACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAe,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAW,EAAE,IAAqB,EAAE,KAA4B;IAC9F,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAa,EAAE,IAAqB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAS,EAAE,KAA2B;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAa;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC","sourcesContent":["const META = Symbol.for('sqlstack:meta');\n\nexport type MethodLabels = {\n defaults?: Record<string, unknown>;\n shape?: 'single' | 'only' | 'exist' | 'none';\n validateSchema?: unknown;\n source?: { kind: 'inline'; sql: string } | { kind: 'fs'; rootDir: string };\n db?: string;\n transform?: (row: any) => any;\n page?: { size: number; zeroBase?: boolean };\n};\n\nexport type ClassLabels = {\n db?: string;\n};\n\nexport type MetaShape = {\n class?: ClassLabels;\n methods: Record<string | symbol, MethodLabels>;\n};\n\nexport function getMeta(target: any): MetaShape {\n if (!target[META]) {\n target[META] = { methods: {} } as MetaShape;\n }\n return target[META];\n}\n\nexport function setMethodLabels(target: any, prop: string | symbol, patch: Partial<MethodLabels>) {\n const meta = getMeta(target);\n meta.methods[prop] = { ...(meta.methods[prop] || {}), ...patch };\n}\n\nexport function getMethodLabels(instance: any, prop: string | symbol): MethodLabels {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.methods[prop] || {};\n}\n\nexport function setClassLabels(ctor: any, patch: Partial<ClassLabels>) {\n const meta = getMeta(ctor.prototype);\n meta.class = { ...(meta.class || {}), ...patch };\n}\n\nexport function getClassLabels(instance: any): ClassLabels | undefined {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.class;\n}\n"]}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/core/metadata.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAyBzC,MAAM,UAAU,OAAO,CAAC,MAAW;IACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAe,CAAC;IAC9C,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAW,EAAE,IAAqB,EAAE,KAA4B;IAC9F,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAa,EAAE,IAAqB;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAS,EAAE,KAA2B;IACnE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAa;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,KAAK,CAAC;AACpB,CAAC","sourcesContent":["const META = Symbol.for('sqlstack:meta');\n\nexport type MethodLabels = {\n defaults?: Record<string, unknown>;\n shape?: 'single' | 'only' | 'exist' | 'none';\n validateSchema?: unknown;\n source?:\n | { kind: 'inline'; sql: string }\n | { kind: 'fs'; rootDir: string }\n /** Bare @Query(): the directory of the decorating module, read from the stack at decoration time. */\n | { kind: 'guess'; dir: string };\n db?: string;\n transform?: (row: any) => any;\n page?: { size: number; zeroBase?: boolean };\n};\n\nexport type ClassLabels = {\n db?: string;\n};\n\nexport type MetaShape = {\n class?: ClassLabels;\n methods: Record<string | symbol, MethodLabels>;\n};\n\nexport function getMeta(target: any): MetaShape {\n if (!target[META]) {\n target[META] = { methods: {} } as MetaShape;\n }\n return target[META];\n}\n\nexport function setMethodLabels(target: any, prop: string | symbol, patch: Partial<MethodLabels>) {\n const meta = getMeta(target);\n meta.methods[prop] = { ...(meta.methods[prop] || {}), ...patch };\n}\n\nexport function getMethodLabels(instance: any, prop: string | symbol): MethodLabels {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.methods[prop] || {};\n}\n\nexport function setClassLabels(ctor: any, patch: Partial<ClassLabels>) {\n const meta = getMeta(ctor.prototype);\n meta.class = { ...(meta.class || {}), ...patch };\n}\n\nexport function getClassLabels(instance: any): ClassLabels | undefined {\n const meta = getMeta(Object.getPrototypeOf(instance));\n return meta.class;\n}\n"]}
@@ -0,0 +1,91 @@
1
+ const g = globalThis;
2
+ if (!g.__SQLSTACK_RESOURCES_STATE__) {
3
+ g.__SQLSTACK_RESOURCES_STATE__ = {
4
+ resources: undefined,
5
+ byKey: new Map(),
6
+ byTail: new Map(),
7
+ lookups: new Map(),
8
+ };
9
+ }
10
+ const state = g.__SQLSTACK_RESOURCES_STATE__;
11
+ const DIALECT_EXT = { postgres: 'pg', mysql: 'mysql', sqlite: 'sqlite' };
12
+ /** Forward slashes, no `file://`, no leading `./`, exactly one leading `/`. */
13
+ export function normalizeResourcePath(p) {
14
+ let s = p.replace(/\\/g, '/');
15
+ if (s.startsWith('file://'))
16
+ s = s.slice('file://'.length);
17
+ s = s.replace(/^(\.\/)+/, '');
18
+ s = s.replace(/^\/+/, '');
19
+ return '/' + s;
20
+ }
21
+ function tailOf(normalized) {
22
+ const parts = normalized.split('/');
23
+ return '/' + parts.slice(-2).join('/');
24
+ }
25
+ /** Install (or clear with undefined) the process-wide packaged SQL resources. */
26
+ export function setResources(map) {
27
+ state.byKey = new Map();
28
+ state.byTail = new Map();
29
+ state.lookups = new Map();
30
+ state.resources = map;
31
+ if (!map)
32
+ return;
33
+ for (const [rawKey, sql] of Object.entries(map)) {
34
+ const key = normalizeResourcePath(rawKey);
35
+ state.byKey.set(key, sql);
36
+ const tail = tailOf(key);
37
+ const list = state.byTail.get(tail);
38
+ if (list)
39
+ list.push(key);
40
+ else
41
+ state.byTail.set(tail, [key]);
42
+ }
43
+ }
44
+ export function getResources() {
45
+ return state.resources;
46
+ }
47
+ /**
48
+ * Resolve one absolute (or module-tree) candidate path against the installed
49
+ * resources. Order: exact key; the longest key that is a path suffix of the
50
+ * candidate; the unique key sharing the candidate's `<folder>/<file>` tail.
51
+ */
52
+ export function lookupResource(candidatePath) {
53
+ if (!state.resources)
54
+ return undefined;
55
+ const candidate = normalizeResourcePath(candidatePath);
56
+ if (state.lookups.has(candidate))
57
+ return state.lookups.get(candidate);
58
+ let found = state.byKey.get(candidate);
59
+ if (found === undefined) {
60
+ let bestLen = -1;
61
+ for (const [key, sql] of state.byKey) {
62
+ if (key.length > bestLen && candidate.endsWith(key)) {
63
+ found = sql;
64
+ bestLen = key.length;
65
+ }
66
+ }
67
+ }
68
+ if (found === undefined) {
69
+ const hits = state.byTail.get(tailOf(candidate));
70
+ if (hits && hits.length === 1)
71
+ found = state.byKey.get(hits[0]);
72
+ }
73
+ state.lookups.set(candidate, found);
74
+ return found;
75
+ }
76
+ /**
77
+ * Resolve a decorated method's SQL from the installed resources: the
78
+ * dialect-specific `<dir>/<method>.<ext>.sql` first, then `<dir>/<method>.sql`.
79
+ * Returns the tried candidate paths so a miss can be reported precisely.
80
+ */
81
+ export function resolveSqlFromResources(dir, methodName, dialect) {
82
+ const base = normalizeResourcePath(dir).replace(/\/+$/, '');
83
+ const tried = [`${base}/${methodName}.${DIALECT_EXT[dialect]}.sql`, `${base}/${methodName}.sql`];
84
+ for (const candidate of tried) {
85
+ const sql = lookupResource(candidate);
86
+ if (sql !== undefined)
87
+ return { sql, tried };
88
+ }
89
+ return { sql: undefined, tried };
90
+ }
91
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/core/resources.ts"],"names":[],"mappings":"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","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"]}
@@ -13,15 +13,15 @@ var _SourceScanResolver_inner;
13
13
  import { ManifestResolver } from './resolver.js';
14
14
  import { scanSqlManifestSync } from '../codegen/generateManifest.js';
15
15
  /**
16
- * Zero-config Node resolution for bare @Query(): lazily scans the project
17
- * tree (process.cwd(), or an explicit rootDir) for @Query classes and their
18
- * sibling .sql files, then answers Contract A lookups from the in-memory
19
- * manifest. The scan runs once, on the first bare-@Query execution.
16
+ * Opt-in Node resolution that scans a project tree (process.cwd(), or an
17
+ * explicit rootDir) for @Query classes and their sibling .sql files, then
18
+ * answers Contract A lookups from the in-memory manifest. The scan runs once
19
+ * per instance, on first resolve.
20
20
  *
21
- * This is the DEFAULT resolver — installed resolvers (per-root SqlStackConfig
22
- * or the deprecated global) always take precedence, and bundled runtimes
23
- * (Cloudflare Workers) never reach it because their entrypoints install a
24
- * ManifestResolver.
21
+ * This is NOT a default. Bare @Query() resolves its own module directory
22
+ * (stack guess at decoration time) against `SqlStack.useResources(...)` or
23
+ * the filesystem; nothing walks the tree unless this resolver is installed
24
+ * explicitly via `SqlStack.useResolver` / `SqlStackConfig.resolver`.
25
25
  */
26
26
  export class SourceScanResolver {
27
27
  constructor(rootDir) {
@@ -37,15 +37,4 @@ export class SourceScanResolver {
37
37
  }
38
38
  }
39
39
  _SourceScanResolver_inner = new WeakMap();
40
- let defaultInstance;
41
- /**
42
- * @internal Process-wide default used by the @Query call path when no
43
- * resolver is installed and the decorator captured no filesystem root.
44
- * Node-only: returns undefined where the filesystem is unavailable.
45
- */
46
- export function defaultSourceScanResolver() {
47
- if (typeof process === 'undefined' || typeof process.cwd !== 'function')
48
- return undefined;
49
- return (defaultInstance ?? (defaultInstance = new SourceScanResolver()));
50
- }
51
40
  //# sourceMappingURL=sourceScanResolver.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sourceScanResolver.js","sourceRoot":"","sources":["../../../src/core/sourceScanResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,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,mBAAmB,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,gBAAgB,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;;AAED,IAAI,eAA+C,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,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,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE;;;;;;;;;;GAUG;AACH,MAAM,OAAO,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,mBAAmB,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YACxE,uBAAA,IAAI,6BAAU,IAAI,gBAAgB,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","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,14 +1,14 @@
1
1
  import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata.js';
2
2
  import { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError, DatabaseError, ExpectedRowsError } from '../core/errors.js';
3
3
  import { isValidationDisabled, validateOutput } from '../core/validator.js';
4
- import { resolveExecution, resolveSqlResolver } from '../runtime.js';
4
+ import { resolveExecution, resolveSqlResolver, isRegisteredDatabaseName } from '../runtime.js';
5
5
  import { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder.js';
6
- import { coerceRootPath, resolveSqlFromFs } from '../core/fileResolution.js';
7
- import { registerDecoratedMethod, recordQueryMethodOnClass } from '../core/resolver.js';
8
- import { defaultSourceScanResolver } from '../core/sourceScanResolver.js';
9
- import { getActiveTransaction } from '../transactions.js';
6
+ import { coerceRootPath, resolveSqlFromFs, guessDecoratorDir } from '../core/fileResolution.js';
7
+ import { registerDecoratedMethod, recordQueryMethodOnClass, getActiveResolver } from '../core/resolver.js';
8
+ import { getResources, resolveSqlFromResources } from '../core/resources.js';
9
+ import { getTransactionTarget } from '../transactions.js';
10
10
  import { SqlFragment, compileFragment } from '../sql.js';
11
- import { runStorage, resolveRunTarget, executeOnTarget, toRunError, fragmentText, } from '../run.js';
11
+ import { runStorage, resolveRunTarget, executeOnTarget, toRunError, fragmentText, isRunDatabaseHandle, } from '../run.js';
12
12
  /**
13
13
  * Turn a method into a database query. The body calls `run(...)` (see `run`
14
14
  * for its forms); the wrapper resolves SQL, binds, executes, and applies the
@@ -36,14 +36,20 @@ export function Query(arg) {
36
36
  setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });
37
37
  }
38
38
  else {
39
- // FS-based resolution: only an EXPLICIT path argument pins a directory.
40
- // Bare @Query() resolves through the active resolver (or the default
41
- // SourceScanResolver) — no stack-based directory guessing, which breaks
42
- // under bundlers and test transforms.
39
+ // An EXPLICIT path argument pins a filesystem directory. Bare @Query()
40
+ // records the directory of the decorating module (first non-sqlstack
41
+ // stack frame at decoration time); at call time that directory is
42
+ // resolved against the packaged resources map when one is installed
43
+ // (SqlStack.useResources), else read from the filesystem. No tree scan.
43
44
  const { rootDir } = coerceRootPath(rootArg);
44
45
  if (rootDir) {
45
46
  setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir } });
46
47
  }
48
+ else {
49
+ const dir = guessDecoratorDir();
50
+ if (dir)
51
+ setMethodLabels(_target, prop, { source: { kind: 'guess', dir } });
52
+ }
47
53
  }
48
54
  // Record for resolver coverage checks: immutable class metadata (the
49
55
  // canonical, environment-local source) plus the deprecated global list
@@ -80,26 +86,25 @@ export function Query(arg) {
80
86
  }
81
87
  const db = target.db;
82
88
  const dialect = options?.dialect ?? db.dialect ?? 'sqlite';
83
- // 3) load SQL source (inline, environment resolver, v1 fs fallback,
84
- // or the zero-config source scan — bare @Query() with nothing installed)
89
+ // 3) load SQL source: inline; else an installed resolver (the
90
+ // instance's, else the process-global one — a build-time manifest
91
+ // registered by a host runner applies even when the SqlStack itself
92
+ // came from an IoC root); else the decorator's directory (explicit
93
+ // path or guessed module dir) against the packaged resources /
94
+ // filesystem.
95
+ const className = this?.constructor?.name ?? '<anonymous>';
96
+ const resolver = activeResolver ?? getActiveResolver();
85
97
  const sql = labels?.source?.kind === 'inline'
86
98
  ? labels.source.sql
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
- : defaultSourceScanResolver()?.resolve({
97
- className: this?.constructor?.name ?? '<anonymous>',
98
- methodName: String(prop),
99
- dialect,
100
- });
99
+ : (resolver?.resolve({
100
+ className,
101
+ methodName: String(prop),
102
+ dialect,
103
+ rootDir: labels?.source?.kind === 'fs' ? labels.source.rootDir : undefined,
104
+ }) ?? resolveSourceSql(labels?.source, className, String(prop), dialect));
101
105
  if (!sql) {
102
- throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);
106
+ throw new SqlStackError(`No SQL source for ${className}.${String(prop)}: the decorating module's directory could not be ` +
107
+ 'determined from the stack. Use @Query() with a file/folder path or inline sql.');
103
108
  }
104
109
  onSql(sql);
105
110
  // 4) bind placeholders
@@ -311,11 +316,43 @@ export function Query(arg) {
311
316
  const resolved = await resolveExecution(dbName);
312
317
  return {
313
318
  db: resolved.entry.db,
314
- tx: getActiveTransaction(resolved.entry),
319
+ tx: getTransactionTarget(resolved.entry),
315
320
  resolver: resolved.resolver,
316
321
  byName: true,
317
322
  };
318
323
  };
324
+ // The method's own leading database argument: a handle (object with
325
+ // query()) or a registered database name. It selects run()'s target
326
+ // and is never bound as a value.
327
+ const leadingDb = async () => {
328
+ if (callArgs.length === 0)
329
+ return undefined;
330
+ const first = callArgs[0];
331
+ if (isRunDatabaseHandle(first))
332
+ return first;
333
+ if (typeof first === 'string' && first.length > 0 && (await isRegisteredDatabaseName(first)))
334
+ return first;
335
+ return undefined;
336
+ };
337
+ // A database chosen by run's argument or the method's leading argument.
338
+ const explicitTarget = async (db) => {
339
+ const target = await resolveRunTarget(db);
340
+ // Inline SQL needs no resolver; only look one up for file-based SQL.
341
+ const resolver = target.byName
342
+ ? target.resolver
343
+ : labels?.source?.kind === 'inline'
344
+ ? undefined
345
+ : await resolveSqlResolver();
346
+ return { target, resolver };
347
+ };
348
+ // run() (and the legacy fallback): the method's arguments minus a
349
+ // leading database, on that database or the decorator context.
350
+ const executeDefault = async (onSql) => {
351
+ const lead = await leadingDb();
352
+ if (lead === undefined)
353
+ return executeMethodSql(callArgs, undefined, onSql);
354
+ return executeMethodSql(callArgs.slice(1), await explicitTarget(lead), onSql);
355
+ };
319
356
  // run's argument-taking forms: return the adapter's raw result.
320
357
  const executeInvocation = async (invocation, onSql) => {
321
358
  if (invocation.kind === 'fragment') {
@@ -327,17 +364,19 @@ export function Query(arg) {
327
364
  onSql(boundSql);
328
365
  return executeOnTarget(target, boundSql, params);
329
366
  }
330
- // run(db, params): the method's own SQL against db, bound from params
331
- // only (an object for :named, an array for :argN).
332
- const target = await resolveRunTarget(invocation.db);
333
- // Inline SQL needs no resolver; only look one up for file-based SQL.
334
- const resolver = target.byName
335
- ? target.resolver
336
- : labels?.source?.kind === 'inline'
337
- ? undefined
338
- : await resolveSqlResolver();
367
+ if (invocation.kind === 'db') {
368
+ // run(db): the method's own SQL against db, bound from the method's
369
+ // arguments minus a leading database argument.
370
+ const lead = await leadingDb();
371
+ const bindArgs = lead === undefined ? callArgs : callArgs.slice(1);
372
+ return executeMethodSql(bindArgs, await explicitTarget(invocation.db), onSql);
373
+ }
374
+ // run(db, params) / run(params): the method's own SQL bound from params
375
+ // only (an object for :named, an array for :argN), against run's db,
376
+ // else the method's leading database, else the decorator context.
339
377
  const bindArgs = Array.isArray(invocation.params) ? [...invocation.params] : [invocation.params];
340
- return executeMethodSql(bindArgs, { target, resolver }, onSql);
378
+ const db = invocation.db ?? (await leadingDb());
379
+ return executeMethodSql(bindArgs, db !== undefined ? await explicitTarget(db) : undefined, onSql);
341
380
  };
342
381
  // The full pipeline: execute, then — if rows were returned
343
382
  // (SELECT/CTE/RETURNING) — shape + transform + validate; a write result
@@ -349,7 +388,7 @@ export function Query(arg) {
349
388
  // DatabaseError with the original error in `.cause`.
350
389
  const pipeline = async (invocation) => {
351
390
  if (invocation === undefined || invocation.kind === 'default') {
352
- const out = await executeMethodSql(callArgs, undefined, () => { });
391
+ const out = await executeDefault(() => { });
353
392
  return finishResult(out, labels, this, prop);
354
393
  }
355
394
  let sqlText = invocation.kind === 'fragment' ? fragmentText(invocation.fragment) : '';
@@ -393,7 +432,7 @@ export function Query(arg) {
393
432
  const db = entry.db;
394
433
  let out;
395
434
  try {
396
- const tx = getActiveTransaction(entry);
435
+ const tx = getTransactionTarget(entry);
397
436
  out = tx ? await tx.query(boundSql, params) : await db.query(boundSql, params);
398
437
  }
399
438
  catch (dbError) {
@@ -406,6 +445,28 @@ export function Query(arg) {
406
445
  return desc;
407
446
  };
408
447
  }
448
+ // Directory-based SQL for a decorated method. An explicit @Query('<path>')
449
+ // is always the filesystem. A bare @Query() uses the packaged resources map
450
+ // when one is installed (bundled/packaged runtimes), else the filesystem next
451
+ // to the decorating module (tests, plain Node). Misses name every key tried.
452
+ function resolveSourceSql(source, className, methodName, dialect) {
453
+ if (!source || source.kind === 'inline')
454
+ return undefined;
455
+ if (source.kind === 'fs')
456
+ return resolveSqlFromFs(source.rootDir, methodName, dialect).sql;
457
+ const packaged = getResources();
458
+ const fromResources = packaged ? resolveSqlFromResources(source.dir, methodName, dialect) : undefined;
459
+ if (fromResources?.sql !== undefined)
460
+ return fromResources.sql;
461
+ try {
462
+ return resolveSqlFromFs(source.dir, methodName, dialect).sql;
463
+ }
464
+ catch (fsError) {
465
+ const triedResources = fromResources ? `\npackaged resources tried:\n${fromResources.tried.join('\n')}` : '';
466
+ throw new SqlStackError(`sqlstack: no SQL for ${className}.${methodName}.${triedResources}\n` +
467
+ `${fsError?.message ?? String(fsError)}`);
468
+ }
469
+ }
409
470
  // Deprecated (removal in the next major version): a @Query body that RETURNS
410
471
  // an sql`` fragment. It only type-checks when the method's declared return
411
472
  // type is bent to admit SqlFragment (an `as any`-style hole). One warning per