sqlstack 3.3.0 → 3.5.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 (128) hide show
  1. package/dist/cjs/adapters/sqlite.d.ts.map +1 -1
  2. package/dist/cjs/adapters/sqlite.js +4 -1
  3. package/dist/cjs/adapters/sqlite.js.map +1 -1
  4. package/dist/cjs/codegen/generateManifest.d.ts +3 -1
  5. package/dist/cjs/codegen/generateManifest.d.ts.map +1 -1
  6. package/dist/cjs/codegen/generateManifest.js +195 -3
  7. package/dist/cjs/codegen/generateManifest.js.map +1 -1
  8. package/dist/cjs/core/errors.d.ts +9 -0
  9. package/dist/cjs/core/errors.d.ts.map +1 -1
  10. package/dist/cjs/core/errors.js +10 -0
  11. package/dist/cjs/core/errors.js.map +1 -1
  12. package/dist/cjs/core/fileResolution.d.ts +7 -0
  13. package/dist/cjs/core/fileResolution.d.ts.map +1 -1
  14. package/dist/cjs/core/fileResolution.js +53 -14
  15. package/dist/cjs/core/fileResolution.js.map +1 -1
  16. package/dist/cjs/core/metadata.d.ts +5 -0
  17. package/dist/cjs/core/metadata.d.ts.map +1 -1
  18. package/dist/cjs/core/metadata.js.map +1 -1
  19. package/dist/cjs/core/resources.d.ts +36 -0
  20. package/dist/cjs/core/resources.d.ts.map +1 -0
  21. package/dist/cjs/core/resources.js +98 -0
  22. package/dist/cjs/core/resources.js.map +1 -0
  23. package/dist/cjs/core/sourceScanResolver.d.ts +8 -14
  24. package/dist/cjs/core/sourceScanResolver.d.ts.map +1 -1
  25. package/dist/cjs/core/sourceScanResolver.js +8 -20
  26. package/dist/cjs/core/sourceScanResolver.js.map +1 -1
  27. package/dist/cjs/decorators/query.d.ts +14 -0
  28. package/dist/cjs/decorators/query.d.ts.map +1 -1
  29. package/dist/cjs/decorators/query.js +208 -40
  30. package/dist/cjs/decorators/query.js.map +1 -1
  31. package/dist/cjs/family.d.ts.map +1 -1
  32. package/dist/cjs/family.js +3 -1
  33. package/dist/cjs/family.js.map +1 -1
  34. package/dist/cjs/index.d.ts +4 -1
  35. package/dist/cjs/index.d.ts.map +1 -1
  36. package/dist/cjs/index.js +7 -2
  37. package/dist/cjs/index.js.map +1 -1
  38. package/dist/cjs/run.d.ts +180 -6
  39. package/dist/cjs/run.d.ts.map +1 -1
  40. package/dist/cjs/run.js +158 -17
  41. package/dist/cjs/run.js.map +1 -1
  42. package/dist/cjs/runtime.d.ts +14 -0
  43. package/dist/cjs/runtime.d.ts.map +1 -1
  44. package/dist/cjs/runtime.js +30 -0
  45. package/dist/cjs/runtime.js.map +1 -1
  46. package/dist/cjs/sql.d.ts +19 -0
  47. package/dist/cjs/sql.d.ts.map +1 -1
  48. package/dist/cjs/sql.js +66 -28
  49. package/dist/cjs/sql.js.map +1 -1
  50. package/dist/cjs/stack.d.ts +16 -0
  51. package/dist/cjs/stack.d.ts.map +1 -1
  52. package/dist/cjs/stack.js +60 -27
  53. package/dist/cjs/stack.js.map +1 -1
  54. package/dist/cjs/testing/builder.d.ts.map +1 -1
  55. package/dist/cjs/testing/builder.js +14 -5
  56. package/dist/cjs/testing/builder.js.map +1 -1
  57. package/dist/cjs/testing/fixture-provenance.d.ts +3 -0
  58. package/dist/cjs/testing/fixture-provenance.d.ts.map +1 -0
  59. package/dist/cjs/testing/fixture-provenance.js +21 -0
  60. package/dist/cjs/testing/fixture-provenance.js.map +1 -0
  61. package/dist/cjs/testing/index.d.ts +2 -0
  62. package/dist/cjs/testing/index.d.ts.map +1 -1
  63. package/dist/cjs/testing/index.js +5 -1
  64. package/dist/cjs/testing/index.js.map +1 -1
  65. package/dist/cjs/testing/postgres/database.d.ts +9 -1
  66. package/dist/cjs/testing/postgres/database.d.ts.map +1 -1
  67. package/dist/cjs/testing/postgres/database.js +17 -13
  68. package/dist/cjs/testing/postgres/database.js.map +1 -1
  69. package/dist/cjs/testing/resource.d.ts +76 -0
  70. package/dist/cjs/testing/resource.d.ts.map +1 -0
  71. package/dist/cjs/testing/resource.js +117 -0
  72. package/dist/cjs/testing/resource.js.map +1 -0
  73. package/dist/cjs/testing/sqlite/builder.d.ts.map +1 -1
  74. package/dist/cjs/testing/sqlite/builder.js +10 -2
  75. package/dist/cjs/testing/sqlite/builder.js.map +1 -1
  76. package/dist/cjs/testing/sqlite/database.d.ts +11 -1
  77. package/dist/cjs/testing/sqlite/database.d.ts.map +1 -1
  78. package/dist/cjs/testing/sqlite/database.js +32 -18
  79. package/dist/cjs/testing/sqlite/database.js.map +1 -1
  80. package/dist/cjs/transactions.d.ts +66 -0
  81. package/dist/cjs/transactions.d.ts.map +1 -1
  82. package/dist/cjs/transactions.js +584 -3
  83. package/dist/cjs/transactions.js.map +1 -1
  84. package/dist/esm/adapters/sqlite.js +4 -1
  85. package/dist/esm/adapters/sqlite.js.map +1 -1
  86. package/dist/esm/codegen/generateManifest.js +195 -3
  87. package/dist/esm/codegen/generateManifest.js.map +1 -1
  88. package/dist/esm/core/errors.js +10 -0
  89. package/dist/esm/core/errors.js.map +1 -1
  90. package/dist/esm/core/fileResolution.js +52 -14
  91. package/dist/esm/core/fileResolution.js.map +1 -1
  92. package/dist/esm/core/metadata.js.map +1 -1
  93. package/dist/esm/core/resources.js +91 -0
  94. package/dist/esm/core/resources.js.map +1 -0
  95. package/dist/esm/core/sourceScanResolver.js +8 -19
  96. package/dist/esm/core/sourceScanResolver.js.map +1 -1
  97. package/dist/esm/decorators/query.js +214 -46
  98. package/dist/esm/decorators/query.js.map +1 -1
  99. package/dist/esm/family.js +3 -1
  100. package/dist/esm/family.js.map +1 -1
  101. package/dist/esm/index.js +4 -2
  102. package/dist/esm/index.js.map +1 -1
  103. package/dist/esm/run.js +153 -18
  104. package/dist/esm/run.js.map +1 -1
  105. package/dist/esm/runtime.js +28 -0
  106. package/dist/esm/runtime.js.map +1 -1
  107. package/dist/esm/sql.js +63 -27
  108. package/dist/esm/sql.js.map +1 -1
  109. package/dist/esm/stack.js +61 -28
  110. package/dist/esm/stack.js.map +1 -1
  111. package/dist/esm/testing/builder.js +14 -5
  112. package/dist/esm/testing/builder.js.map +1 -1
  113. package/dist/esm/testing/fixture-provenance.js +15 -0
  114. package/dist/esm/testing/fixture-provenance.js.map +1 -0
  115. package/dist/esm/testing/index.js +1 -0
  116. package/dist/esm/testing/index.js.map +1 -1
  117. package/dist/esm/testing/postgres/database.js +17 -13
  118. package/dist/esm/testing/postgres/database.js.map +1 -1
  119. package/dist/esm/testing/resource.js +106 -0
  120. package/dist/esm/testing/resource.js.map +1 -0
  121. package/dist/esm/testing/sqlite/builder.js +10 -2
  122. package/dist/esm/testing/sqlite/builder.js.map +1 -1
  123. package/dist/esm/testing/sqlite/database.js +32 -18
  124. package/dist/esm/testing/sqlite/database.js.map +1 -1
  125. package/dist/esm/transactions.js +579 -3
  126. package/dist/esm/transactions.js.map +1 -1
  127. package/package.json +1 -1
  128. package/readme.md +201 -171
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { SqlStack, DatabaseEntry } from './stack';\nimport { SqlStackDB } from './registry';\nimport type { Database } from './registry';\nimport type { SqlResolver } from './core/resolver';\nimport { getActiveResolver } from './core/resolver';\nimport { SqlStackError } from './core/errors';\n\n/**\n * Active-environment resolution for @Query and transactions (spec 16 §17,\n * repo spec 19 §7/§9).\n *\n * Canonical path: the active IoC execution context (owned by @noego/ioc)\n * supplies the current scope; the scope resolves its root's SqlStack\n * Singleton. When an IoC environment is active, the process-global legacy\n * registry is NEVER consulted — legacy state cannot override an active root.\n *\n * Legacy path: with no active IoC environment, execution falls back to the\n * deprecated process-global SqlStackDB registry so existing consumers keep\n * working during migration.\n */\n\ntype IocModule = {\n ExecutionContext: { current(): any };\n DependencyNotFoundError?: new (...args: any[]) => Error;\n};\n\ntype ActiveScope = {\n get(label: any): unknown;\n isRegistered?(label: any): boolean;\n};\n\n// @noego/ioc is an optional peer: sqlstack remains usable standalone. The\n// import is dynamic so the CJS and ESM builds both work and so a missing\n// peer only disables the IoC path instead of breaking module load.\nlet iocModulePromise: Promise<IocModule | undefined> | undefined;\n\nfunction loadIoc(): Promise<IocModule | undefined> {\n iocModulePromise ??= import('@noego/ioc').then(\n (m: any) => (m?.ExecutionContext ? (m as IocModule) : undefined),\n () => undefined\n );\n return iocModulePromise;\n}\n\n/** @internal Test-only: force re-detection of @noego/ioc. */\nexport function __resetIocDetection(): void {\n iocModulePromise = undefined;\n}\n\nfunction missingActiveSqlStackError(): SqlStackError {\n return new SqlStackError(\n 'An IoC execution environment is active, but no SqlStack is registered in it. ' +\n 'Register a SqlStack at root composition (see registerSqlStack in \"sqlstack/ioc\").'\n );\n}\n\nfunction isDirectMissingSqlStackError(ioc: IocModule, err: unknown): boolean {\n const DependencyNotFoundError = ioc.DependencyNotFoundError;\n return (\n typeof DependencyNotFoundError === 'function' &&\n err instanceof DependencyNotFoundError &&\n err.message === 'Dependency not found: SqlStack'\n );\n}\n\n/**\n * The SqlStack for the active IoC execution context, or undefined when no\n * IoC environment is active (or @noego/ioc is not installed).\n *\n * Throws when an environment IS active but has no SqlStack registered —\n * silently falling back to global state under an active root is forbidden.\n */\nexport async function activeSqlStack(): Promise<SqlStack | undefined> {\n const ioc = await loadIoc();\n if (!ioc) return undefined;\n const scope = ioc.ExecutionContext.current() as ActiveScope | undefined;\n if (!scope) return undefined;\n\n // Newer IoC peers expose exact-token registration knowledge. Consulting it\n // before resolution distinguishes an absent SqlStack from errors raised by a\n // registered SqlStack provider (including DependencyNotFoundError).\n const registrationKnown = typeof scope.isRegistered === 'function';\n if (registrationKnown && !scope.isRegistered!(SqlStack)) {\n throw missingActiveSqlStackError();\n }\n\n try {\n return (await scope.get(SqlStack)) as SqlStack;\n } catch (err) {\n // Older optional peers cannot answer isRegistered(). Their direct missing\n // error is recognized by exported error identity plus the exact SqlStack\n // label; nested provider errors retain their original identity.\n if (!registrationKnown && isDirectMissingSqlStackError(ioc, err)) {\n throw missingActiveSqlStackError();\n }\n throw err;\n }\n}\n\nexport type ResolvedExecution = {\n entry: DatabaseEntry;\n resolver: SqlResolver | undefined;\n /** True when resolved through an active IoC root's SqlStack. */\n viaStack: boolean;\n};\n\n/**\n * Resolve the concrete database entry (and SQL resolver) for one execution.\n */\nexport async function resolveExecution(dbName?: string): Promise<ResolvedExecution> {\n const stack = await activeSqlStack();\n if (stack) {\n return { entry: await stack.resolveEntry(dbName), resolver: stack.resolver(), viaStack: true };\n }\n return {\n entry: legacyEntry(dbName),\n resolver: getActiveResolver(),\n viaStack: false,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Legacy (deprecated) global-registry support\n// ---------------------------------------------------------------------------\n\n// Stable DatabaseEntry identities for the legacy global registry, so the\n// entry-keyed transaction store works identically on both paths. Keyed by\n// name AND database object so re-registration under a name yields a fresh\n// identity (matching the fresh underlying connection).\nconst legacyEntries = new Map<string, { db: Database; entry: DatabaseEntry }>();\n\n// One shared legacy pseudo-stack so legacy entries carry a stack identity for\n// diagnostics. It is intentionally NOT usable as a real stack.\nlet legacyStack: SqlStack | undefined;\n\n/** @internal Resolve a legacy global-registry database as a DatabaseEntry. */\nexport function legacyEntry(dbName?: string): DatabaseEntry {\n const { name, db } = SqlStackDB.getEntry(dbName);\n const cached = legacyEntries.get(name);\n if (cached && cached.db === db) return cached.entry;\n legacyStack ??= new SqlStack();\n const entry: DatabaseEntry = { name, db, owned: false, stack: legacyStack };\n legacyEntries.set(name, { db, entry });\n return entry;\n}\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { SqlStack, DatabaseEntry } from './stack';\nimport { SqlStackDB } from './registry';\nimport type { Database } from './registry';\nimport type { SqlResolver } from './core/resolver';\nimport { getActiveResolver } from './core/resolver';\nimport { SqlStackError } from './core/errors';\n\n/**\n * Active-environment resolution for @Query and transactions (spec 16 §17,\n * repo spec 19 §7/§9).\n *\n * Canonical path: the active IoC execution context (owned by @noego/ioc)\n * supplies the current scope; the scope resolves its root's SqlStack\n * Singleton. When an IoC environment is active, the process-global legacy\n * registry is NEVER consulted — legacy state cannot override an active root.\n *\n * Legacy path: with no active IoC environment, execution falls back to the\n * deprecated process-global SqlStackDB registry so existing consumers keep\n * working during migration.\n */\n\ntype IocModule = {\n ExecutionContext: { current(): any };\n DependencyNotFoundError?: new (...args: any[]) => Error;\n};\n\ntype ActiveScope = {\n get(label: any): unknown;\n isRegistered?(label: any): boolean;\n};\n\n// @noego/ioc is an optional peer: sqlstack remains usable standalone. The\n// import is dynamic so the CJS and ESM builds both work and so a missing\n// peer only disables the IoC path instead of breaking module load.\nlet iocModulePromise: Promise<IocModule | undefined> | undefined;\n\nfunction loadIoc(): Promise<IocModule | undefined> {\n iocModulePromise ??= import('@noego/ioc').then(\n (m: any) => (m?.ExecutionContext ? (m as IocModule) : undefined),\n () => undefined\n );\n return iocModulePromise;\n}\n\n/** @internal Test-only: force re-detection of @noego/ioc. */\nexport function __resetIocDetection(): void {\n iocModulePromise = undefined;\n}\n\nfunction missingActiveSqlStackError(): SqlStackError {\n return new SqlStackError(\n 'An IoC execution environment is active, but no SqlStack is registered in it. ' +\n 'Register a SqlStack at root composition (see registerSqlStack in \"sqlstack/ioc\").'\n );\n}\n\nfunction isDirectMissingSqlStackError(ioc: IocModule, err: unknown): boolean {\n const DependencyNotFoundError = ioc.DependencyNotFoundError;\n return (\n typeof DependencyNotFoundError === 'function' &&\n err instanceof DependencyNotFoundError &&\n err.message === 'Dependency not found: SqlStack'\n );\n}\n\n/**\n * The SqlStack for the active IoC execution context, or undefined when no\n * IoC environment is active (or @noego/ioc is not installed).\n *\n * Throws when an environment IS active but has no SqlStack registered —\n * silently falling back to global state under an active root is forbidden.\n */\nexport async function activeSqlStack(): Promise<SqlStack | undefined> {\n const ioc = await loadIoc();\n if (!ioc) return undefined;\n const scope = ioc.ExecutionContext.current() as ActiveScope | undefined;\n if (!scope) return undefined;\n\n // Newer IoC peers expose exact-token registration knowledge. Consulting it\n // before resolution distinguishes an absent SqlStack from errors raised by a\n // registered SqlStack provider (including DependencyNotFoundError).\n const registrationKnown = typeof scope.isRegistered === 'function';\n if (registrationKnown && !scope.isRegistered!(SqlStack)) {\n throw missingActiveSqlStackError();\n }\n\n try {\n return (await scope.get(SqlStack)) as SqlStack;\n } catch (err) {\n // Older optional peers cannot answer isRegistered(). Their direct missing\n // error is recognized by exported error identity plus the exact SqlStack\n // label; nested provider errors retain their original identity.\n if (!registrationKnown && isDirectMissingSqlStackError(ioc, err)) {\n throw missingActiveSqlStackError();\n }\n throw err;\n }\n}\n\nexport type ResolvedExecution = {\n entry: DatabaseEntry;\n resolver: SqlResolver | undefined;\n /** True when resolved through an active IoC root's SqlStack. */\n viaStack: boolean;\n};\n\n/**\n * Resolve the concrete database entry (and SQL resolver) for one execution.\n */\nexport async function resolveExecution(dbName?: string): Promise<ResolvedExecution> {\n const stack = await activeSqlStack();\n if (stack) {\n return { entry: await stack.resolveEntry(dbName), resolver: stack.resolver(), viaStack: true };\n }\n return {\n entry: legacyEntry(dbName),\n resolver: getActiveResolver(),\n viaStack: false,\n };\n}\n\n/**\n * @internal The SQL source resolver for one execution WITHOUT resolving a\n * database — used when the caller supplied a database handle directly\n * (`run(db, params)`). Same environment rules as resolveExecution: the\n * active root's SqlStack resolver when an IoC environment is active (and an\n * error when that environment has no SqlStack), else the legacy global one.\n */\nexport async function resolveSqlResolver(): Promise<SqlResolver | undefined> {\n const stack = await activeSqlStack();\n return stack ? stack.resolver() : getActiveResolver();\n}\n\n/**\n * @internal Whether `name` is a database (or family) registered with the\n * active environment: the active root's SqlStack, else the legacy global\n * registry. Never throws; an environment that cannot answer reports false.\n */\nexport async function isRegisteredDatabaseName(name: string): Promise<boolean> {\n try {\n const stack = await activeSqlStack();\n if (stack) return stack.has(name);\n SqlStackDB.getEntry(name);\n return true;\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Legacy (deprecated) global-registry support\n// ---------------------------------------------------------------------------\n\n// Stable DatabaseEntry identities for the legacy global registry, so the\n// entry-keyed transaction store works identically on both paths. Keyed by\n// name AND database object so re-registration under a name yields a fresh\n// identity (matching the fresh underlying connection).\nconst legacyEntries = new Map<string, { db: Database; entry: DatabaseEntry }>();\n\n// One shared legacy pseudo-stack so legacy entries carry a stack identity for\n// diagnostics. It is intentionally NOT usable as a real stack.\nlet legacyStack: SqlStack | undefined;\n\n/** @internal Resolve a legacy global-registry database as a DatabaseEntry. */\nexport function legacyEntry(dbName?: string): DatabaseEntry {\n const { name, db } = SqlStackDB.getEntry(dbName);\n const cached = legacyEntries.get(name);\n if (cached && cached.db === db) return cached.entry;\n legacyStack ??= new SqlStack();\n const entry: DatabaseEntry = { name, db, owned: false, stack: legacyStack };\n legacyEntries.set(name, { db, entry });\n return entry;\n}\n"]}
package/dist/cjs/sql.d.ts CHANGED
@@ -1,11 +1,30 @@
1
+ import type { Dialect } from './registry';
1
2
  export declare class SqlFragment {
2
3
  readonly strings: readonly string[];
3
4
  readonly values: readonly unknown[];
4
5
  constructor(strings: readonly string[], values: readonly unknown[]);
6
+ /**
7
+ * Compile to SQL with `?` placeholders and the matching parameter list.
8
+ *
9
+ * @throws {Error} When a binder macro (`:insert`, `:update`, `:filter`,
10
+ * `:batch_insert`) receives invalid input. `run(...)` wraps this in
11
+ * DatabaseError with the original error in `.cause`.
12
+ */
5
13
  toSQL(): {
6
14
  sql: string;
7
15
  params: unknown[];
8
16
  };
9
17
  }
18
+ /** @internal True for a SqlFragment from this or any other sqlstack copy. */
19
+ export declare function isSqlFragment(value: unknown): value is SqlFragment;
20
+ /**
21
+ * @internal Compile a fragment for a dialect: `$1, $2, ...` for Postgres,
22
+ * `?` for SQLite and MySQL. Throws plain Error on invalid macro input
23
+ * (callers in run() wrap it).
24
+ */
25
+ export declare function compileFragment(fragment: SqlFragment, dialect: Dialect): {
26
+ sql: string;
27
+ params: unknown[];
28
+ };
10
29
  export declare function sql(strings: TemplateStringsArray, ...values: unknown[]): SqlFragment;
11
30
  //# sourceMappingURL=sql.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAaA,qBAAa,WAAW;aAEJ,OAAO,EAAE,SAAS,MAAM,EAAE;aAC1B,MAAM,EAAE,SAAS,OAAO,EAAE;gBAD1B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,EAAE,SAAS,OAAO,EAAE;IAG5C,KAAK,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,EAAE,CAAA;KAAE;CA8B5C;AAwDD,wBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAEpF"}
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAwB1C,qBAAa,WAAW;aAEJ,OAAO,EAAE,SAAS,MAAM,EAAE;aAC1B,MAAM,EAAE,SAAS,OAAO,EAAE;gBAD1B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,MAAM,EAAE,SAAS,OAAO,EAAE;IAG5C;;;;;;OAMG;IACH,KAAK,IAAI;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,EAAE,CAAA;KAAE;CAG5C;AAID,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAOlE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,EAAE,CAAA;CAAE,CAI3G;AA0FD,wBAAgB,GAAG,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAEpF"}
package/dist/cjs/sql.js CHANGED
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SqlFragment = void 0;
4
+ exports.isSqlFragment = isSqlFragment;
5
+ exports.compileFragment = compileFragment;
4
6
  exports.sql = sql;
5
7
  /**
6
8
  * Tagged template literal for SQL queries with `?` placeholders.
@@ -11,45 +13,82 @@ exports.sql = sql;
11
13
  * sql`UPDATE users SET :update(${data}) WHERE id = ${id}`
12
14
  * sql`SELECT * FROM users WHERE :filter(${criteria})`
13
15
  * sql`INSERT INTO users :batch_insert(${rows})`
16
+ *
17
+ * Execute a fragment with `run(db, fragment)` (or `run(fragment)` inside a
18
+ * @Query method): run binds it for the target dialect (`?` for SQLite/MySQL,
19
+ * `$1..` for Postgres) and wraps failures in DatabaseError.
14
20
  */
15
21
  const MACRO_OPEN = /:(insert|update|filter|batch_insert)\s*\(\s*$/i;
16
22
  const MACRO_CLOSE = /^\s*\)/;
23
+ // Cross-copy identity for fragments: duplicated module instances (npm link,
24
+ // dual ESM/CJS loads) each define their own SqlFragment class, so `instanceof`
25
+ // alone would misclassify a fragment built by another copy.
26
+ const FRAGMENT_BRAND = Symbol.for('noego.sqlstack.SqlFragment');
17
27
  class SqlFragment {
18
28
  constructor(strings, values) {
19
29
  this.strings = strings;
20
30
  this.values = values;
21
31
  }
32
+ /**
33
+ * Compile to SQL with `?` placeholders and the matching parameter list.
34
+ *
35
+ * @throws {Error} When a binder macro (`:insert`, `:update`, `:filter`,
36
+ * `:batch_insert`) receives invalid input. `run(...)` wraps this in
37
+ * DatabaseError with the original error in `.cause`.
38
+ */
22
39
  toSQL() {
23
- const segments = [...this.strings];
24
- const sqlParts = [];
25
- const params = [];
26
- for (let i = 0; i < segments.length; i++) {
27
- if (i < this.values.length) {
28
- const openMatch = segments[i].match(MACRO_OPEN);
29
- const closeMatch = segments[i + 1]?.match(MACRO_CLOSE);
30
- if (openMatch && closeMatch) {
31
- // Binder macro: trim the macro syntax and expand
32
- sqlParts.push(segments[i].slice(0, -openMatch[0].length));
33
- segments[i + 1] = segments[i + 1].slice(closeMatch[0].length);
34
- const { text, params: expanded } = expandMacro(openMatch[1].toLowerCase(), this.values[i]);
35
- sqlParts.push(text);
36
- params.push(...expanded);
37
- }
38
- else {
39
- sqlParts.push(segments[i]);
40
- sqlParts.push('?');
41
- params.push(this.values[i]);
42
- }
40
+ return compileParts(this.strings, this.values, () => '?');
41
+ }
42
+ }
43
+ exports.SqlFragment = SqlFragment;
44
+ Object.defineProperty(SqlFragment.prototype, FRAGMENT_BRAND, { value: true });
45
+ /** @internal True for a SqlFragment from this or any other sqlstack copy. */
46
+ function isSqlFragment(value) {
47
+ if (value instanceof SqlFragment)
48
+ return true;
49
+ return (typeof value === 'object' &&
50
+ value !== null &&
51
+ value[FRAGMENT_BRAND] === true);
52
+ }
53
+ /**
54
+ * @internal Compile a fragment for a dialect: `$1, $2, ...` for Postgres,
55
+ * `?` for SQLite and MySQL. Throws plain Error on invalid macro input
56
+ * (callers in run() wrap it).
57
+ */
58
+ function compileFragment(fragment, dialect) {
59
+ let next = 0;
60
+ const placeholder = dialect === 'postgres' ? () => `$${++next}` : () => '?';
61
+ return compileParts(fragment.strings, fragment.values, placeholder);
62
+ }
63
+ function compileParts(strings, values, placeholder) {
64
+ const segments = [...strings];
65
+ const sqlParts = [];
66
+ const params = [];
67
+ for (let i = 0; i < segments.length; i++) {
68
+ if (i < values.length) {
69
+ const openMatch = segments[i].match(MACRO_OPEN);
70
+ const closeMatch = segments[i + 1]?.match(MACRO_CLOSE);
71
+ if (openMatch && closeMatch) {
72
+ // Binder macro: trim the macro syntax and expand
73
+ sqlParts.push(segments[i].slice(0, -openMatch[0].length));
74
+ segments[i + 1] = segments[i + 1].slice(closeMatch[0].length);
75
+ const { text, params: expanded } = expandMacro(openMatch[1].toLowerCase(), values[i], placeholder);
76
+ sqlParts.push(text);
77
+ params.push(...expanded);
43
78
  }
44
79
  else {
45
80
  sqlParts.push(segments[i]);
81
+ sqlParts.push(placeholder());
82
+ params.push(values[i]);
46
83
  }
47
84
  }
48
- return { sql: sqlParts.join(''), params };
85
+ else {
86
+ sqlParts.push(segments[i]);
87
+ }
49
88
  }
89
+ return { sql: sqlParts.join(''), params };
50
90
  }
51
- exports.SqlFragment = SqlFragment;
52
- function expandMacro(type, value) {
91
+ function expandMacro(type, value, placeholder) {
53
92
  switch (type) {
54
93
  case 'insert': {
55
94
  assertPlainObject(value, ':insert()');
@@ -58,7 +97,7 @@ function expandMacro(type, value) {
58
97
  if (keys.length === 0)
59
98
  throw new Error(':insert() requires at least one column');
60
99
  const cols = keys.join(', ');
61
- const placeholders = keys.map(() => '?').join(', ');
100
+ const placeholders = keys.map(() => placeholder()).join(', ');
62
101
  return { text: `(${cols}) VALUES (${placeholders})`, params: keys.map(k => obj[k]) };
63
102
  }
64
103
  case 'update': {
@@ -67,7 +106,7 @@ function expandMacro(type, value) {
67
106
  if (entries.length === 0)
68
107
  throw new Error(':update() requires at least one defined column');
69
108
  return {
70
- text: entries.map(([k]) => `${k} = ?`).join(', '),
109
+ text: entries.map(([k]) => `${k} = ${placeholder()}`).join(', '),
71
110
  params: entries.map(([, v]) => v),
72
111
  };
73
112
  }
@@ -77,7 +116,7 @@ function expandMacro(type, value) {
77
116
  if (entries.length === 0)
78
117
  throw new Error(':filter() requires at least one defined condition');
79
118
  return {
80
- text: entries.map(([k]) => `${k} = ?`).join(' AND '),
119
+ text: entries.map(([k]) => `${k} = ${placeholder()}`).join(' AND '),
81
120
  params: entries.map(([, v]) => v),
82
121
  };
83
122
  }
@@ -89,8 +128,7 @@ function expandMacro(type, value) {
89
128
  if (keys.length === 0)
90
129
  throw new Error(':batch_insert() requires at least one column');
91
130
  const cols = keys.join(', ');
92
- const rowPlaceholder = `(${keys.map(() => '?').join(', ')})`;
93
- const allPlaceholders = value.map(() => rowPlaceholder).join(', ');
131
+ const allPlaceholders = value.map(() => `(${keys.map(() => placeholder()).join(', ')})`).join(', ');
94
132
  return {
95
133
  text: `(${cols}) VALUES ${allPlaceholders}`,
96
134
  params: value.flatMap(row => keys.map(k => row[k])),
@@ -1 +1 @@
1
- {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tagged template literal for SQL queries with `?` placeholders.\n *\n * Usage:\n * sql`SELECT * FROM users WHERE id = ${userId} AND status = ${status}`\n * sql`INSERT INTO users :insert(${data})`\n * sql`UPDATE users SET :update(${data}) WHERE id = ${id}`\n * sql`SELECT * FROM users WHERE :filter(${criteria})`\n * sql`INSERT INTO users :batch_insert(${rows})`\n */\nconst MACRO_OPEN = /:(insert|update|filter|batch_insert)\\s*\\(\\s*$/i;\nconst MACRO_CLOSE = /^\\s*\\)/;\n\nexport class SqlFragment {\n constructor(\n public readonly strings: readonly string[],\n public readonly values: readonly unknown[],\n ) {}\n\n toSQL(): { sql: string; params: unknown[] } {\n const segments = [...this.strings];\n const sqlParts: string[] = [];\n const params: unknown[] = [];\n\n for (let i = 0; i < segments.length; i++) {\n if (i < this.values.length) {\n const openMatch = segments[i].match(MACRO_OPEN);\n const closeMatch = segments[i + 1]?.match(MACRO_CLOSE);\n\n if (openMatch && closeMatch) {\n // Binder macro: trim the macro syntax and expand\n sqlParts.push(segments[i].slice(0, -openMatch[0].length));\n segments[i + 1] = segments[i + 1].slice(closeMatch[0].length);\n\n const { text, params: expanded } = expandMacro(openMatch[1].toLowerCase(), this.values[i]);\n sqlParts.push(text);\n params.push(...expanded);\n } else {\n sqlParts.push(segments[i]);\n sqlParts.push('?');\n params.push(this.values[i]);\n }\n } else {\n sqlParts.push(segments[i]);\n }\n }\n\n return { sql: sqlParts.join(''), params };\n }\n}\n\nfunction expandMacro(type: string, value: unknown): { text: string; params: unknown[] } {\n switch (type) {\n case 'insert': {\n assertPlainObject(value, ':insert()');\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj);\n if (keys.length === 0) throw new Error(':insert() requires at least one column');\n const cols = keys.join(', ');\n const placeholders = keys.map(() => '?').join(', ');\n return { text: `(${cols}) VALUES (${placeholders})`, params: keys.map(k => obj[k]) };\n }\n case 'update': {\n assertPlainObject(value, ':update()');\n const entries = Object.entries(value as Record<string, unknown>).filter(([, v]) => v !== undefined);\n if (entries.length === 0) throw new Error(':update() requires at least one defined column');\n return {\n text: entries.map(([k]) => `${k} = ?`).join(', '),\n params: entries.map(([, v]) => v),\n };\n }\n case 'filter': {\n assertPlainObject(value, ':filter()');\n const entries = Object.entries(value as Record<string, unknown>).filter(([, v]) => v !== undefined);\n if (entries.length === 0) throw new Error(':filter() requires at least one defined condition');\n return {\n text: entries.map(([k]) => `${k} = ?`).join(' AND '),\n params: entries.map(([, v]) => v),\n };\n }\n case 'batch_insert': {\n if (!Array.isArray(value) || value.length === 0) {\n throw new Error(':batch_insert() requires a non-empty array of objects');\n }\n const keys = Object.keys(value[0]);\n if (keys.length === 0) throw new Error(':batch_insert() requires at least one column');\n const cols = keys.join(', ');\n const rowPlaceholder = `(${keys.map(() => '?').join(', ')})`;\n const allPlaceholders = value.map(() => rowPlaceholder).join(', ');\n return {\n text: `(${cols}) VALUES ${allPlaceholders}`,\n params: value.flatMap(row => keys.map(k => (row as Record<string, unknown>)[k])),\n };\n }\n default:\n throw new Error(`Unknown binder macro :${type}()`);\n }\n}\n\nfunction assertPlainObject(value: unknown, label: string): asserts value is Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} in sql\\`\\` template requires a plain object`);\n }\n}\n\nexport function sql(strings: TemplateStringsArray, ...values: unknown[]): SqlFragment {\n return new SqlFragment(strings, values);\n}\n"]}
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Dialect } from './registry';\n\n/**\n * Tagged template literal for SQL queries with `?` placeholders.\n *\n * Usage:\n * sql`SELECT * FROM users WHERE id = ${userId} AND status = ${status}`\n * sql`INSERT INTO users :insert(${data})`\n * sql`UPDATE users SET :update(${data}) WHERE id = ${id}`\n * sql`SELECT * FROM users WHERE :filter(${criteria})`\n * sql`INSERT INTO users :batch_insert(${rows})`\n *\n * Execute a fragment with `run(db, fragment)` (or `run(fragment)` inside a\n * @Query method): run binds it for the target dialect (`?` for SQLite/MySQL,\n * `$1..` for Postgres) and wraps failures in DatabaseError.\n */\nconst MACRO_OPEN = /:(insert|update|filter|batch_insert)\\s*\\(\\s*$/i;\nconst MACRO_CLOSE = /^\\s*\\)/;\n\n// Cross-copy identity for fragments: duplicated module instances (npm link,\n// dual ESM/CJS loads) each define their own SqlFragment class, so `instanceof`\n// alone would misclassify a fragment built by another copy.\nconst FRAGMENT_BRAND = Symbol.for('noego.sqlstack.SqlFragment');\n\nexport class SqlFragment {\n constructor(\n public readonly strings: readonly string[],\n public readonly values: readonly unknown[],\n ) {}\n\n /**\n * Compile to SQL with `?` placeholders and the matching parameter list.\n *\n * @throws {Error} When a binder macro (`:insert`, `:update`, `:filter`,\n * `:batch_insert`) receives invalid input. `run(...)` wraps this in\n * DatabaseError with the original error in `.cause`.\n */\n toSQL(): { sql: string; params: unknown[] } {\n return compileParts(this.strings, this.values, () => '?');\n }\n}\n\nObject.defineProperty(SqlFragment.prototype, FRAGMENT_BRAND, { value: true });\n\n/** @internal True for a SqlFragment from this or any other sqlstack copy. */\nexport function isSqlFragment(value: unknown): value is SqlFragment {\n if (value instanceof SqlFragment) return true;\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { [FRAGMENT_BRAND]?: unknown })[FRAGMENT_BRAND] === true\n );\n}\n\n/**\n * @internal Compile a fragment for a dialect: `$1, $2, ...` for Postgres,\n * `?` for SQLite and MySQL. Throws plain Error on invalid macro input\n * (callers in run() wrap it).\n */\nexport function compileFragment(fragment: SqlFragment, dialect: Dialect): { sql: string; params: unknown[] } {\n let next = 0;\n const placeholder = dialect === 'postgres' ? () => `$${++next}` : () => '?';\n return compileParts(fragment.strings, fragment.values, placeholder);\n}\n\nfunction compileParts(\n strings: readonly string[],\n values: readonly unknown[],\n placeholder: () => string,\n): { sql: string; params: unknown[] } {\n const segments = [...strings];\n const sqlParts: string[] = [];\n const params: unknown[] = [];\n\n for (let i = 0; i < segments.length; i++) {\n if (i < values.length) {\n const openMatch = segments[i].match(MACRO_OPEN);\n const closeMatch = segments[i + 1]?.match(MACRO_CLOSE);\n\n if (openMatch && closeMatch) {\n // Binder macro: trim the macro syntax and expand\n sqlParts.push(segments[i].slice(0, -openMatch[0].length));\n segments[i + 1] = segments[i + 1].slice(closeMatch[0].length);\n\n const { text, params: expanded } = expandMacro(openMatch[1].toLowerCase(), values[i], placeholder);\n sqlParts.push(text);\n params.push(...expanded);\n } else {\n sqlParts.push(segments[i]);\n sqlParts.push(placeholder());\n params.push(values[i]);\n }\n } else {\n sqlParts.push(segments[i]);\n }\n }\n\n return { sql: sqlParts.join(''), params };\n}\n\nfunction expandMacro(type: string, value: unknown, placeholder: () => string): { text: string; params: unknown[] } {\n switch (type) {\n case 'insert': {\n assertPlainObject(value, ':insert()');\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj);\n if (keys.length === 0) throw new Error(':insert() requires at least one column');\n const cols = keys.join(', ');\n const placeholders = keys.map(() => placeholder()).join(', ');\n return { text: `(${cols}) VALUES (${placeholders})`, params: keys.map(k => obj[k]) };\n }\n case 'update': {\n assertPlainObject(value, ':update()');\n const entries = Object.entries(value as Record<string, unknown>).filter(([, v]) => v !== undefined);\n if (entries.length === 0) throw new Error(':update() requires at least one defined column');\n return {\n text: entries.map(([k]) => `${k} = ${placeholder()}`).join(', '),\n params: entries.map(([, v]) => v),\n };\n }\n case 'filter': {\n assertPlainObject(value, ':filter()');\n const entries = Object.entries(value as Record<string, unknown>).filter(([, v]) => v !== undefined);\n if (entries.length === 0) throw new Error(':filter() requires at least one defined condition');\n return {\n text: entries.map(([k]) => `${k} = ${placeholder()}`).join(' AND '),\n params: entries.map(([, v]) => v),\n };\n }\n case 'batch_insert': {\n if (!Array.isArray(value) || value.length === 0) {\n throw new Error(':batch_insert() requires a non-empty array of objects');\n }\n const keys = Object.keys(value[0]);\n if (keys.length === 0) throw new Error(':batch_insert() requires at least one column');\n const cols = keys.join(', ');\n const allPlaceholders = value.map(() => `(${keys.map(() => placeholder()).join(', ')})`).join(', ');\n return {\n text: `(${cols}) VALUES ${allPlaceholders}`,\n params: value.flatMap(row => keys.map(k => (row as Record<string, unknown>)[k])),\n };\n }\n default:\n throw new Error(`Unknown binder macro :${type}()`);\n }\n}\n\nfunction assertPlainObject(value: unknown, label: string): asserts value is Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} in sql\\`\\` template requires a plain object`);\n }\n}\n\nexport function sql(strings: TemplateStringsArray, ...values: unknown[]): SqlFragment {\n return new SqlFragment(strings, values);\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { Database } from './registry';
2
2
  import type { SqlResolver } from './core/resolver';
3
+ import { type SqlResources } from './core/resources';
3
4
  import { FamilyRuntime } from './family';
4
5
  import type { FamilyConfig } from './family';
5
6
  /**
@@ -50,6 +51,19 @@ export declare class SqlStack {
50
51
  static useResolver(resolver: SqlResolver): void;
51
52
  /** @deprecated See static useResolver. */
52
53
  static clearResolver(): void;
54
+ /**
55
+ * Install the packaged SQL resources for this process: a path-keyed map
56
+ * `{ 'server/.../<method>.sql': '<sql>' }` (an `import.meta.glob` raw
57
+ * import, or a build-generated module). Bare `@Query()` methods resolve
58
+ * their guessed module directory + `<method>.sql` against it by path
59
+ * suffix, so the map works unchanged across an asar, a Worker module tree
60
+ * and a plain checkout. Replaces any previously installed map.
61
+ */
62
+ static useResources(resources: SqlResources): void;
63
+ /** Remove the packaged SQL resources (tests). */
64
+ static clearResources(): void;
65
+ /** The installed packaged SQL resources, if any. */
66
+ static resources(): SqlResources | undefined;
53
67
  constructor(config?: SqlStackConfig);
54
68
  register(name: string, db: Database, options?: {
55
69
  owned?: boolean;
@@ -97,5 +111,7 @@ export declare class SqlStack {
97
111
  * collected and reported with database identity rather than swallowed.
98
112
  */
99
113
  close(): Promise<void>;
114
+ /** Native IoC resource hook; manually calling close remains supported. */
115
+ dispose(): Promise<void>;
100
116
  }
101
117
  //# sourceMappingURL=stack.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/stack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AASnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,YAAY,EAAoC,MAAM,UAAU,CAAC;AAG/E;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;CAC1B;AAED,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR;IACE,EAAE,EAAE,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,CAAC;IAChC,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEN,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IACjD,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED;;;;;;GAMG;AACH,qBAAa,QAAQ;;IACnB;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAI/C,0CAA0C;IAC1C,MAAM,CAAC,aAAa,IAAI,IAAI;gBAUhB,MAAM,CAAC,EAAE,cAAc;IAenC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAW5F,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa;IAiBtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ;IAIjC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;;OAGG;IACH,cAAc,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI;IASvE,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC;IAYlD;;;;;;OAMG;IACG,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAwBrF;;;;OAIG;IACG,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAgCzD;;;;;;OAMG;IACH,WAAW,CACT,QAAQ,EAAE,WAAW,EACrB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAA;KAAE,GAC1E,IAAI;IAaP,QAAQ,IAAI,WAAW,GAAG,SAAS;IAInC,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAwC7B"}
1
+ {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/stack.ts"],"names":[],"mappings":"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"}
package/dist/cjs/stack.js CHANGED
@@ -43,11 +43,12 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
43
43
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
44
44
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
45
45
  };
46
- var _SqlStack_instances, _SqlStack_entries, _SqlStack_families, _SqlStack_defaultName, _SqlStack_resolver, _SqlStack_closed, _SqlStack_assertOpen, _SqlStack_registeredNames;
46
+ var _SqlStack_instances, _SqlStack_entries, _SqlStack_families, _SqlStack_defaultName, _SqlStack_resolver, _SqlStack_closed, _SqlStack_closing, _SqlStack_assertOpen, _SqlStack_registeredNames;
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.SqlStack = void 0;
49
49
  const resolver_1 = require("./core/resolver");
50
50
  const errors_1 = require("./core/errors");
51
+ const resources_1 = require("./core/resources");
51
52
  const family_1 = require("./family");
52
53
  const familyBinding_1 = require("./familyBinding");
53
54
  /**
@@ -71,6 +72,25 @@ class SqlStack {
71
72
  static clearResolver() {
72
73
  (0, resolver_1.clearGlobalResolver)();
73
74
  }
75
+ /**
76
+ * Install the packaged SQL resources for this process: a path-keyed map
77
+ * `{ 'server/.../<method>.sql': '<sql>' }` (an `import.meta.glob` raw
78
+ * import, or a build-generated module). Bare `@Query()` methods resolve
79
+ * their guessed module directory + `<method>.sql` against it by path
80
+ * suffix, so the map works unchanged across an asar, a Worker module tree
81
+ * and a plain checkout. Replaces any previously installed map.
82
+ */
83
+ static useResources(resources) {
84
+ (0, resources_1.setResources)(resources);
85
+ }
86
+ /** Remove the packaged SQL resources (tests). */
87
+ static clearResources() {
88
+ (0, resources_1.setResources)(undefined);
89
+ }
90
+ /** The installed packaged SQL resources, if any. */
91
+ static resources() {
92
+ return (0, resources_1.getResources)();
93
+ }
74
94
  constructor(config) {
75
95
  _SqlStack_instances.add(this);
76
96
  _SqlStack_entries.set(this, new Map());
@@ -78,6 +98,7 @@ class SqlStack {
78
98
  _SqlStack_defaultName.set(this, void 0);
79
99
  _SqlStack_resolver.set(this, void 0);
80
100
  _SqlStack_closed.set(this, false);
101
+ _SqlStack_closing.set(this, void 0);
81
102
  if (config?.databases) {
82
103
  for (const [name, reg] of Object.entries(config.databases)) {
83
104
  if (typeof reg === 'object' && reg !== null && 'db' in reg) {
@@ -242,39 +263,51 @@ class SqlStack {
242
263
  * Externally supplied databases (owned: false) are not touched. Failures are
243
264
  * collected and reported with database identity rather than swallowed.
244
265
  */
245
- async close() {
246
- if (__classPrivateFieldGet(this, _SqlStack_closed, "f"))
247
- return;
266
+ close() {
267
+ if (__classPrivateFieldGet(this, _SqlStack_closing, "f"))
268
+ return __classPrivateFieldGet(this, _SqlStack_closing, "f");
248
269
  __classPrivateFieldSet(this, _SqlStack_closed, true, "f");
249
- const failures = [];
250
- for (const entry of __classPrivateFieldGet(this, _SqlStack_entries, "f").values()) {
251
- if (!entry.owned)
252
- continue;
253
- try {
254
- await entry.db.close();
255
- }
256
- catch (err) {
257
- failures.push(`"${entry.name}": ${err?.message ?? String(err)}`);
270
+ __classPrivateFieldSet(this, _SqlStack_closing, Promise.resolve().then(async () => {
271
+ const failures = [];
272
+ const errors = [];
273
+ const closed = new Set();
274
+ for (const entry of __classPrivateFieldGet(this, _SqlStack_entries, "f").values()) {
275
+ if (!entry.owned || closed.has(entry.db))
276
+ continue;
277
+ closed.add(entry.db);
278
+ try {
279
+ await entry.db.close();
280
+ }
281
+ catch (error) {
282
+ errors.push(error);
283
+ failures.push(`"${entry.name}": ${error?.message ?? String(error)}`);
284
+ }
258
285
  }
259
- }
260
- for (const fam of __classPrivateFieldGet(this, _SqlStack_families, "f").values()) {
261
- try {
262
- await fam.closeAll();
286
+ for (const fam of __classPrivateFieldGet(this, _SqlStack_families, "f").values()) {
287
+ try {
288
+ await fam.closeAll();
289
+ }
290
+ catch (error) {
291
+ errors.push(error);
292
+ failures.push(error?.message ?? String(error));
293
+ }
263
294
  }
264
- catch (err) {
265
- failures.push(err?.message ?? String(err));
295
+ __classPrivateFieldGet(this, _SqlStack_entries, "f").clear();
296
+ __classPrivateFieldGet(this, _SqlStack_families, "f").clear();
297
+ __classPrivateFieldSet(this, _SqlStack_resolver, undefined, "f");
298
+ if (failures.length) {
299
+ throw Object.assign(new errors_1.SqlStackError(`SqlStack close failed for ${failures.join(', ')}`), {
300
+ errors: Object.freeze(errors), cause: errors[0],
301
+ });
266
302
  }
267
- }
268
- __classPrivateFieldGet(this, _SqlStack_entries, "f").clear();
269
- __classPrivateFieldGet(this, _SqlStack_families, "f").clear();
270
- __classPrivateFieldSet(this, _SqlStack_resolver, undefined, "f");
271
- if (failures.length) {
272
- throw new errors_1.SqlStackError(`SqlStack close failed for ${failures.join(', ')}`);
273
- }
303
+ }), "f");
304
+ return __classPrivateFieldGet(this, _SqlStack_closing, "f");
274
305
  }
306
+ /** Native IoC resource hook; manually calling close remains supported. */
307
+ dispose() { return this.close(); }
275
308
  }
276
309
  exports.SqlStack = SqlStack;
277
- _SqlStack_entries = new WeakMap(), _SqlStack_families = new WeakMap(), _SqlStack_defaultName = new WeakMap(), _SqlStack_resolver = new WeakMap(), _SqlStack_closed = new WeakMap(), _SqlStack_instances = new WeakSet(), _SqlStack_assertOpen = function _SqlStack_assertOpen() {
310
+ _SqlStack_entries = new WeakMap(), _SqlStack_families = new WeakMap(), _SqlStack_defaultName = new WeakMap(), _SqlStack_resolver = new WeakMap(), _SqlStack_closed = new WeakMap(), _SqlStack_closing = new WeakMap(), _SqlStack_instances = new WeakSet(), _SqlStack_assertOpen = function _SqlStack_assertOpen() {
278
311
  if (__classPrivateFieldGet(this, _SqlStack_closed, "f")) {
279
312
  throw new errors_1.SqlStackError('SqlStack has been closed; its owning root was disposed.');
280
313
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/stack.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,8CAMyB;AACzB,0CAA8C;AAC9C,qCAAyC;AAEzC,mDAA+E;AAqC/E;;;;;;GAMG;AACH,MAAa,QAAQ;IACnB;;;;;OAKG;IACH,MAAM,CAAC,WAAW,CAAC,QAAqB;QACtC,IAAA,4BAAiB,EAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED,0CAA0C;IAC1C,MAAM,CAAC,aAAa;QAClB,IAAA,8BAAmB,GAAE,CAAC;IACxB,CAAC;IAQD,YAAY,MAAuB;;QANnC,4BAAW,IAAI,GAAG,EAAyB,EAAC;QAC5C,6BAAY,IAAI,GAAG,EAA8B,EAAC;QAClD,wCAAiC;QACjC,qCAAmC;QACnC,2BAAU,KAAK,EAAC;QAGd,IAAI,MAAM,EAAE,SAAS,EAAE,CAAC;YACtB,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3D,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;oBAC3D,MAAM,EAAE,GAAG,OAAO,GAAG,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5D,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,UAAU,EAAE,CAAC,CAAC;gBAChF,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAe,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,MAAM,EAAE,OAAO;YAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,MAAM,EAAE,QAAQ;YAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,EAAY,EAAE,OAAgD;QACnF,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,MAAM,KAAK,GAAkB,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACvF,uBAAA,IAAI,yBAAS,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC/B,IAAI,OAAO,EAAE,OAAO,IAAI,uBAAA,IAAI,yBAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACjD,gHAAsB,IAAI,MAAA,CAAC;YAC3B,IAAI,OAAO,EAAE,OAAO;gBAAE,uBAAA,IAAI,yBAAgB,IAAI,MAAA,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,IAAI,CAAC,uBAAA,IAAI,yBAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,sBAAa,CACrB,8CAA8C,IAAI,kBAAkB,uBAAA,IAAI,sDAAiB,MAArB,IAAI,CAAmB,EAAE,CAC9F,CAAC;QACJ,CAAC;QACD,uBAAA,IAAI,yBAAgB,IAAI,MAAA,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ,CAAC,IAAa;QACpB,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,IAAI,uBAAA,IAAI,6BAAa,CAAC;QACtC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,sBAAa,CACrB,iGAAiG,CAClG,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,uBAAA,IAAI,yBAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,sBAAa,CACrB,8CAA8C,GAAG,kBAAkB,uBAAA,IAAI,sDAAiB,MAArB,IAAI,CAAmB,EAAE,CAC7F,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,QAAQ,CAAC,IAAa;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;IAChC,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,uBAAA,IAAI,yBAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,uBAAA,IAAI,0BAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED;;;OAGG;IACH,cAAc,CAAa,IAAY,EAAE,MAAuB;QAC9D,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,IAAI,uBAAA,IAAI,yBAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,sBAAa,CAAC,IAAI,IAAI,+CAA+C,CAAC,CAAC;QACnF,CAAC;QACD,uBAAA,IAAI,0BAAU,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,sBAAa,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,CAAa,IAAY;QAC7B,MAAM,GAAG,GAAG,uBAAA,IAAI,0BAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,sBAAa,CACrB,qDAAqD,IAAI,gBACvD,CAAC,GAAG,uBAAA,IAAI,0BAAU,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAChE,EAAE,CACH,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,YAAY,CAAI,MAAc,EAAE,GAAY,EAAE,EAAoB;QACtE,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,KAAK,GAAG,IAAA,8BAAc,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAClD,MAAM,EAAE,oBAAoB,EAAE,GAAG,wDAAa,gBAAgB,GAAC,CAAC;YAChE,IAAI,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5C,MAAM,IAAI,sBAAa,CACrB,kCAAkC,MAAM,WAAW,KAAK,CAAC,KAAK,SAAS,KAAK,KAAK;oBAC/E,+EAA+E,CAClF,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAiB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAC1E,IAAI,CAAC;YACH,OAAO,MAAM,IAAA,8BAAc,EAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACzC,CAAC;gBAAS,CAAC;YACT,MAAM,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;QAC/B,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,IAAa;QAC9B,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,MAAM,GAAG,GACP,IAAI;YACJ,uBAAA,IAAI,6BAAa;YACjB,sEAAsE;YACtE,CAAC,uBAAA,IAAI,yBAAS,CAAC,IAAI,KAAK,CAAC,IAAI,uBAAA,IAAI,0BAAU,CAAC,IAAI,KAAK,CAAC;gBACpD,CAAC,CAAC,CAAC,GAAG,uBAAA,IAAI,0BAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/B,CAAC,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,uBAAA,IAAI,yBAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACrC,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAC;YACxB,MAAM,GAAG,GAAG,uBAAA,IAAI,0BAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACpC,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,KAAK,GAAG,IAAA,8BAAc,EAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACxC,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM,IAAI,sBAAa,CACrB,6BAA6B,GAAG,sCAAsC;wBACpE,6EAA6E;wBAC7E,sDAAsD,GAAG,eAAe;wBACxE,oEAAoE,CACvE,CAAC;gBACJ,CAAC;gBACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;oBACjB,KAAK,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAClD,CAAC;gBACD,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CACT,QAAqB,EACrB,OAA2E;QAE3E,uBAAA,IAAI,iDAAY,MAAhB,IAAI,CAAc,CAAC;QACnB,IAAI,QAAQ,YAAY,2BAAgB,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;YAC9E,IAAI,OAAO,EAAE,OAAO,EAAE,CAAC;gBACrB,IAAA,sCAA2B,EAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,IAAA,iCAAsB,EAAC,QAAQ,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;QACD,uBAAA,IAAI,sBAAa,QAAQ,MAAA,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,QAAQ;QACN,OAAO,uBAAA,IAAI,0BAAU,CAAC;IACxB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,uBAAA,IAAI,wBAAQ,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,uBAAA,IAAI,wBAAQ;YAAE,OAAO;QACzB,uBAAA,IAAI,oBAAW,IAAI,MAAA,CAAC;QACpB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,KAAK,IAAI,uBAAA,IAAI,yBAAS,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,KAAK,CAAC,KAAK;gBAAE,SAAS;YAC3B,IAAI,CAAC;gBACH,MAAM,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;YACzB,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,uBAAA,IAAI,0BAAU,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACH,MAAM,GAAG,CAAC,QAAQ,EAAE,CAAC;YACvB,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,uBAAA,IAAI,yBAAS,CAAC,KAAK,EAAE,CAAC;QACtB,uBAAA,IAAI,0BAAU,CAAC,KAAK,EAAE,CAAC;QACvB,uBAAA,IAAI,sBAAa,SAAS,MAAA,CAAC;QAC3B,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,IAAI,sBAAa,CAAC,6BAA6B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;CAeF;AA7PD,4BA6PC;;IAZG,IAAI,uBAAA,IAAI,wBAAQ,EAAE,CAAC;QACjB,MAAM,IAAI,sBAAa,CAAC,yDAAyD,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;IAGC,MAAM,KAAK,GAAG;QACZ,GAAG,CAAC,GAAG,uBAAA,IAAI,yBAAS,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;QACjD,GAAG,CAAC,GAAG,uBAAA,IAAI,0BAAU,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC;KAC5D,CAAC;IACF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpD,CAAC","sourcesContent":["import type { Database } from './registry';\nimport type { SqlResolver } from './core/resolver';\nimport {\n setGlobalResolver,\n clearGlobalResolver,\n ManifestResolver,\n assertManifestCoverage,\n assertManifestCoversClasses,\n} from './core/resolver';\nimport { SqlStackError } from './core/errors';\nimport { FamilyRuntime } from './family';\nimport type { FamilyConfig, FamilyMemberEntry, DatabaseLease } from './family';\nimport { currentBinding, runWithBinding, BindingFrame } from './familyBinding';\n\n/**\n * Concrete database identity inside one SqlStack instance.\n *\n * The entry OBJECT is the identity: two roots that both register a database\n * under the name \"primary\" produce two distinct DatabaseEntry instances, so\n * transaction lookup, caches, and diagnostics keyed by entry can never collide\n * across roots merely because the registration text matches.\n *\n * Dynamic database families (spec 17) extend this identity with a normalized\n * key; a static database is the no-key case.\n */\nexport interface DatabaseEntry {\n readonly name: string;\n readonly db: Database;\n /** Close() closes owned databases; externally supplied ones are left open. */\n readonly owned: boolean;\n /** The stack this entry belongs to, for diagnostics and mismatch checks. */\n readonly stack: SqlStack;\n}\n\nexport type DatabaseRegistration =\n | Database\n | {\n db: Database | (() => Database);\n /** Default false for direct Database values, true for factories. */\n owned?: boolean;\n };\n\nexport interface SqlStackConfig {\n databases?: Record<string, DatabaseRegistration>;\n /** Name of the default database. Required when more than one is registered. */\n default?: string;\n resolver?: SqlResolver;\n}\n\n/**\n * Environment-owned SQLStack runtime (spec 16 §12-13, repo spec 19 §3-5).\n *\n * One instance per owning IoC root; child scopes resolve the root's Singleton.\n * Native @Query/transaction/resolver execution goes through an instance —\n * never through the process-global SqlStackDB registry.\n */\nexport class SqlStack {\n /**\n * @deprecated Legacy v2 process-global resolver registration\n * (`SqlStack.useResolver(...)`). Forwards to the deprecated global state,\n * which is only consulted when no IoC environment is active. Use the\n * per-instance `useResolver` / SqlStackConfig.resolver instead.\n */\n static useResolver(resolver: SqlResolver): void {\n setGlobalResolver(resolver);\n }\n\n /** @deprecated See static useResolver. */\n static clearResolver(): void {\n clearGlobalResolver();\n }\n\n #entries = new Map<string, DatabaseEntry>();\n #families = new Map<string, FamilyRuntime<any>>();\n #defaultName: string | undefined;\n #resolver: SqlResolver | undefined;\n #closed = false;\n\n constructor(config?: SqlStackConfig) {\n if (config?.databases) {\n for (const [name, reg] of Object.entries(config.databases)) {\n if (typeof reg === 'object' && reg !== null && 'db' in reg) {\n const db = typeof reg.db === 'function' ? reg.db() : reg.db;\n this.register(name, db, { owned: reg.owned ?? typeof reg.db === 'function' });\n } else {\n this.register(name, reg as Database);\n }\n }\n }\n if (config?.default) this.setDefault(config.default);\n if (config?.resolver) this.useResolver(config.resolver);\n }\n\n register(name: string, db: Database, options?: { owned?: boolean; default?: boolean }): this {\n this.#assertOpen();\n const entry: DatabaseEntry = { name, db, owned: options?.owned ?? false, stack: this };\n this.#entries.set(name, entry);\n if (options?.default || this.#entries.size === 1) {\n this.#defaultName ??= name;\n if (options?.default) this.#defaultName = name;\n }\n return this;\n }\n\n setDefault(name: string): this {\n this.#assertOpen();\n if (!this.#entries.has(name)) {\n throw new SqlStackError(\n `SqlStack has no database registered under \"${name}\". Registered: ${this.#registeredNames()}`\n );\n }\n this.#defaultName = name;\n return this;\n }\n\n getEntry(name?: string): DatabaseEntry {\n this.#assertOpen();\n const key = name ?? this.#defaultName;\n if (!key) {\n throw new SqlStackError(\n 'SqlStack has no default database. Register one with { default: true } or call setDefault(name).'\n );\n }\n const entry = this.#entries.get(key);\n if (!entry) {\n throw new SqlStackError(\n `SqlStack has no database registered under \"${key}\". Registered: ${this.#registeredNames()}`\n );\n }\n return entry;\n }\n\n database(name?: string): Database {\n return this.getEntry(name).db;\n }\n\n has(name: string): boolean {\n return this.#entries.has(name) || this.#families.has(name);\n }\n\n /**\n * Register a dynamic database family (spec 17): one registration whose\n * concrete member is selected per execution flow via withDatabase(...).\n */\n registerFamily<K = string>(name: string, config: FamilyConfig<K>): this {\n this.#assertOpen();\n if (this.#entries.has(name)) {\n throw new SqlStackError(`\"${name}\" is already registered as a static database.`);\n }\n this.#families.set(name, new FamilyRuntime(this, name, config));\n return this;\n }\n\n family<K = string>(name: string): FamilyRuntime<K> {\n const fam = this.#families.get(name);\n if (!fam) {\n throw new SqlStackError(\n `SqlStack has no database family registered under \"${name}\". Families: ${\n [...this.#families.keys()].map((n) => `\"${n}\"`).join(', ') || '(none)'\n }`\n );\n }\n return fam;\n }\n\n /**\n * Bind a family registration to a concrete member for the duration of fn\n * (spec 17 §10). The binding is flow-local to this SqlStack; the member's\n * connection is leased lazily on first database resolution and released\n * when fn settles. Rebinding a family to a different key while it has an\n * active transaction fails deterministically (spec 17 §29).\n */\n async withDatabase<T>(family: string, key: unknown, fn: () => Promise<T>): Promise<T> {\n this.#assertOpen();\n const fam = this.family(family);\n const { keyId } = fam.normalize(key);\n\n const outer = currentBinding(this, family);\n if (outer && outer.keyId !== keyId && outer.lease) {\n const { getActiveTransaction } = await import('./transactions');\n if (getActiveTransaction(outer.lease.entry)) {\n throw new SqlStackError(\n `Cannot rebind database family \"${family}\" from \"${outer.keyId}\" to \"${keyId}\": ` +\n 'a transaction is active for the current member. Finish the transaction first.'\n );\n }\n }\n\n const frame: BindingFrame = { stack: this, family, keyInput: key, keyId };\n try {\n return await runWithBinding(frame, fn);\n } finally {\n await frame.lease?.release();\n }\n }\n\n /**\n * Async database resolution for query/transaction execution. Static\n * registrations resolve directly; family registrations resolve through the\n * active flow-local binding, opening/leasing the member on first use.\n */\n async resolveEntry(name?: string): Promise<DatabaseEntry> {\n this.#assertOpen();\n const key =\n name ??\n this.#defaultName ??\n // A stack whose only registration is one family treats it as default.\n (this.#entries.size === 0 && this.#families.size === 1\n ? [...this.#families.keys()][0]\n : undefined);\n if (key !== undefined) {\n const entry = this.#entries.get(key);\n if (entry) return entry;\n const fam = this.#families.get(key);\n if (fam) {\n const frame = currentBinding(this, key);\n if (!frame) {\n throw new SqlStackError(\n `SQLStack database family \"${key}\" requires a concrete database key. ` +\n 'No active binding exists for this execution. Establish the database at the ' +\n `orchestration boundary with sqlStack.withDatabase(\"${key}\", key, ...) ` +\n 'or acquire a member explicitly via sqlStack.family(...).with(...).'\n );\n }\n if (!frame.lease) {\n frame.lease = await fam.acquire(frame.keyInput);\n }\n return frame.lease.entry;\n }\n }\n return this.getEntry(name);\n }\n\n /**\n * Set this stack's SQL resolver. When `options.classes` supplies the\n * repository catalog, manifest coverage is validated from those classes'\n * immutable metadata (environment-local, unpollutable by unrelated\n * imports). Without a catalog, coverage falls back to the deprecated\n * process-global decorated list.\n */\n useResolver(\n resolver: SqlResolver,\n options?: { classes?: ReadonlyArray<abstract new (...args: any[]) => any> }\n ): this {\n this.#assertOpen();\n if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {\n if (options?.classes) {\n assertManifestCoversClasses(resolver, options.classes);\n } else {\n assertManifestCoverage(resolver);\n }\n }\n this.#resolver = resolver;\n return this;\n }\n\n resolver(): SqlResolver | undefined {\n return this.#resolver;\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n /**\n * Close owned database adapters exactly once and release runtime resources.\n * Externally supplied databases (owned: false) are not touched. Failures are\n * collected and reported with database identity rather than swallowed.\n */\n async close(): Promise<void> {\n if (this.#closed) return;\n this.#closed = true;\n const failures: string[] = [];\n for (const entry of this.#entries.values()) {\n if (!entry.owned) continue;\n try {\n await entry.db.close();\n } catch (err: any) {\n failures.push(`\"${entry.name}\": ${err?.message ?? String(err)}`);\n }\n }\n for (const fam of this.#families.values()) {\n try {\n await fam.closeAll();\n } catch (err: any) {\n failures.push(err?.message ?? String(err));\n }\n }\n this.#entries.clear();\n this.#families.clear();\n this.#resolver = undefined;\n if (failures.length) {\n throw new SqlStackError(`SqlStack close failed for ${failures.join(', ')}`);\n }\n }\n\n #assertOpen(): void {\n if (this.#closed) {\n throw new SqlStackError('SqlStack has been closed; its owning root was disposed.');\n }\n }\n\n #registeredNames(): string {\n const names = [\n ...[...this.#entries.keys()].map((n) => `\"${n}\"`),\n ...[...this.#families.keys()].map((n) => `\"${n}\" (family)`),\n ];\n return names.length ? names.join(', ') : '(none)';\n }\n}\n"]}
1
+ {"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/stack.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Database } from './registry';\nimport type { SqlResolver } from './core/resolver';\nimport {\n setGlobalResolver,\n clearGlobalResolver,\n ManifestResolver,\n assertManifestCoverage,\n assertManifestCoversClasses,\n} from './core/resolver';\nimport { SqlStackError } from './core/errors';\nimport { setResources, getResources, type SqlResources } from './core/resources';\nimport { FamilyRuntime } from './family';\nimport type { FamilyConfig, FamilyMemberEntry, DatabaseLease } from './family';\nimport { currentBinding, runWithBinding, BindingFrame } from './familyBinding';\n\n/**\n * Concrete database identity inside one SqlStack instance.\n *\n * The entry OBJECT is the identity: two roots that both register a database\n * under the name \"primary\" produce two distinct DatabaseEntry instances, so\n * transaction lookup, caches, and diagnostics keyed by entry can never collide\n * across roots merely because the registration text matches.\n *\n * Dynamic database families (spec 17) extend this identity with a normalized\n * key; a static database is the no-key case.\n */\nexport interface DatabaseEntry {\n readonly name: string;\n readonly db: Database;\n /** Close() closes owned databases; externally supplied ones are left open. */\n readonly owned: boolean;\n /** The stack this entry belongs to, for diagnostics and mismatch checks. */\n readonly stack: SqlStack;\n}\n\nexport type DatabaseRegistration =\n | Database\n | {\n db: Database | (() => Database);\n /** Default false for direct Database values, true for factories. */\n owned?: boolean;\n };\n\nexport interface SqlStackConfig {\n databases?: Record<string, DatabaseRegistration>;\n /** Name of the default database. Required when more than one is registered. */\n default?: string;\n resolver?: SqlResolver;\n}\n\n/**\n * Environment-owned SQLStack runtime (spec 16 §12-13, repo spec 19 §3-5).\n *\n * One instance per owning IoC root; child scopes resolve the root's Singleton.\n * Native @Query/transaction/resolver execution goes through an instance —\n * never through the process-global SqlStackDB registry.\n */\nexport class SqlStack {\n /**\n * @deprecated Legacy v2 process-global resolver registration\n * (`SqlStack.useResolver(...)`). Forwards to the deprecated global state,\n * which is only consulted when no IoC environment is active. Use the\n * per-instance `useResolver` / SqlStackConfig.resolver instead.\n */\n static useResolver(resolver: SqlResolver): void {\n setGlobalResolver(resolver);\n }\n\n /** @deprecated See static useResolver. */\n static clearResolver(): void {\n clearGlobalResolver();\n }\n\n /**\n * Install the packaged SQL resources for this process: a path-keyed map\n * `{ 'server/.../<method>.sql': '<sql>' }` (an `import.meta.glob` raw\n * import, or a build-generated module). Bare `@Query()` methods resolve\n * their guessed module directory + `<method>.sql` against it by path\n * suffix, so the map works unchanged across an asar, a Worker module tree\n * and a plain checkout. Replaces any previously installed map.\n */\n static useResources(resources: SqlResources): void {\n setResources(resources);\n }\n\n /** Remove the packaged SQL resources (tests). */\n static clearResources(): void {\n setResources(undefined);\n }\n\n /** The installed packaged SQL resources, if any. */\n static resources(): SqlResources | undefined {\n return getResources();\n }\n\n #entries = new Map<string, DatabaseEntry>();\n #families = new Map<string, FamilyRuntime<any>>();\n #defaultName: string | undefined;\n #resolver: SqlResolver | undefined;\n #closed = false;\n #closing: Promise<void> | undefined;\n\n constructor(config?: SqlStackConfig) {\n if (config?.databases) {\n for (const [name, reg] of Object.entries(config.databases)) {\n if (typeof reg === 'object' && reg !== null && 'db' in reg) {\n const db = typeof reg.db === 'function' ? reg.db() : reg.db;\n this.register(name, db, { owned: reg.owned ?? typeof reg.db === 'function' });\n } else {\n this.register(name, reg as Database);\n }\n }\n }\n if (config?.default) this.setDefault(config.default);\n if (config?.resolver) this.useResolver(config.resolver);\n }\n\n register(name: string, db: Database, options?: { owned?: boolean; default?: boolean }): this {\n this.#assertOpen();\n const entry: DatabaseEntry = { name, db, owned: options?.owned ?? false, stack: this };\n this.#entries.set(name, entry);\n if (options?.default || this.#entries.size === 1) {\n this.#defaultName ??= name;\n if (options?.default) this.#defaultName = name;\n }\n return this;\n }\n\n setDefault(name: string): this {\n this.#assertOpen();\n if (!this.#entries.has(name)) {\n throw new SqlStackError(\n `SqlStack has no database registered under \"${name}\". Registered: ${this.#registeredNames()}`\n );\n }\n this.#defaultName = name;\n return this;\n }\n\n getEntry(name?: string): DatabaseEntry {\n this.#assertOpen();\n const key = name ?? this.#defaultName;\n if (!key) {\n throw new SqlStackError(\n 'SqlStack has no default database. Register one with { default: true } or call setDefault(name).'\n );\n }\n const entry = this.#entries.get(key);\n if (!entry) {\n throw new SqlStackError(\n `SqlStack has no database registered under \"${key}\". Registered: ${this.#registeredNames()}`\n );\n }\n return entry;\n }\n\n database(name?: string): Database {\n return this.getEntry(name).db;\n }\n\n has(name: string): boolean {\n return this.#entries.has(name) || this.#families.has(name);\n }\n\n /**\n * Register a dynamic database family (spec 17): one registration whose\n * concrete member is selected per execution flow via withDatabase(...).\n */\n registerFamily<K = string>(name: string, config: FamilyConfig<K>): this {\n this.#assertOpen();\n if (this.#entries.has(name)) {\n throw new SqlStackError(`\"${name}\" is already registered as a static database.`);\n }\n this.#families.set(name, new FamilyRuntime(this, name, config));\n return this;\n }\n\n family<K = string>(name: string): FamilyRuntime<K> {\n const fam = this.#families.get(name);\n if (!fam) {\n throw new SqlStackError(\n `SqlStack has no database family registered under \"${name}\". Families: ${\n [...this.#families.keys()].map((n) => `\"${n}\"`).join(', ') || '(none)'\n }`\n );\n }\n return fam;\n }\n\n /**\n * Bind a family registration to a concrete member for the duration of fn\n * (spec 17 §10). The binding is flow-local to this SqlStack; the member's\n * connection is leased lazily on first database resolution and released\n * when fn settles. Rebinding a family to a different key while it has an\n * active transaction fails deterministically (spec 17 §29).\n */\n async withDatabase<T>(family: string, key: unknown, fn: () => Promise<T>): Promise<T> {\n this.#assertOpen();\n const fam = this.family(family);\n const { keyId } = fam.normalize(key);\n\n const outer = currentBinding(this, family);\n if (outer && outer.keyId !== keyId && outer.lease) {\n const { getActiveTransaction } = await import('./transactions');\n if (getActiveTransaction(outer.lease.entry)) {\n throw new SqlStackError(\n `Cannot rebind database family \"${family}\" from \"${outer.keyId}\" to \"${keyId}\": ` +\n 'a transaction is active for the current member. Finish the transaction first.'\n );\n }\n }\n\n const frame: BindingFrame = { stack: this, family, keyInput: key, keyId };\n try {\n return await runWithBinding(frame, fn);\n } finally {\n await frame.lease?.release();\n }\n }\n\n /**\n * Async database resolution for query/transaction execution. Static\n * registrations resolve directly; family registrations resolve through the\n * active flow-local binding, opening/leasing the member on first use.\n */\n async resolveEntry(name?: string): Promise<DatabaseEntry> {\n this.#assertOpen();\n const key =\n name ??\n this.#defaultName ??\n // A stack whose only registration is one family treats it as default.\n (this.#entries.size === 0 && this.#families.size === 1\n ? [...this.#families.keys()][0]\n : undefined);\n if (key !== undefined) {\n const entry = this.#entries.get(key);\n if (entry) return entry;\n const fam = this.#families.get(key);\n if (fam) {\n const frame = currentBinding(this, key);\n if (!frame) {\n throw new SqlStackError(\n `SQLStack database family \"${key}\" requires a concrete database key. ` +\n 'No active binding exists for this execution. Establish the database at the ' +\n `orchestration boundary with sqlStack.withDatabase(\"${key}\", key, ...) ` +\n 'or acquire a member explicitly via sqlStack.family(...).with(...).'\n );\n }\n if (!frame.lease) {\n frame.lease = await fam.acquire(frame.keyInput);\n }\n return frame.lease.entry;\n }\n }\n return this.getEntry(name);\n }\n\n /**\n * Set this stack's SQL resolver. When `options.classes` supplies the\n * repository catalog, manifest coverage is validated from those classes'\n * immutable metadata (environment-local, unpollutable by unrelated\n * imports). Without a catalog, coverage falls back to the deprecated\n * process-global decorated list.\n */\n useResolver(\n resolver: SqlResolver,\n options?: { classes?: ReadonlyArray<abstract new (...args: any[]) => any> }\n ): this {\n this.#assertOpen();\n if (resolver instanceof ManifestResolver && resolver.options.assert !== false) {\n if (options?.classes) {\n assertManifestCoversClasses(resolver, options.classes);\n } else {\n assertManifestCoverage(resolver);\n }\n }\n this.#resolver = resolver;\n return this;\n }\n\n resolver(): SqlResolver | undefined {\n return this.#resolver;\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n /**\n * Close owned database adapters exactly once and release runtime resources.\n * Externally supplied databases (owned: false) are not touched. Failures are\n * collected and reported with database identity rather than swallowed.\n */\n close(): Promise<void> {\n if (this.#closing) return this.#closing;\n this.#closed = true;\n this.#closing = Promise.resolve().then(async () => {\n const failures: string[] = [];\n const errors: unknown[] = [];\n const closed = new Set<Database>();\n for (const entry of this.#entries.values()) {\n if (!entry.owned || closed.has(entry.db)) continue;\n closed.add(entry.db);\n try { await entry.db.close(); }\n catch (error: any) {\n errors.push(error);\n failures.push(`\"${entry.name}\": ${error?.message ?? String(error)}`);\n }\n }\n for (const fam of this.#families.values()) {\n try { await fam.closeAll(); }\n catch (error: any) { errors.push(error); failures.push(error?.message ?? String(error)); }\n }\n this.#entries.clear();\n this.#families.clear();\n this.#resolver = undefined;\n if (failures.length) {\n throw Object.assign(new SqlStackError(`SqlStack close failed for ${failures.join(', ')}`), {\n errors: Object.freeze(errors), cause: errors[0],\n });\n }\n });\n return this.#closing;\n }\n\n /** Native IoC resource hook; manually calling close remains supported. */\n dispose(): Promise<void> { return this.close(); }\n\n #assertOpen(): void {\n if (this.#closed) {\n throw new SqlStackError('SqlStack has been closed; its owning root was disposed.');\n }\n }\n\n #registeredNames(): string {\n const names = [\n ...[...this.#entries.keys()].map((n) => `\"${n}\"`),\n ...[...this.#families.keys()].map((n) => `\"${n}\" (family)`),\n ];\n return names.length ? names.join(', ') : '(none)';\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/testing/builder.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,OAAO,EAAwB,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EAA2B,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAe,aAAa,EAAc,GAAG,EAAgB,MAAM,qBAAqB,CAAC;AAEhG,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB,EAAE,sBAAsB;CAAG;AAEzF,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,SAAS,aAAa,EAAE,CAAC;IACvC,gEAAgE;IAChE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,mBAAmB,CAAC;IACvD;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACxC;AAiFD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,mBAAwB,GAChC,mBAAmB,CAIrB"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/testing/builder.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAEnF,OAAO,EAAwB,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,OAAO,EAA2B,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAe,aAAa,EAAc,GAAG,EAAgB,MAAM,qBAAqB,CAAC;AAEhG,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB,EAAE,sBAAsB;CAAG;AAEzF,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,SAAS,aAAa,EAAE,CAAC;IACvC,gEAAgE;IAChE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,mBAAmB,CAAC;IACvD;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACxC;AAqFD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,OAAO,GAAE,mBAAwB,GAChC,mBAAmB,CAIrB"}
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.testPostgres = testPostgres;
37
37
  const fs = __importStar(require("fs"));
38
+ const resource_1 = require("./resource");
39
+ const fixture_provenance_1 = require("./fixture-provenance");
38
40
  const parser_1 = require("./schema/parser");
39
41
  const ddl_1 = require("./schema/ddl");
40
42
  const allocator_1 = require("./postgres/allocator");
@@ -48,6 +50,7 @@ function readRawSql(schema) {
48
50
  return { label: `sql entry #${entry.index} (inline)`, sql: entry.sql };
49
51
  }
50
52
  try {
53
+ (0, fixture_provenance_1.assertFixtureSqlFile)(entry.resolvedPath);
51
54
  return {
52
55
  label: `sql entry #${entry.index} (${entry.sourcePath})`,
53
56
  sql: fs.readFileSync(entry.resolvedPath, 'utf8'),
@@ -97,14 +100,20 @@ function makeBuilder(state) {
97
100
  }
98
101
  }
99
102
  await (0, loadData_1.insertRows)((sql, params) => handle._pool.query(sql, params), state.schema, effective);
100
- return handle;
103
+ return (0, resource_1.adoptFixtureResource)(handle);
101
104
  }
102
105
  catch (err) {
103
- // Clean up partially created owned resources.
104
- if (handle) {
105
- await handle._pool.end().catch(() => undefined);
106
+ // Use the handle's all-steps disposer and retire its provenance even
107
+ // after failed DDL/data. Preserve allocation and every cleanup failure.
108
+ try {
109
+ if (handle)
110
+ await handle.dispose();
111
+ else
112
+ await (0, allocator_2.dropDatabase)(allocated.name, state.options);
113
+ }
114
+ catch (cleanup) {
115
+ throw new resource_1.TestDatabaseBuildError('PostgreSQL fixture build and cleanup failed', err, cleanup);
106
116
  }
107
- await (0, allocator_2.dropDatabase)(allocated.name, state.options).catch(() => undefined);
108
117
  throw err;
109
118
  }
110
119
  },