sqlstack 1.0.7 → 1.0.8

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 (162) hide show
  1. package/dist/cjs/adapters/index.d.ts.map +1 -0
  2. package/dist/cjs/adapters/index.js.map +1 -0
  3. package/dist/cjs/adapters/mysql.d.ts.map +1 -0
  4. package/dist/cjs/adapters/mysql.js.map +1 -0
  5. package/dist/cjs/adapters/pg.d.ts.map +1 -0
  6. package/dist/cjs/adapters/pg.js.map +1 -0
  7. package/dist/cjs/adapters/sqlite.d.ts.map +1 -0
  8. package/dist/cjs/adapters/sqlite.js.map +1 -0
  9. package/dist/cjs/adapters/test.d.ts.map +1 -0
  10. package/dist/cjs/adapters/test.js.map +1 -0
  11. package/dist/cjs/binders/sqlBinder.d.ts.map +1 -0
  12. package/dist/cjs/binders/sqlBinder.js.map +1 -0
  13. package/dist/cjs/core/errors.d.ts.map +1 -0
  14. package/dist/cjs/core/errors.js.map +1 -0
  15. package/dist/cjs/core/fileResolution.d.ts.map +1 -0
  16. package/dist/cjs/core/fileResolution.js.map +1 -0
  17. package/dist/cjs/core/metadata.d.ts.map +1 -0
  18. package/dist/cjs/core/metadata.js.map +1 -0
  19. package/dist/cjs/core/validator.d.ts.map +1 -0
  20. package/dist/cjs/core/validator.js.map +1 -0
  21. package/dist/cjs/decorators/defaults.d.ts.map +1 -0
  22. package/dist/cjs/decorators/defaults.js.map +1 -0
  23. package/dist/cjs/decorators/page.d.ts.map +1 -0
  24. package/dist/cjs/decorators/page.js.map +1 -0
  25. package/dist/cjs/decorators/query.d.ts.map +1 -0
  26. package/dist/cjs/decorators/query.js.map +1 -0
  27. package/dist/cjs/decorators/queryBinder.d.ts.map +1 -0
  28. package/dist/cjs/decorators/queryBinder.js.map +1 -0
  29. package/dist/cjs/decorators/resultShape.d.ts.map +1 -0
  30. package/dist/cjs/decorators/resultShape.js.map +1 -0
  31. package/dist/cjs/decorators/transform.d.ts.map +1 -0
  32. package/dist/cjs/decorators/transform.js.map +1 -0
  33. package/dist/cjs/decorators/validateResult.d.ts.map +1 -0
  34. package/dist/cjs/decorators/validateResult.js.map +1 -0
  35. package/dist/cjs/index.d.ts.map +1 -0
  36. package/dist/cjs/index.js.map +1 -0
  37. package/dist/cjs/registry.d.ts.map +1 -0
  38. package/dist/cjs/registry.js.map +1 -0
  39. package/dist/cjs/utils/dto.d.ts.map +1 -0
  40. package/dist/cjs/utils/dto.js.map +1 -0
  41. package/dist/esm/adapters/index.js +4 -0
  42. package/dist/esm/adapters/index.js.map +1 -0
  43. package/dist/esm/adapters/mysql.js +36 -0
  44. package/dist/esm/adapters/mysql.js.map +1 -0
  45. package/dist/esm/adapters/pg.js +67 -0
  46. package/dist/esm/adapters/pg.js.map +1 -0
  47. package/dist/esm/adapters/sqlite.js +141 -0
  48. package/dist/esm/adapters/sqlite.js.map +1 -0
  49. package/dist/esm/adapters/test.js +47 -0
  50. package/dist/esm/adapters/test.js.map +1 -0
  51. package/dist/esm/binders/sqlBinder.js +182 -0
  52. package/dist/esm/binders/sqlBinder.js.map +1 -0
  53. package/dist/esm/core/errors.js +25 -0
  54. package/dist/esm/core/errors.js.map +1 -0
  55. package/dist/esm/core/fileResolution.js +74 -0
  56. package/dist/esm/core/fileResolution.js.map +1 -0
  57. package/dist/esm/core/metadata.js +24 -0
  58. package/dist/esm/core/metadata.js.map +1 -0
  59. package/dist/esm/core/validator.js +57 -0
  60. package/dist/esm/core/validator.js.map +1 -0
  61. package/dist/esm/decorators/defaults.js +7 -0
  62. package/dist/esm/decorators/defaults.js.map +1 -0
  63. package/dist/esm/decorators/page.js +8 -0
  64. package/dist/esm/decorators/page.js.map +1 -0
  65. package/dist/esm/decorators/query.js +278 -0
  66. package/dist/esm/decorators/query.js.map +1 -0
  67. package/dist/esm/decorators/queryBinder.js +7 -0
  68. package/dist/esm/decorators/queryBinder.js.map +1 -0
  69. package/dist/esm/decorators/resultShape.js +14 -0
  70. package/dist/esm/decorators/resultShape.js.map +1 -0
  71. package/dist/esm/decorators/transform.js +8 -0
  72. package/dist/esm/decorators/transform.js.map +1 -0
  73. package/dist/esm/decorators/validateResult.js +8 -0
  74. package/dist/esm/decorators/validateResult.js.map +1 -0
  75. package/dist/esm/index.js +14 -0
  76. package/dist/esm/index.js.map +1 -0
  77. package/dist/esm/package.json +3 -0
  78. package/dist/esm/registry.js +26 -0
  79. package/dist/esm/registry.js.map +1 -0
  80. package/dist/esm/utils/dto.js +129 -0
  81. package/dist/esm/utils/dto.js.map +1 -0
  82. package/package.json +18 -16
  83. package/dist/adapters/index.d.ts.map +0 -1
  84. package/dist/adapters/index.js.map +0 -1
  85. package/dist/adapters/mysql.d.ts.map +0 -1
  86. package/dist/adapters/mysql.js.map +0 -1
  87. package/dist/adapters/pg.d.ts.map +0 -1
  88. package/dist/adapters/pg.js.map +0 -1
  89. package/dist/adapters/sqlite.d.ts.map +0 -1
  90. package/dist/adapters/sqlite.js.map +0 -1
  91. package/dist/adapters/test.d.ts.map +0 -1
  92. package/dist/adapters/test.js.map +0 -1
  93. package/dist/binders/sqlBinder.d.ts.map +0 -1
  94. package/dist/binders/sqlBinder.js.map +0 -1
  95. package/dist/core/errors.d.ts.map +0 -1
  96. package/dist/core/errors.js.map +0 -1
  97. package/dist/core/fileResolution.d.ts.map +0 -1
  98. package/dist/core/fileResolution.js.map +0 -1
  99. package/dist/core/metadata.d.ts.map +0 -1
  100. package/dist/core/metadata.js.map +0 -1
  101. package/dist/core/validator.d.ts.map +0 -1
  102. package/dist/core/validator.js.map +0 -1
  103. package/dist/decorators/defaults.d.ts.map +0 -1
  104. package/dist/decorators/defaults.js.map +0 -1
  105. package/dist/decorators/page.d.ts.map +0 -1
  106. package/dist/decorators/page.js.map +0 -1
  107. package/dist/decorators/query.d.ts.map +0 -1
  108. package/dist/decorators/query.js.map +0 -1
  109. package/dist/decorators/queryBinder.d.ts.map +0 -1
  110. package/dist/decorators/queryBinder.js.map +0 -1
  111. package/dist/decorators/resultShape.d.ts.map +0 -1
  112. package/dist/decorators/resultShape.js.map +0 -1
  113. package/dist/decorators/transform.d.ts.map +0 -1
  114. package/dist/decorators/transform.js.map +0 -1
  115. package/dist/decorators/validateResult.d.ts.map +0 -1
  116. package/dist/decorators/validateResult.js.map +0 -1
  117. package/dist/index.d.ts.map +0 -1
  118. package/dist/index.js.map +0 -1
  119. package/dist/registry.d.ts.map +0 -1
  120. package/dist/registry.js.map +0 -1
  121. package/dist/utils/dto.d.ts.map +0 -1
  122. package/dist/utils/dto.js.map +0 -1
  123. /package/dist/{adapters → cjs/adapters}/index.d.ts +0 -0
  124. /package/dist/{adapters → cjs/adapters}/index.js +0 -0
  125. /package/dist/{adapters → cjs/adapters}/mysql.d.ts +0 -0
  126. /package/dist/{adapters → cjs/adapters}/mysql.js +0 -0
  127. /package/dist/{adapters → cjs/adapters}/pg.d.ts +0 -0
  128. /package/dist/{adapters → cjs/adapters}/pg.js +0 -0
  129. /package/dist/{adapters → cjs/adapters}/sqlite.d.ts +0 -0
  130. /package/dist/{adapters → cjs/adapters}/sqlite.js +0 -0
  131. /package/dist/{adapters → cjs/adapters}/test.d.ts +0 -0
  132. /package/dist/{adapters → cjs/adapters}/test.js +0 -0
  133. /package/dist/{binders → cjs/binders}/sqlBinder.d.ts +0 -0
  134. /package/dist/{binders → cjs/binders}/sqlBinder.js +0 -0
  135. /package/dist/{core → cjs/core}/errors.d.ts +0 -0
  136. /package/dist/{core → cjs/core}/errors.js +0 -0
  137. /package/dist/{core → cjs/core}/fileResolution.d.ts +0 -0
  138. /package/dist/{core → cjs/core}/fileResolution.js +0 -0
  139. /package/dist/{core → cjs/core}/metadata.d.ts +0 -0
  140. /package/dist/{core → cjs/core}/metadata.js +0 -0
  141. /package/dist/{core → cjs/core}/validator.d.ts +0 -0
  142. /package/dist/{core → cjs/core}/validator.js +0 -0
  143. /package/dist/{decorators → cjs/decorators}/defaults.d.ts +0 -0
  144. /package/dist/{decorators → cjs/decorators}/defaults.js +0 -0
  145. /package/dist/{decorators → cjs/decorators}/page.d.ts +0 -0
  146. /package/dist/{decorators → cjs/decorators}/page.js +0 -0
  147. /package/dist/{decorators → cjs/decorators}/query.d.ts +0 -0
  148. /package/dist/{decorators → cjs/decorators}/query.js +0 -0
  149. /package/dist/{decorators → cjs/decorators}/queryBinder.d.ts +0 -0
  150. /package/dist/{decorators → cjs/decorators}/queryBinder.js +0 -0
  151. /package/dist/{decorators → cjs/decorators}/resultShape.d.ts +0 -0
  152. /package/dist/{decorators → cjs/decorators}/resultShape.js +0 -0
  153. /package/dist/{decorators → cjs/decorators}/transform.d.ts +0 -0
  154. /package/dist/{decorators → cjs/decorators}/transform.js +0 -0
  155. /package/dist/{decorators → cjs/decorators}/validateResult.d.ts +0 -0
  156. /package/dist/{decorators → cjs/decorators}/validateResult.js +0 -0
  157. /package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
  158. /package/dist/{index.js → cjs/index.js} +0 -0
  159. /package/dist/{registry.d.ts → cjs/registry.d.ts} +0 -0
  160. /package/dist/{registry.js → cjs/registry.js} +0 -0
  161. /package/dist/{utils → cjs/utils}/dto.d.ts +0 -0
  162. /package/dist/{utils → cjs/utils}/dto.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/core/validator.ts"],"names":[],"mappings":"AAAA,OAAO,GAAqB,MAAM,KAAK,CAAC;AACxC,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,OAAO,eAAgB,SAAQ,aAAa;IAChD,YAAmB,OAAe;QAChC,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;QADtB,YAAO,GAAP,OAAO,CAAQ;QAEhC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACxD,UAAU,CAAC,GAAG,CAAC,CAAC;AAEhB,MAAM,KAAK,GAAG,IAAI,OAAO,EAAsC,CAAC;AAEhE,SAAS,YAAY,CAAC,MAAW;IAC/B,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAgB,CAAC,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,CAAC,GAAG,CAAC,MAAgB,EAAE,QAAQ,CAAC,CAAC;QACtC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,eAAe,CAAC,gBAAgB,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAW,EAAE,IAAS;IACnD,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,MAA+B,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC5F,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,KAAyB;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,QAAQ,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QAC5B,KAAK,GAAG,CAAC;QACT,KAAK,MAAM,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,IAAI;YACP,OAAO,IAAI,CAAC;QACd;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,oBAAoB;IAClC,8DAA8D;IAC9D,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QAAE,OAAO,KAAK,CAAC;IACtE,yBAAyB;IACzB,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,uCAAuC;IACvC,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import Ajv, { DefinedError } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport { SqlStackError } from './errors';\n\nexport class ValidationError extends SqlStackError {\n constructor(public details: string) {\n super(`Validation failed: ${details}`);\n this.name = 'ValidationError';\n }\n}\n\nconst ajv = new Ajv({ allErrors: true, strict: false });\naddFormats(ajv);\n\nconst cache = new WeakMap<object, ReturnType<Ajv['compile']>>();\n\nfunction getValidator(schema: any) {\n if (schema && typeof schema === 'object') {\n const existing = cache.get(schema as object);\n if (existing) return existing;\n const compiled = ajv.compile(schema);\n cache.set(schema as object, compiled);\n return compiled;\n }\n throw new ValidationError('Invalid schema');\n}\n\nexport function validateOutput(schema: any, data: any) {\n const validate = getValidator(schema);\n const ok = validate(data);\n if (!ok) {\n const msg = ajv.errorsText(validate.errors as DefinedError[] | null, { dataVar: 'result' });\n throw new ValidationError(msg);\n }\n}\n\nfunction isTruthyEnv(value: string | undefined): boolean {\n if (!value) return false;\n switch (value.toLowerCase()) {\n case '1':\n case 'true':\n case 'yes':\n case 'on':\n return true;\n default:\n return false;\n }\n}\n\n// SQLSTACK_DISABLE_VALIDATION: when truthy, validation is skipped.\nexport function isValidationDisabled(): boolean {\n // Highest priority: explicit enable wins (even in production)\n if (isTruthyEnv(process.env.SQLSTACK_ENABLE_VALIDATION)) return false;\n // Next: explicit disable\n if (isTruthyEnv(process.env.SQLSTACK_DISABLE_VALIDATION)) return true;\n // Default: enabled in all environments\n return false;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { setMethodLabels } from '../core/metadata';
2
+ export function Defaults(values) {
3
+ return function (_target, prop) {
4
+ setMethodLabels(_target, prop, { defaults: { ...(values || {}) } });
5
+ };
6
+ }
7
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../src/decorators/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,UAAU,QAAQ,CAAC,MAA+B;IACtD,OAAO,UAAU,OAAY,EAAE,IAAqB;QAClD,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\nexport function Defaults(values: Record<string, unknown>) {\n return function (_target: any, prop: string | symbol) {\n setMethodLabels(_target, prop, { defaults: { ...(values || {}) } });\n };\n}\n\n"]}
@@ -0,0 +1,8 @@
1
+ import { setMethodLabels } from '../core/metadata';
2
+ export function Page(size, options) {
3
+ return function (_target, prop) {
4
+ const zeroBase = options?.zeroBase === true;
5
+ setMethodLabels(_target, prop, { page: { size, zeroBase } });
6
+ };
7
+ }
8
+ //# sourceMappingURL=page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/decorators/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMnD,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,OAAqB;IACtD,OAAO,UAAU,OAAY,EAAE,IAAqB;QAClD,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC5C,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\nexport type PageOptions = {\n zeroBase?: boolean; // default false → pages are 1-based\n};\n\nexport function Page(size: number, options?: PageOptions) {\n return function (_target: any, prop: string | symbol) {\n const zeroBase = options?.zeroBase === true;\n setMethodLabels(_target, prop, { page: { size, zeroBase } });\n };\n}\n\n// Runtime options object users can pass as the final argument\n// e.g. repo.list(userId, { page: 2 }) or repo.list({ user_id: 'u1' }, { page: 2 })\nexport interface PageOption {\n page?: number;\n}\n"]}
@@ -0,0 +1,278 @@
1
+ import { getClassLabels, getMethodLabels, setMethodLabels } from '../core/metadata';
2
+ import { SqlStackError, ExactlyOneRowError, NoRowsError, RowsExistError } from '../core/errors';
3
+ import { isValidationDisabled, validateOutput } from '../core/validator';
4
+ import { SqlStackDB } from '../registry';
5
+ import { createSqliteBinder, createMysqlBinder, createPostgresBinder } from '../binders/sqlBinder';
6
+ import { coerceRootPath, guessDecoratorDir, resolveSqlFromFs } from '../core/fileResolution';
7
+ export function Query(arg) {
8
+ return function (_target, prop, desc) {
9
+ const options = typeof arg === 'string' ? undefined : arg;
10
+ const rootArg = typeof arg === 'string' ? arg : undefined;
11
+ // Store method-level db override if provided
12
+ if (options?.db) {
13
+ setMethodLabels(_target, prop, { db: options.db });
14
+ }
15
+ // Store inline SQL if provided
16
+ if (options?.sql) {
17
+ setMethodLabels(_target, prop, { source: { kind: 'inline', sql: options.sql } });
18
+ }
19
+ else {
20
+ // FS-based resolution
21
+ const { rootDir } = coerceRootPath(rootArg);
22
+ const dir = rootDir ?? guessDecoratorDir();
23
+ if (dir) {
24
+ setMethodLabels(_target, prop, { source: { kind: 'fs', rootDir: dir } });
25
+ }
26
+ }
27
+ const original = desc.value;
28
+ desc.value = async function (...callArgs) {
29
+ const labels = getMethodLabels(this, prop);
30
+ const classLabels = getClassLabels(this);
31
+ // 1) prepare args with defaults
32
+ const rawInput = callArgs.length === 1 ? callArgs[0] : callArgs; // object or positional array
33
+ // 2) choose database and dialect
34
+ const dbName = labels.db ?? options?.db ?? classLabels?.db;
35
+ const db = SqlStackDB.get(dbName);
36
+ const dialect = options?.dialect ?? db.dialect ?? 'sqlite';
37
+ // 3) load SQL source (inline or fs)
38
+ const sql = labels?.source?.kind === 'inline'
39
+ ? labels.source.sql
40
+ : labels?.source?.kind === 'fs'
41
+ ? resolveSqlFromFs(labels.source.rootDir, String(prop), dialect).sql
42
+ : undefined;
43
+ if (!sql) {
44
+ throw new SqlStackError(`No SQL source provided for method ${String(prop)}. Use @Query() with a file/folder path or inline sql.`);
45
+ }
46
+ // 4) bind placeholders
47
+ // Decide argument mode: positional if SQL contains :argN
48
+ let workingSql = sql;
49
+ const hasPositional = /:arg[1-9][0-9]*/.test(workingSql);
50
+ // Prepare args for binder
51
+ let args;
52
+ if (hasPositional) {
53
+ args = callArgs;
54
+ }
55
+ else {
56
+ const namedBase = callArgs.length > 0 ? callArgs[0] : undefined;
57
+ args = applyDefaults(labels.defaults, namedBase ?? {});
58
+ }
59
+ // Compute paging and inject :offset/:limit (named mode) or rewrite to positional
60
+ const pageCfg = labels.page;
61
+ if (pageCfg) {
62
+ const { size, zeroBase } = pageCfg;
63
+ const base = zeroBase ? 0 : 1;
64
+ // Extract page number from input (object) or a trailing options object in positional mode
65
+ const pageFromObject = (val) => {
66
+ if (val && typeof val === 'object' && !Array.isArray(val) && typeof val.page !== 'undefined') {
67
+ const p = val.page;
68
+ if (typeof p === 'number' && isFinite(p))
69
+ return p;
70
+ }
71
+ return undefined;
72
+ };
73
+ let pageNum;
74
+ if (hasPositional) {
75
+ // Variadic-style: only the LAST argument may carry `{ page }`
76
+ if (callArgs.length > 0) {
77
+ const last = callArgs[callArgs.length - 1];
78
+ pageNum = pageFromObject(last);
79
+ }
80
+ }
81
+ else {
82
+ // Prefer last-arg options if provided; otherwise read from named object
83
+ if (callArgs.length > 1) {
84
+ const last = callArgs[callArgs.length - 1];
85
+ pageNum = pageFromObject(last);
86
+ }
87
+ if (pageNum === undefined) {
88
+ pageNum = pageFromObject(args);
89
+ }
90
+ }
91
+ const effectivePage = typeof pageNum === 'number' ? pageNum : base;
92
+ const offset = (effectivePage - base) * size;
93
+ const limit = size;
94
+ if (hasPositional) {
95
+ // Replace occurrences of :offset and :limit with new :argN tokens appended to args
96
+ const baseIndex = callArgs.length; // start numbering after user args
97
+ let nextIndex = baseIndex + 1;
98
+ const additions = [];
99
+ const rewrite = (sqlText) => {
100
+ const out = [];
101
+ let i = 0;
102
+ let inSQ = false, inDQ = false, inLC = false, inBC = false;
103
+ const len = sqlText.length;
104
+ while (i < len) {
105
+ const ch = sqlText[i];
106
+ const next = i + 1 < len ? sqlText[i + 1] : '';
107
+ if (inLC) {
108
+ out.push(ch);
109
+ if (ch === '\n')
110
+ inLC = false;
111
+ i++;
112
+ continue;
113
+ }
114
+ if (inBC) {
115
+ out.push(ch);
116
+ if (ch === '*' && next === '/') {
117
+ out.push(next);
118
+ i++;
119
+ inBC = false;
120
+ }
121
+ i++;
122
+ continue;
123
+ }
124
+ if (inSQ) {
125
+ out.push(ch);
126
+ if (ch === "'" && next === "'") {
127
+ out.push(next);
128
+ i += 2;
129
+ continue;
130
+ }
131
+ if (ch === "'")
132
+ inSQ = false;
133
+ i++;
134
+ continue;
135
+ }
136
+ if (inDQ) {
137
+ out.push(ch);
138
+ if (ch === '"' && next === '"') {
139
+ out.push(next);
140
+ i += 2;
141
+ continue;
142
+ }
143
+ if (ch === '"')
144
+ inDQ = false;
145
+ i++;
146
+ continue;
147
+ }
148
+ if (ch === '-' && next === '-') {
149
+ out.push(ch, next);
150
+ i += 2;
151
+ inLC = true;
152
+ continue;
153
+ }
154
+ if (ch === '/' && next === '*') {
155
+ out.push(ch, next);
156
+ i += 2;
157
+ inBC = true;
158
+ continue;
159
+ }
160
+ if (ch === '"') {
161
+ out.push(ch);
162
+ inDQ = true;
163
+ i++;
164
+ continue;
165
+ }
166
+ if (ch === "'") {
167
+ out.push(ch);
168
+ inSQ = true;
169
+ i++;
170
+ continue;
171
+ }
172
+ if (ch === ':' && next === ':') {
173
+ out.push('::');
174
+ i += 2;
175
+ continue;
176
+ }
177
+ if (ch === ':') {
178
+ // parse token
179
+ let j = i + 1;
180
+ const start = j;
181
+ while (j < len) {
182
+ const c = sqlText[j];
183
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '_')
184
+ j++;
185
+ else
186
+ break;
187
+ }
188
+ const name = sqlText.slice(start, j);
189
+ if (name === 'offset') {
190
+ const token = `:arg${nextIndex++}`;
191
+ out.push(token);
192
+ additions.push(offset);
193
+ i = j;
194
+ continue;
195
+ }
196
+ if (name === 'limit') {
197
+ const token = `:arg${nextIndex++}`;
198
+ out.push(token);
199
+ additions.push(limit);
200
+ i = j;
201
+ continue;
202
+ }
203
+ // otherwise leave untouched
204
+ out.push(':');
205
+ i++;
206
+ continue;
207
+ }
208
+ out.push(ch);
209
+ i++;
210
+ }
211
+ return out.join('');
212
+ };
213
+ const rewritten = rewrite(workingSql);
214
+ if (rewritten !== workingSql) {
215
+ workingSql = rewritten;
216
+ // append values so :argK map correctly
217
+ args.push(...additions);
218
+ }
219
+ }
220
+ else {
221
+ // Named-mode: attach computed values (override any provided)
222
+ args = { ...args, offset, limit };
223
+ }
224
+ }
225
+ const binder = dialect === 'postgres' ? createPostgresBinder() : dialect === 'mysql' ? createMysqlBinder() : createSqliteBinder();
226
+ const { sql: boundSql, params } = binder.bind(workingSql, args);
227
+ // 5) execute query via registry DB
228
+ const out = await db.query(boundSql, params);
229
+ // 6) If rows were returned (SELECT/CTE), shape + transform + validate
230
+ if (Array.isArray(out)) {
231
+ const shaped = applyShape(out, labels.shape);
232
+ const transformed = labels.transform ? labels.transform(shaped) : shaped;
233
+ // 7) validate result via JSON Schema, if provided
234
+ if (labels.validateSchema && !isValidationDisabled()) {
235
+ if (Array.isArray(transformed)) {
236
+ for (const row of transformed)
237
+ validateOutput(labels.validateSchema, row);
238
+ }
239
+ else if (transformed !== null && transformed !== undefined) {
240
+ validateOutput(labels.validateSchema, transformed);
241
+ }
242
+ }
243
+ return transformed;
244
+ }
245
+ // Non-SELECT: return the write result as-is
246
+ return out;
247
+ };
248
+ return desc;
249
+ };
250
+ }
251
+ function applyDefaults(defaults, input) {
252
+ if (!defaults)
253
+ return input;
254
+ if (Array.isArray(input))
255
+ return input; // defaults only apply to named-object args
256
+ return { ...defaults, ...(input || {}) };
257
+ }
258
+ function applyShape(rows, shape) {
259
+ switch (shape) {
260
+ case 'single':
261
+ return rows.length > 0 ? rows[0] : null;
262
+ case 'only':
263
+ if (rows.length !== 1)
264
+ throw new ExactlyOneRowError(rows.length);
265
+ return rows[0];
266
+ case 'exist':
267
+ if (rows.length < 1)
268
+ throw new NoRowsError();
269
+ return rows[0];
270
+ case 'none':
271
+ if (rows.length > 0)
272
+ throw new RowsExistError(rows.length);
273
+ return null;
274
+ default:
275
+ return rows;
276
+ }
277
+ }
278
+ //# sourceMappingURL=query.js.map
@@ -0,0 +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 } 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';\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 // 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 db = SqlStackDB.get(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 const out = await db.query(boundSql, params);\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"]}
@@ -0,0 +1,7 @@
1
+ import { setClassLabels } from '../core/metadata';
2
+ export function QueryBinder(options) {
3
+ return function (ctor) {
4
+ setClassLabels(ctor, { db: options?.db });
5
+ };
6
+ }
7
+ //# sourceMappingURL=queryBinder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryBinder.js","sourceRoot":"","sources":["../../../src/decorators/queryBinder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,UAAU,WAAW,CAAC,OAAyB;IACnD,OAAO,UAAU,IAAc;QAC7B,cAAc,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setClassLabels } from '../core/metadata';\n\nexport function QueryBinder(options?: { db?: string }) {\n return function (ctor: Function) {\n setClassLabels(ctor, { db: options?.db });\n };\n}\n\n"]}
@@ -0,0 +1,14 @@
1
+ import { setMethodLabels } from '../core/metadata';
2
+ export function Single(target, prop) {
3
+ setMethodLabels(target, prop, { shape: 'single' });
4
+ }
5
+ export function Only(target, prop) {
6
+ setMethodLabels(target, prop, { shape: 'only' });
7
+ }
8
+ export function Exist(target, prop) {
9
+ setMethodLabels(target, prop, { shape: 'exist' });
10
+ }
11
+ export function None(target, prop) {
12
+ setMethodLabels(target, prop, { shape: 'none' });
13
+ }
14
+ //# sourceMappingURL=resultShape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resultShape.js","sourceRoot":"","sources":["../../../src/decorators/resultShape.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,UAAU,MAAM,CAAC,MAAW,EAAE,IAAqB;IACvD,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,MAAW,EAAE,IAAqB;IACrD,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,MAAW,EAAE,IAAqB;IACtD,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,MAAW,EAAE,IAAqB;IACrD,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\nexport function Single(target: any, prop: string | symbol) {\n setMethodLabels(target, prop, { shape: 'single' });\n}\n\nexport function Only(target: any, prop: string | symbol) {\n setMethodLabels(target, prop, { shape: 'only' });\n}\n\nexport function Exist(target: any, prop: string | symbol) {\n setMethodLabels(target, prop, { shape: 'exist' });\n}\n\nexport function None(target: any, prop: string | symbol) {\n setMethodLabels(target, prop, { shape: 'none' });\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { setMethodLabels } from '../core/metadata';
2
+ // Transform operates on the shaped value (array of rows, single row, or null)
3
+ export function Transform(fn) {
4
+ return function (target, prop) {
5
+ setMethodLabels(target, prop, { transform: fn });
6
+ };
7
+ }
8
+ //# sourceMappingURL=transform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/decorators/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAwB,EAAwB;IACvE,OAAO,UAAU,MAAW,EAAE,IAAqB;QACjD,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAS,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\n// Transform operates on the shaped value (array of rows, single row, or null)\nexport function Transform<TIn = any, TOut = any>(fn: (value: TIn) => TOut) {\n return function (target: any, prop: string | symbol) {\n setMethodLabels(target, prop, { transform: fn as any });\n };\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { setMethodLabels } from '../core/metadata';
2
+ // Accept a JSON Schema directly
3
+ export function ValidateResult(schema) {
4
+ return function (target, prop) {
5
+ setMethodLabels(target, prop, { validateSchema: schema });
6
+ };
7
+ }
8
+ //# sourceMappingURL=validateResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateResult.js","sourceRoot":"","sources":["../../../src/decorators/validateResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,gCAAgC;AAChC,MAAM,UAAU,cAAc,CAAC,MAAe;IAC5C,OAAO,UAAU,MAAW,EAAE,IAAqB;QACjD,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { setMethodLabels } from '../core/metadata';\n\n// Accept a JSON Schema directly\nexport function ValidateResult(schema: unknown) {\n return function (target: any, prop: string | symbol) {\n setMethodLabels(target, prop, { validateSchema: schema });\n };\n}\n\n"]}
@@ -0,0 +1,14 @@
1
+ export * from './binders/sqlBinder';
2
+ export * from './core/errors';
3
+ export * from './core/validator';
4
+ export * from './registry';
5
+ export * from './adapters';
6
+ export * from './decorators/queryBinder';
7
+ export * from './decorators/query';
8
+ export * from './decorators/defaults';
9
+ export * from './decorators/resultShape';
10
+ export * from './decorators/validateResult';
11
+ export * from './decorators/transform';
12
+ export * from './decorators/page';
13
+ export * from './utils/dto';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,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;AAClC,cAAc,aAAa,CAAC","sourcesContent":["export * from './binders/sqlBinder';\nexport * from './core/errors';\nexport * from './core/validator';\nexport * from './registry';\nexport * from './adapters';\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';\nexport * from './utils/dto';\n"]}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,26 @@
1
+ class Registry {
2
+ constructor() {
3
+ this.map = new Map();
4
+ }
5
+ register(name, db) {
6
+ this.map.set(name, db);
7
+ return this;
8
+ }
9
+ setDefault(name) {
10
+ if (!this.map.has(name))
11
+ throw new Error(`No database registered under ${name}`);
12
+ this.defaultName = name;
13
+ return this;
14
+ }
15
+ get(name) {
16
+ const key = name ?? this.defaultName;
17
+ if (!key)
18
+ throw new Error('No default database set');
19
+ const db = this.map.get(key);
20
+ if (!db)
21
+ throw new Error(`No database registered under ${key}`);
22
+ return db;
23
+ }
24
+ }
25
+ export const SqlStackDB = new Registry();
26
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAwBA,MAAM,QAAQ;IAAd;QACU,QAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IAqB5C,CAAC;IAlBC,QAAQ,CAAC,IAAY,EAAE,EAAY;QACjC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAa;QACf,MAAM,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC;QACrC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QACrD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;QAChE,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,QAAQ,EAAE,CAAC","sourcesContent":["export type Dialect = 'sqlite' | 'mysql' | 'postgres';\n\n// Result for non-SELECT statements across adapters\nexport interface WriteResult {\n rowsAffected: number;\n lastInsertId?: unknown;\n}\n\n// Postgres-specific extension when using RETURNING on write statements\nexport interface PostgresWriteResult extends WriteResult {\n // Only present when the SQL includes RETURNING and rows are returned\n returning?: any[];\n}\n\nexport type QueryResult = any[] | WriteResult | PostgresWriteResult;\n\nexport interface Database {\n dialect: Dialect;\n query(sql: string, params: unknown[]): Promise<QueryResult>;\n // Underlying driver connection or pool (driver-specific)\n conn: unknown;\n close: () => Promise<void> | void;\n}\n\nclass Registry {\n private map = new Map<string, Database>();\n private defaultName?: string;\n\n register(name: string, db: Database) {\n this.map.set(name, db);\n return this;\n }\n\n setDefault(name: string) {\n if (!this.map.has(name)) throw new Error(`No database registered under ${name}`);\n this.defaultName = name;\n return this;\n }\n\n get(name?: string): Database {\n const key = name ?? this.defaultName;\n if (!key) throw new Error('No default database set');\n const db = this.map.get(key);\n if (!db) throw new Error(`No database registered under ${key}`);\n return db;\n }\n}\n\nexport const SqlStackDB = new Registry();\n"]}
@@ -0,0 +1,129 @@
1
+ const CHILD_INDEX = Symbol('childIndex');
2
+ function setDeep(obj, path, value) {
3
+ const parts = path.split('.');
4
+ let cur = obj;
5
+ for (let i = 0; i < parts.length - 1; i++) {
6
+ const k = parts[i];
7
+ if (cur[k] == null || typeof cur[k] !== 'object')
8
+ cur[k] = {};
9
+ cur = cur[k];
10
+ }
11
+ cur[parts[parts.length - 1]] = value;
12
+ }
13
+ function childCollections(spec) {
14
+ const out = [];
15
+ for (const key of Object.keys(spec)) {
16
+ if (key === 'id' || key === 'name')
17
+ continue;
18
+ const val = spec[key];
19
+ if (val && typeof val === 'object' && !Array.isArray(val))
20
+ out.push([key, val]);
21
+ }
22
+ return out;
23
+ }
24
+ function ensureChildInfra(node, collectionKey) {
25
+ if (!node[collectionKey])
26
+ node[collectionKey] = [];
27
+ if (!node[CHILD_INDEX])
28
+ node[CHILD_INDEX] = {};
29
+ const idxBag = node[CHILD_INDEX];
30
+ if (!idxBag[collectionKey])
31
+ idxBag[collectionKey] = new Map();
32
+ return { arr: node[collectionKey], index: idxBag[collectionKey] };
33
+ }
34
+ function stripMeta(node) {
35
+ if (node && typeof node === 'object') {
36
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
37
+ delete node[CHILD_INDEX];
38
+ for (const k of Object.keys(node)) {
39
+ const v = node[k];
40
+ if (Array.isArray(v))
41
+ v.forEach(stripMeta);
42
+ }
43
+ }
44
+ return node;
45
+ }
46
+ /**
47
+ * Build a rows→tree transformer from a nested spec.
48
+ */
49
+ export function DTO(spec, opts = {}) {
50
+ const single = opts.single ?? false;
51
+ const mappingsCache = new WeakMap();
52
+ function getMappings(levelSpec) {
53
+ const cached = mappingsCache.get(levelSpec);
54
+ if (cached)
55
+ return cached;
56
+ const out = [];
57
+ for (const [k, v] of Object.entries(levelSpec)) {
58
+ if (typeof v === 'string')
59
+ out.push([k, v]);
60
+ }
61
+ // Ensure stable ordering so identity is independent of spec key order
62
+ out.sort((a, b) => a[0].localeCompare(b[0]));
63
+ mappingsCache.set(levelSpec, out);
64
+ return out;
65
+ }
66
+ function computeKey(levelSpec, row) {
67
+ const mappings = getMappings(levelSpec);
68
+ if (mappings.length === 0)
69
+ return undefined;
70
+ const pairs = mappings.map(([, source]) => row[source]);
71
+ // If all mapping values are null/undefined, skip
72
+ if (pairs.every((v) => v === null || v === undefined))
73
+ return undefined;
74
+ // Stable composite key: include source keys with values
75
+ const composite = mappings.map(([, source], i) => [source, pairs[i]]);
76
+ return JSON.stringify(composite);
77
+ }
78
+ function upsertAtLevel(rowsIndex, rowsOut, levelSpec, row) {
79
+ const nodeKey = computeKey(levelSpec, row);
80
+ if (nodeKey == null)
81
+ return null;
82
+ let node = rowsIndex.get(nodeKey);
83
+ if (!node) {
84
+ node = {};
85
+ for (const [target, source] of getMappings(levelSpec)) {
86
+ if (source in row)
87
+ setDeep(node, target, row[source]);
88
+ }
89
+ rowsIndex.set(nodeKey, node);
90
+ rowsOut.push(node);
91
+ }
92
+ return node;
93
+ }
94
+ function descend(parent, levelSpec, row) {
95
+ for (const [collectionKey, childSpec] of childCollections(levelSpec)) {
96
+ const childKey = computeKey(childSpec, row);
97
+ if (childKey == null)
98
+ continue; // skip this branch for this row
99
+ const { arr, index } = ensureChildInfra(parent, collectionKey);
100
+ let child = index.get(childKey);
101
+ if (!child) {
102
+ child = {};
103
+ for (const [target, source] of getMappings(childSpec)) {
104
+ if (source in row)
105
+ setDeep(child, target, row[source]);
106
+ }
107
+ index.set(childKey, child);
108
+ arr.push(child);
109
+ }
110
+ // Recurse further for this child (it may host its own collections)
111
+ descend(child, childSpec, row);
112
+ }
113
+ }
114
+ return function transform(rows) {
115
+ if (!rows || rows.length === 0)
116
+ return single ? null : [];
117
+ const roots = [];
118
+ const rootIndex = new Map();
119
+ for (const row of rows) {
120
+ const root = upsertAtLevel(rootIndex, roots, spec, row);
121
+ if (!root)
122
+ continue;
123
+ descend(root, spec, row);
124
+ }
125
+ roots.forEach(stripMeta);
126
+ return single ? roots[0] ?? null : roots;
127
+ };
128
+ }
129
+ //# sourceMappingURL=dto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dto.js","sourceRoot":"","sources":["../../../src/utils/dto.ts"],"names":[],"mappings":"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","sourcesContent":["type KV = Record<string, any>;\n\nexport type NodeSpec = {\n id?: string;\n name?: string;\n // nested collections: { [collectionKey]: NodeSpec }\n [collectionKey: string]: any;\n};\n\ntype DTOOptions = {\n /** If true, return a single root (or null). If false, return an array of roots. Default: true */\n single?: boolean;\n};\n\nconst CHILD_INDEX = Symbol('childIndex');\n\nfunction setDeep(obj: KV, path: string, value: any) {\n const parts = path.split('.');\n let cur: any = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i]!;\n if (cur[k] == null || typeof cur[k] !== 'object') cur[k] = {};\n cur = cur[k];\n }\n cur[parts[parts.length - 1]!] = value;\n}\n\nfunction childCollections(spec: NodeSpec): Array<[string, NodeSpec]> {\n const out: Array<[string, NodeSpec]> = [];\n for (const key of Object.keys(spec)) {\n if (key === 'id' || key === 'name') continue;\n const val = (spec as any)[key];\n if (val && typeof val === 'object' && !Array.isArray(val)) out.push([key, val as NodeSpec]);\n }\n return out;\n}\n\nfunction ensureChildInfra(node: KV, collectionKey: string) {\n if (!node[collectionKey]) node[collectionKey] = [];\n if (!(node as any)[CHILD_INDEX]) (node as any)[CHILD_INDEX] = {} as Record<string, Map<any, KV>>;\n const idxBag = (node as any)[CHILD_INDEX] as Record<string, Map<any, KV>>;\n if (!idxBag[collectionKey]) idxBag[collectionKey] = new Map<any, KV>();\n return { arr: node[collectionKey] as KV[], index: idxBag[collectionKey] as Map<any, KV> };\n}\n\nfunction stripMeta(node: KV) {\n if (node && typeof node === 'object') {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (node as any)[CHILD_INDEX];\n for (const k of Object.keys(node)) {\n const v = node[k];\n if (Array.isArray(v)) v.forEach(stripMeta);\n }\n }\n return node;\n}\n\n/**\n * Build a rows→tree transformer from a nested spec.\n */\nexport function DTO(spec: NodeSpec, opts: DTOOptions = {}) {\n const single = opts.single ?? false;\n type IndexMap = Map<any, KV>;\n const mappingsCache = new WeakMap<NodeSpec, Array<[string, string]>>();\n\n function getMappings(levelSpec: NodeSpec): Array<[string, string]> {\n const cached = mappingsCache.get(levelSpec);\n if (cached) return cached;\n const out: Array<[string, string]> = [];\n for (const [k, v] of Object.entries(levelSpec)) {\n if (typeof v === 'string') out.push([k, v]);\n }\n // Ensure stable ordering so identity is independent of spec key order\n out.sort((a, b) => (a[0] as string).localeCompare(b[0] as string));\n mappingsCache.set(levelSpec, out);\n return out;\n }\n\n function computeKey(levelSpec: NodeSpec, row: KV): any {\n const mappings = getMappings(levelSpec);\n if (mappings.length === 0) return undefined;\n const pairs = mappings.map(([, source]) => row[source]);\n // If all mapping values are null/undefined, skip\n if (pairs.every((v) => v === null || v === undefined)) return undefined;\n // Stable composite key: include source keys with values\n const composite = mappings.map(([, source], i) => [source, pairs[i]] as [string, any]);\n return JSON.stringify(composite);\n }\n\n function upsertAtLevel(rowsIndex: IndexMap, rowsOut: KV[], levelSpec: NodeSpec, row: KV) {\n const nodeKey = computeKey(levelSpec, row);\n if (nodeKey == null) return null;\n\n let node = rowsIndex.get(nodeKey);\n if (!node) {\n node = {};\n for (const [target, source] of getMappings(levelSpec)) {\n if (source in row) setDeep(node, target, (row as any)[source]);\n }\n rowsIndex.set(nodeKey, node);\n rowsOut.push(node);\n }\n return node;\n }\n\n function descend(parent: KV, levelSpec: NodeSpec, row: KV) {\n for (const [collectionKey, childSpec] of childCollections(levelSpec)) {\n const childKey = computeKey(childSpec, row);\n if (childKey == null) continue; // skip this branch for this row\n\n const { arr, index } = ensureChildInfra(parent, collectionKey);\n let child = index.get(childKey);\n if (!child) {\n child = {};\n for (const [target, source] of getMappings(childSpec)) {\n if (source in row) setDeep(child, target, (row as any)[source]);\n }\n index.set(childKey, child);\n arr.push(child);\n }\n\n // Recurse further for this child (it may host its own collections)\n descend(child, childSpec, row);\n }\n }\n\n return function transform(rows: KV[]) {\n if (!rows || rows.length === 0) return single ? null : [];\n\n const roots: KV[] = [];\n const rootIndex: IndexMap = new Map();\n\n for (const row of rows) {\n const root = upsertAtLevel(rootIndex, roots, spec, row);\n if (!root) continue;\n descend(root, spec, row);\n }\n\n roots.forEach(stripMeta);\n return single ? roots[0] ?? null : roots;\n };\n}\n"]}