@danceroutine/tango-orm 1.3.0 → 1.4.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 (60) hide show
  1. package/dist/PostgresAdapter-BFdo_nIt.js +4 -0
  2. package/dist/{PostgresAdapter-C9a1XJRx.js → PostgresAdapter-CMiEpHya.js} +4 -52
  3. package/dist/PostgresAdapter-CMiEpHya.js.map +1 -0
  4. package/dist/PostgresClient-BQJZfEOT.js +68 -0
  5. package/dist/PostgresClient-BQJZfEOT.js.map +1 -0
  6. package/dist/SqliteAdapter-A-P9zUhP.js +4 -0
  7. package/dist/SqliteAdapter-CeqhyrPC.js +44 -0
  8. package/dist/SqliteAdapter-CeqhyrPC.js.map +1 -0
  9. package/dist/{SqliteAdapter-Dp6VRXmz.js → SqliteClient-CjOK9-ki.js} +20 -41
  10. package/dist/SqliteClient-CjOK9-ki.js.map +1 -0
  11. package/dist/connection/clients/DBClient.d.ts +6 -0
  12. package/dist/connection/clients/dialects/PostgresClient.d.ts +21 -5
  13. package/dist/connection/clients/dialects/SqliteClient.d.ts +13 -1
  14. package/dist/connection/index.js +5 -3
  15. package/dist/{connection-CVvycXus.js → connection-B_K2ZAf7.js} +7 -5
  16. package/dist/{connection-CVvycXus.js.map → connection-B_K2ZAf7.js.map} +1 -1
  17. package/dist/defaultRuntime-BPK9kWEW.js +447 -0
  18. package/dist/defaultRuntime-BPK9kWEW.js.map +1 -0
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.js +12 -9
  21. package/dist/manager/ModelManager.d.ts +2 -0
  22. package/dist/manager/index.js +6 -6
  23. package/dist/manager/internal/RuntimeBoundClient.d.ts +5 -1
  24. package/dist/{manager-D6tU8xTO.js → manager-C6oJ2tAF.js} +2 -2
  25. package/dist/{manager-D6tU8xTO.js.map → manager-C6oJ2tAF.js.map} +1 -1
  26. package/dist/query/index.js +1 -1
  27. package/dist/{query-6GeNOf-w.js → query-CWZ1cfjo.js} +1 -1
  28. package/dist/{query-6GeNOf-w.js.map → query-CWZ1cfjo.js.map} +1 -1
  29. package/dist/{registerModelObjects-CXSI5ndy.js → registerModelObjects-Bva_f-Qh.js} +26 -118
  30. package/dist/registerModelObjects-Bva_f-Qh.js.map +1 -0
  31. package/dist/runtime/TangoRuntime.d.ts +17 -4
  32. package/dist/runtime/index.js +6 -6
  33. package/dist/runtime/internal/DBClientProvider.d.ts +12 -0
  34. package/dist/runtime/internal/PostgresDBClientProvider.d.ts +12 -0
  35. package/dist/runtime/internal/SqliteDBClientProvider.d.ts +16 -0
  36. package/dist/runtime/internal/createDBClientProvider.d.ts +5 -0
  37. package/dist/{runtime-7U5_XDad.js → runtime-ByXbpVBS.js} +3 -2
  38. package/dist/{runtime-7U5_XDad.js.map → runtime-ByXbpVBS.js.map} +1 -1
  39. package/dist/transaction/AtomicTransaction.d.ts +32 -0
  40. package/dist/transaction/UnitOfWork.d.ts +3 -0
  41. package/dist/transaction/atomic.d.ts +2 -0
  42. package/dist/transaction/index.d.ts +2 -0
  43. package/dist/transaction/index.js +5 -2
  44. package/dist/transaction/internal/context/AsyncLocalTransactionEngine.d.ts +21 -0
  45. package/dist/transaction/internal/context/CallbackRecord.d.ts +5 -0
  46. package/dist/transaction/internal/context/FrameBoundTransaction.d.ts +20 -0
  47. package/dist/transaction/internal/context/FrameTransactionHandle.d.ts +4 -0
  48. package/dist/transaction/internal/context/TransactionEngine.d.ts +16 -0
  49. package/dist/transaction/internal/context/TransactionFrame.d.ts +7 -0
  50. package/dist/transaction/internal/context/TransactionState.d.ts +10 -0
  51. package/dist/transaction/internal/context/index.d.ts +1 -0
  52. package/dist/{transaction-DooTMuAl.js → transaction-Cs0Z9tbW.js} +15 -3
  53. package/dist/transaction-Cs0Z9tbW.js.map +1 -0
  54. package/package.json +6 -6
  55. package/dist/PostgresAdapter-C9a1XJRx.js.map +0 -1
  56. package/dist/PostgresAdapter-CBc1u8eT.js +0 -3
  57. package/dist/SqliteAdapter-BJKNxCvS.js +0 -3
  58. package/dist/SqliteAdapter-Dp6VRXmz.js.map +0 -1
  59. package/dist/registerModelObjects-CXSI5ndy.js.map +0 -1
  60. package/dist/transaction-DooTMuAl.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danceroutine/tango-orm",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Model-first querying, runtime-managed database access, and transactions for Tango",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,9 +49,9 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "zod": "^4.0.0",
52
- "@danceroutine/tango-config": "1.3.0",
53
- "@danceroutine/tango-core": "1.3.0",
54
- "@danceroutine/tango-schema": "1.3.0"
52
+ "@danceroutine/tango-config": "1.4.0",
53
+ "@danceroutine/tango-core": "1.4.0",
54
+ "@danceroutine/tango-schema": "1.4.0"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "pg": "^8.13.1",
@@ -74,8 +74,8 @@
74
74
  "tsdown": "^0.4.0",
75
75
  "typescript": "^5.6.3",
76
76
  "vitest": "^4.0.6",
77
- "@danceroutine/tango-migrations": "1.3.0",
78
- "@danceroutine/tango-testing": "1.3.0"
77
+ "@danceroutine/tango-migrations": "1.4.0",
78
+ "@danceroutine/tango-testing": "1.4.0"
79
79
  },
80
80
  "scripts": {
81
81
  "build": "tsdown",
@@ -1 +0,0 @@
1
- {"version":3,"file":"PostgresAdapter-C9a1XJRx.js","names":["pool: pg.Pool","client: pg.PoolClient","value: unknown","sql: string","params?: readonly unknown[]","value: unknown","config: AdapterConfig"],"sources":["../src/connection/clients/dialects/PostgresClient.ts","../src/connection/adapters/dialects/PostgresAdapter.ts"],"sourcesContent":["import type pg from 'pg';\nimport type { DBClient } from '../DBClient';\n\n/**\n * `DBClient` implementation backed by a PostgreSQL pool client.\n */\nexport class PostgresClient implements DBClient {\n static readonly BRAND = 'tango.orm.postgres_client' as const;\n readonly __tangoBrand: typeof PostgresClient.BRAND = PostgresClient.BRAND;\n\n constructor(\n private pool: pg.Pool,\n private client: pg.PoolClient\n ) {}\n\n /**\n * Narrow an unknown value to `PostgresClient`.\n */\n static isPostgresClient(value: unknown): value is PostgresClient {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === PostgresClient.BRAND\n );\n }\n\n /**\n * Execute a SQL statement with optional bound parameters.\n */\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const result = await this.client.query(sql, params as unknown[]);\n return { rows: result.rows as T[] };\n }\n\n /**\n * Begin a database transaction.\n */\n async begin(): Promise<void> {\n await this.client.query('BEGIN');\n }\n\n /**\n * Commit the active transaction.\n */\n async commit(): Promise<void> {\n await this.client.query('COMMIT');\n }\n\n /**\n * Roll back the active transaction.\n */\n async rollback(): Promise<void> {\n await this.client.query('ROLLBACK');\n }\n\n /**\n * Release client resources and close the associated pool.\n */\n async close(): Promise<void> {\n this.client.release();\n await this.pool.end();\n }\n}\n","import pg from 'pg';\nimport type { Adapter, AdapterConfig } from '../Adapter';\nimport type { DBClient } from '../../clients/DBClient';\nimport { PostgresClient } from '../../clients/dialects/PostgresClient';\n\nconst { Pool } = pg;\n\n/**\n * Postgres adapter that turns adapter config into a transactional `DBClient`.\n */\nexport class PostgresAdapter implements Adapter {\n static readonly BRAND = 'tango.orm.postgres_adapter' as const;\n readonly __tangoBrand: typeof PostgresAdapter.BRAND = PostgresAdapter.BRAND;\n readonly name = 'postgres';\n /**\n * Declares capabilities of this database adapter.\n * Used by the migration runner and query compiler to determine which\n * SQL features can be safely used:\n * - transactionalDDL: Postgres supports DDL inside transactions (safe rollback of schema changes)\n * - concurrentIndex: Supports CREATE INDEX CONCURRENTLY (non-blocking index builds)\n * - validateForeignKeys: Supports deferred FK validation via NOT VALID + VALIDATE CONSTRAINT\n */\n readonly features = {\n transactionalDDL: true,\n concurrentIndex: true,\n validateForeignKeys: true,\n };\n\n /**\n * Narrow an unknown value to `PostgresAdapter`.\n */\n static isPostgresAdapter(value: unknown): value is PostgresAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === PostgresAdapter.BRAND\n );\n }\n\n /**\n * Open a Postgres connection pool and return a client-backed DB abstraction.\n */\n async connect(config: AdapterConfig): Promise<DBClient> {\n const pool = new Pool({\n connectionString: config.url,\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n password: config.password,\n max: config.maxConnections || 10,\n });\n\n const client = await pool.connect();\n return new PostgresClient(pool, client);\n }\n}\n"],"mappings":";;;IAMa,iBAAN,MAAM,eAAmC;CAC5C,OAAgB,QAAQ;CACxB,eAAqD,eAAe;CAEpE,YACYA,MACAC,QACV;AAAA,OAFU,OAAA;AAAA,OACA,SAAA;CACR;;;;CAKJ,OAAO,iBAAiBC,OAAyC;AAC7D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,eAAe;CAE7E;;;;CAKD,MAAM,MAAmBC,KAAaC,QAAqD;EACvF,MAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,OAAoB;AAChE,SAAO,EAAE,MAAM,OAAO,KAAa;CACtC;;;;CAKD,MAAM,QAAuB;AACzB,QAAM,KAAK,OAAO,MAAM,QAAQ;CACnC;;;;CAKD,MAAM,SAAwB;AAC1B,QAAM,KAAK,OAAO,MAAM,SAAS;CACpC;;;;CAKD,MAAM,WAA0B;AAC5B,QAAM,KAAK,OAAO,MAAM,WAAW;CACtC;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,OAAO,SAAS;AACrB,QAAM,KAAK,KAAK,KAAK;CACxB;AACJ;;;;ACzDD,MAAM,EAAE,MAAM,GAAG;IAKJ,kBAAN,MAAM,gBAAmC;CAC5C,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;CACtE,OAAgB;;;;;;;;;CAShB,WAAoB;EAChB,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB;CACxB;;;;CAKD,OAAO,kBAAkBC,OAA0C;AAC/D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE9E;;;;CAKD,MAAM,QAAQC,QAA0C;EACpD,MAAM,OAAO,IAAI,KAAK;GAClB,kBAAkB,OAAO;GACzB,MAAM,OAAO;GACb,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,KAAK,OAAO,kBAAkB;EACjC;EAED,MAAM,SAAS,MAAM,KAAK,SAAS;AACnC,SAAO,IAAI,eAAe,MAAM;CACnC;AACJ"}
@@ -1,3 +0,0 @@
1
- import { PostgresAdapter } from "./PostgresAdapter-C9a1XJRx.js";
2
-
3
- export { PostgresAdapter };
@@ -1,3 +0,0 @@
1
- import { SqliteAdapter } from "./SqliteAdapter-Dp6VRXmz.js";
2
-
3
- export { SqliteAdapter };
@@ -1 +0,0 @@
1
- {"version":3,"file":"SqliteAdapter-Dp6VRXmz.js","names":["db: Database.Database","value: unknown","sql: string","params?: readonly unknown[]","value: unknown","config: AdapterConfig"],"sources":["../src/connection/clients/dialects/SqliteClient.ts","../src/connection/adapters/dialects/SqliteAdapter.ts"],"sourcesContent":["import type Database from 'better-sqlite3';\nimport type { DBClient } from '../DBClient';\n\n/**\n * `DBClient` implementation backed by a synchronous `better-sqlite3` handle.\n */\nexport class SqliteClient implements DBClient {\n static readonly BRAND = 'tango.orm.sqlite_client' as const;\n readonly __tangoBrand: typeof SqliteClient.BRAND = SqliteClient.BRAND;\n private inTransaction = false;\n\n constructor(private db: Database.Database) {}\n\n /**\n * Narrow an unknown value to `SqliteClient`.\n */\n static isSqliteClient(value: unknown): value is SqliteClient {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === SqliteClient.BRAND\n );\n }\n\n /**\n * Execute a SQL statement with optional parameters.\n *\n * `SELECT`/`PRAGMA` statements return row data; write statements return\n * an empty row list.\n */\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const stmt = this.db.prepare(sql);\n const isPragmaWrite = /^\\s*PRAGMA\\b/i.test(sql) && /=/.test(sql);\n\n const normalizedParams = params?.map((param) => this.normalizeParam(param));\n\n if (!isPragmaWrite && stmt.reader) {\n const rows = normalizedParams ? stmt.all(...(normalizedParams as unknown[])) : stmt.all();\n return { rows: rows as T[] };\n }\n\n if (normalizedParams) {\n stmt.run(...(normalizedParams as unknown[]));\n } else {\n stmt.run();\n }\n return { rows: [] };\n }\n\n /**\n * Begin a transaction if one is not already active.\n */\n async begin(): Promise<void> {\n if (!this.inTransaction) {\n this.db.prepare('BEGIN').run();\n this.inTransaction = true;\n }\n }\n\n /**\n * Commit the active transaction.\n */\n async commit(): Promise<void> {\n if (this.inTransaction) {\n this.db.prepare('COMMIT').run();\n this.inTransaction = false;\n }\n }\n\n /**\n * Roll back the active transaction.\n */\n async rollback(): Promise<void> {\n if (this.inTransaction) {\n this.db.prepare('ROLLBACK').run();\n this.inTransaction = false;\n }\n }\n\n /**\n * Close the underlying SQLite handle.\n */\n async close(): Promise<void> {\n this.db.close();\n }\n\n private normalizeParam(value: unknown): unknown {\n if (isDateValue(value)) {\n return value.toISOString();\n }\n if (typeof value === 'boolean') {\n return value ? 1 : 0;\n }\n return value;\n }\n}\n\nfunction isDateValue(value: unknown): value is Date {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { getTime?: unknown }).getTime === 'function' &&\n typeof (value as { toISOString?: unknown }).toISOString === 'function'\n );\n}\n","import { createRequire } from 'node:module';\nimport type { Database as BetterSqliteDatabase } from 'better-sqlite3';\nimport type { Adapter, AdapterConfig } from '../Adapter';\nimport type { DBClient } from '../../clients/DBClient';\nimport { SqliteClient } from '../../clients/dialects/SqliteClient';\n\ntype BetterSqliteCtor = new (filename: string, options?: unknown) => BetterSqliteDatabase;\n\n/**\n * SQLite adapter that creates a `better-sqlite3` backed `DBClient`.\n */\nexport class SqliteAdapter implements Adapter {\n static readonly BRAND = 'tango.orm.sqlite_adapter' as const;\n readonly __tangoBrand: typeof SqliteAdapter.BRAND = SqliteAdapter.BRAND;\n readonly name = 'sqlite';\n readonly features = {\n transactionalDDL: true,\n concurrentIndex: false,\n validateForeignKeys: false,\n };\n\n /**\n * Narrow an unknown value to `SqliteAdapter`.\n */\n static isSqliteAdapter(value: unknown): value is SqliteAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === SqliteAdapter.BRAND\n );\n }\n\n /**\n * Open a SQLite database and apply baseline pragmas for durability/safety.\n */\n async connect(config: AdapterConfig = {}): Promise<DBClient> {\n const Database = this.getDatabaseCtor();\n const filename =\n typeof config.filename === 'string' && config.filename.length > 0 ? config.filename : ':memory:';\n const db = new Database(filename);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n\n return new SqliteClient(db);\n }\n\n private getDatabaseCtor(): BetterSqliteCtor {\n const require = createRequire(import.meta.url);\n const moduleValue = require('better-sqlite3') as unknown;\n if (typeof moduleValue === 'function') {\n return moduleValue as BetterSqliteCtor;\n }\n\n const defaultExport = (moduleValue as { default?: unknown }).default;\n if (typeof defaultExport === 'function') {\n return defaultExport as BetterSqliteCtor;\n }\n\n throw new TypeError('Failed to load better-sqlite3 constructor.');\n }\n}\n"],"mappings":";;;IAMa,eAAN,MAAM,aAAiC;CAC1C,OAAgB,QAAQ;CACxB,eAAmD,aAAa;CAChE,gBAAwB;CAExB,YAAoBA,IAAuB;AAAA,OAAvB,KAAA;CAAyB;;;;CAK7C,OAAO,eAAeC,OAAuC;AACzD,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,aAAa;CAE3E;;;;;;;CAQD,MAAM,MAAmBC,KAAaC,QAAqD;EACvF,MAAM,OAAO,KAAK,GAAG,QAAQ,IAAI;EACjC,MAAM,gBAAgB,gBAAgB,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI;EAEhE,MAAM,mBAAmB,QAAQ,IAAI,CAAC,UAAU,KAAK,eAAe,MAAM,CAAC;AAE3E,OAAK,iBAAiB,KAAK,QAAQ;GAC/B,MAAM,OAAO,mBAAmB,KAAK,IAAI,GAAI,iBAA+B,GAAG,KAAK,KAAK;AACzF,UAAO,EAAQ,KAAa;EAC/B;AAED,MAAI,iBACA,MAAK,IAAI,GAAI,iBAA+B;IAE5C,MAAK,KAAK;AAEd,SAAO,EAAE,MAAM,CAAE,EAAE;CACtB;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,KAAK,eAAe;AACrB,QAAK,GAAG,QAAQ,QAAQ,CAAC,KAAK;AAC9B,QAAK,gBAAgB;EACxB;CACJ;;;;CAKD,MAAM,SAAwB;AAC1B,MAAI,KAAK,eAAe;AACpB,QAAK,GAAG,QAAQ,SAAS,CAAC,KAAK;AAC/B,QAAK,gBAAgB;EACxB;CACJ;;;;CAKD,MAAM,WAA0B;AAC5B,MAAI,KAAK,eAAe;AACpB,QAAK,GAAG,QAAQ,WAAW,CAAC,KAAK;AACjC,QAAK,gBAAgB;EACxB;CACJ;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,GAAG,OAAO;CAClB;CAED,eAAuBF,OAAyB;AAC5C,MAAI,YAAY,MAAM,CAClB,QAAO,MAAM,aAAa;AAE9B,aAAW,UAAU,UACjB,QAAO,QAAQ,IAAI;AAEvB,SAAO;CACV;AACJ;AAED,SAAS,YAAYA,OAA+B;AAChD,eACW,UAAU,YACjB,UAAU,eACF,MAAgC,YAAY,qBAC5C,MAAoC,gBAAgB;AAEnE;;;;IC7FY,gBAAN,MAAM,cAAiC;CAC1C,OAAgB,QAAQ;CACxB,eAAoD,cAAc;CAClE,OAAgB;CAChB,WAAoB;EAChB,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB;CACxB;;;;CAKD,OAAO,gBAAgBG,OAAwC;AAC3D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,cAAc;CAE5E;;;;CAKD,MAAM,QAAQC,SAAwB,CAAE,GAAqB;EACzD,MAAM,WAAW,KAAK,iBAAiB;EACvC,MAAM,kBACK,OAAO,aAAa,YAAY,OAAO,SAAS,SAAS,IAAI,OAAO,WAAW;EAC1F,MAAM,KAAK,IAAI,SAAS;AACxB,KAAG,OAAO,qBAAqB;AAC/B,KAAG,OAAO,oBAAoB;AAE9B,SAAO,IAAI,aAAa;CAC3B;CAED,kBAA4C;EACxC,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;EAC9C,MAAM,cAAc,QAAQ,iBAAiB;AAC7C,aAAW,gBAAgB,WACvB,QAAO;EAGX,MAAM,gBAAiB,YAAsC;AAC7D,aAAW,kBAAkB,WACzB,QAAO;AAGX,QAAM,IAAI,UAAU;CACvB;AACJ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"registerModelObjects-CXSI5ndy.js","names":["dialect: Dialect","plan: ValidatedInsertSqlPlan","values: readonly unknown[]","plan: ValidatedUpdateSqlPlan","id: unknown","plan: ValidatedDeleteSqlPlan","valueRows: ReadonlyArray<ReadonlyArray<unknown>>","count: number","index: number","runtime: TangoRuntime","sql: string","params?: readonly unknown[]","model: ModelLike<TModelRow>","runtime: TangoRuntime","value: unknown","rawMeta: TableMeta","id: TModelRow[keyof TModelRow]","input: Partial<TModelRow>","patch: Partial<TModelRow>","inputs: Partial<TModelRow>[]","batchPrepared: Partial<TModelRow>[]","data: Partial<TModelRow>","current: TModelRow","loadLoadedConfig: () => LoadedConfig","value: unknown","defaultRuntime: TangoRuntime | null","fromFile: () => unknown","model: SchemaModel<TSchema, TKey>"],"sources":["../src/manager/internal/MutationCompiler.ts","../src/manager/internal/RuntimeBoundClient.ts","../src/manager/ModelManager.ts","../src/runtime/TangoRuntime.ts","../src/runtime/defaultRuntime.ts","../src/manager/registerModelObjects.ts"],"sourcesContent":["import type { CompiledQuery, Dialect } from '../../query/domain/index';\nimport type {\n ValidatedDeleteSqlPlan,\n ValidatedInsertSqlPlan,\n ValidatedUpdateSqlPlan,\n} from '../../validation/SQLValidationEngine';\n\n/**\n * Internal compiler for manager-owned INSERT/UPDATE/DELETE statements.\n */\nexport class MutationCompiler {\n constructor(private readonly dialect: Dialect) {}\n\n compileInsert(plan: ValidatedInsertSqlPlan, values: readonly unknown[]): CompiledQuery {\n return {\n sql: `INSERT INTO ${plan.meta.table} (${plan.writeKeys.join(', ')}) VALUES (${this.buildValuePlaceholders(plan.writeKeys.length)}) RETURNING *`,\n params: values,\n };\n }\n\n compileUpdate(plan: ValidatedUpdateSqlPlan, values: readonly unknown[], id: unknown): CompiledQuery {\n const sets = plan.writeKeys.map((key, index) => `${key} = ${this.placeholder(index + 1)}`).join(', ');\n const whereParam = this.placeholder(plan.writeKeys.length + 1);\n\n return {\n sql: `UPDATE ${plan.meta.table} SET ${sets} WHERE ${plan.meta.pk} = ${whereParam} RETURNING *`,\n params: [...values, id],\n };\n }\n\n compileDelete(plan: ValidatedDeleteSqlPlan, id: unknown): CompiledQuery {\n return {\n sql: `DELETE FROM ${plan.meta.table} WHERE ${plan.meta.pk} = ${this.placeholder(1)}`,\n params: [id],\n };\n }\n\n compileBulkInsert(plan: ValidatedInsertSqlPlan, valueRows: ReadonlyArray<ReadonlyArray<unknown>>): CompiledQuery {\n const columnCount = plan.writeKeys.length;\n const placeholders = valueRows\n .map((_row, rowIndex) => {\n const offset = rowIndex * columnCount;\n return `(${plan.writeKeys.map((_, colIndex) => this.placeholder(offset + colIndex + 1)).join(', ')})`;\n })\n .join(', ');\n\n return {\n sql: `INSERT INTO ${plan.meta.table} (${plan.writeKeys.join(', ')}) VALUES ${placeholders} RETURNING *`,\n params: valueRows.flat(),\n };\n }\n\n private buildValuePlaceholders(count: number): string {\n return Array.from({ length: count }, (_value, index) => this.placeholder(index + 1)).join(', ');\n }\n\n private placeholder(index: number): string {\n return this.dialect === 'postgres' ? `$${index}` : '?';\n }\n}\n","import type { DBClient } from '../../connection/index';\nimport type { TangoRuntime } from '../../runtime/index';\n\n/**\n * DB client proxy that resolves the real Tango runtime client lazily.\n */\nexport class RuntimeBoundClient implements DBClient {\n constructor(private readonly runtime: TangoRuntime) {}\n\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const client = await this.runtime.getClient();\n return client.query<T>(sql, params);\n }\n\n async begin(): Promise<void> {\n const client = await this.runtime.getClient();\n await client.begin();\n }\n\n async commit(): Promise<void> {\n const client = await this.runtime.getClient();\n await client.commit();\n }\n\n async rollback(): Promise<void> {\n const client = await this.runtime.getClient();\n await client.rollback();\n }\n\n async close(): Promise<void> {\n const client = await this.runtime.getClient();\n await client.close();\n }\n}\n","import { NotFoundError } from '@danceroutine/tango-core';\nimport { ModelRegistry, type ModelWriteHooks } from '@danceroutine/tango-schema';\nimport type { FilterInput, RelationMeta, TableMeta } from '../query/domain/index';\nimport { InternalRelationKind } from '../query/domain/internal/InternalRelationKind';\nimport type { QuerySet } from '../query/index';\nimport { QuerySet as QuerySetClass } from '../query/index';\nimport type { Dialect, QueryExecutor } from '../query/index';\nimport type { TangoRuntime } from '../runtime/TangoRuntime';\nimport { OrmSqlSafetyAdapter } from '../validation';\nimport type { ManagerLike } from './ManagerLike';\nimport { MutationCompiler } from './internal/MutationCompiler';\nimport { RuntimeBoundClient } from './internal/RuntimeBoundClient';\n\nconst sqlSafetyAdapter = new OrmSqlSafetyAdapter();\n\ntype FieldLike = {\n name: string;\n type: string;\n primaryKey?: boolean;\n};\n\ntype ModelLike<TModelRow extends Record<string, unknown>> = {\n metadata: {\n key?: string;\n name: string;\n table: string;\n fields: FieldLike[];\n };\n schema: {\n parse(input: unknown): TModelRow;\n };\n hooks?: ModelWriteHooks<TModelRow>;\n};\n\n/**\n * Model-backed data access API exposed as `Model.objects`.\n */\nexport class ModelManager<TModelRow extends Record<string, unknown>, TSourceModel = unknown>\n implements ManagerLike<TModelRow, TSourceModel>\n{\n static readonly BRAND = 'tango.orm.model_manager' as const;\n readonly __tangoBrand: typeof ModelManager.BRAND = ModelManager.BRAND;\n private readonly queryExecutor: QueryExecutor<TModelRow>;\n private readonly mutationCompiler: MutationCompiler;\n private readonly model: ModelLike<TModelRow>;\n private readonly client: RuntimeBoundClient;\n private readonly dialect: Dialect;\n\n constructor(model: ModelLike<TModelRow>, runtime: TangoRuntime) {\n this.model = model;\n this.client = new RuntimeBoundClient(runtime);\n this.dialect = runtime.getDialect() as Dialect;\n this.mutationCompiler = new MutationCompiler(this.dialect);\n this.queryExecutor = {\n get meta() {\n return ModelManager.createTableMeta(model);\n },\n client: this.client,\n dialect: this.dialect,\n run: async (compiled) => {\n const result = await this.client.query<TModelRow>(compiled.sql, compiled.params);\n return result.rows;\n },\n };\n }\n\n get meta(): TableMeta {\n return ModelManager.createTableMeta(this.model);\n }\n\n /**\n * Narrow an unknown value to `ModelManager`.\n */\n static isModelManager<TModelRow extends Record<string, unknown>>(value: unknown): value is ModelManager<TModelRow> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === ModelManager.BRAND\n );\n }\n\n private static createTableMeta<TModelRow extends Record<string, unknown>>(model: ModelLike<TModelRow>): TableMeta {\n const pkField = model.metadata.fields.find((field) => field.primaryKey);\n if (!pkField) {\n throw new Error(`Model '${model.metadata.name}' cannot attach a manager without a primary key field.`);\n }\n\n const rawMeta: TableMeta = {\n table: model.metadata.table,\n pk: pkField.name,\n columns: Object.fromEntries(model.metadata.fields.map((field) => [field.name, field.type])),\n };\n\n if (model.metadata.key) {\n const owner = ModelRegistry.getOwner(model as never);\n const relations = owner.getResolvedRelationGraph().byModel.get(model.metadata.key);\n if (relations && relations.size > 0) {\n // This metadata is recomputed on access today. Most application tables have a small relation set, so\n // keeping this path direct is acceptable until profiling points to a dedicated manager-meta cache.\n rawMeta.relations = Object.fromEntries(\n Array.from(relations.entries())\n .filter(([, relation]) => relation.kind !== InternalRelationKind.MANY_TO_MANY)\n .map(([name, relation]) => {\n const targetModel = owner.getByKey(relation.targetModelKey)!;\n // Query planning needs the target model's SQL-facing shape so joined and prefetched rows can be\n // selected, normalized, and attached without leaking internal alias columns.\n const targetColumns = Object.fromEntries(\n targetModel.metadata.fields.map((field) => [field.name, field.type])\n );\n // Forward relations join from this table's FK to the target key. Reverse relations flip that:\n // this table's primary key matches the target model's FK back to this model.\n const sourceKey =\n relation.kind === InternalRelationKind.BELONGS_TO\n ? relation.localFieldName\n : relation.targetFieldName;\n const targetKey =\n relation.kind === InternalRelationKind.BELONGS_TO\n ? relation.targetFieldName\n : relation.localFieldName;\n\n return [\n name,\n {\n kind: relation.kind as RelationMeta['kind'],\n table: targetModel.metadata.table,\n sourceKey: sourceKey as string,\n targetKey: targetKey as string,\n targetColumns,\n alias: relation.alias,\n },\n ];\n })\n );\n }\n }\n\n const validatedMeta = sqlSafetyAdapter.validate({\n kind: 'insert',\n meta: rawMeta,\n writeKeys: Object.keys(rawMeta.columns),\n }).meta;\n\n if (rawMeta.relations) {\n validatedMeta.relations = rawMeta.relations;\n }\n\n return validatedMeta;\n }\n\n query(): QuerySet<TModelRow, TModelRow, TSourceModel> {\n return new QuerySetClass<TModelRow, TModelRow, TSourceModel>(this.queryExecutor, {});\n }\n\n async findById(id: TModelRow[keyof TModelRow]): Promise<TModelRow | null> {\n const filter = { [this.meta.pk]: id } as unknown as FilterInput<TModelRow>;\n return this.query().filter(filter).fetchOne();\n }\n\n async getOrThrow(id: TModelRow[keyof TModelRow]): Promise<TModelRow> {\n const result = await this.findById(id);\n if (!result) {\n throw new NotFoundError(`${this.model.metadata.name} with ${this.meta.pk}=${String(id)} not found`);\n }\n return result;\n }\n\n async create(input: Partial<TModelRow>): Promise<TModelRow> {\n const prepared = await this.runBeforeCreate(input);\n const preparedKeys = Object.keys(prepared);\n if (preparedKeys.length === 0) {\n throw new Error(`Cannot create ${this.model.metadata.name} without any values.`);\n }\n\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'insert',\n meta: this.meta,\n writeKeys: preparedKeys,\n });\n const compiled = this.mutationCompiler.compileInsert(\n validatedPlan,\n preparedKeys.map((key) => prepared[key as keyof TModelRow])\n );\n const result = await this.queryExecutor.client.query<TModelRow>(compiled.sql, compiled.params);\n const created = result.rows[0]!;\n await this.model.hooks?.afterCreate?.({\n record: created,\n model: this.model,\n manager: this,\n });\n return created;\n }\n\n async update(id: TModelRow[keyof TModelRow], patch: Partial<TModelRow>): Promise<TModelRow> {\n const current = await this.getOrThrow(id);\n const prepared = await this.runBeforeUpdate(id, patch, current);\n const preparedKeys = Object.keys(prepared);\n if (preparedKeys.length === 0) {\n throw new Error(`Cannot update ${this.model.metadata.name} without any values.`);\n }\n\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'update',\n meta: this.meta,\n writeKeys: preparedKeys,\n });\n const compiled = this.mutationCompiler.compileUpdate(\n validatedPlan,\n preparedKeys.map((key) => prepared[key as keyof TModelRow]),\n id\n );\n const result = await this.queryExecutor.client.query<TModelRow>(compiled.sql, compiled.params);\n const updated = result.rows[0]!;\n await this.model.hooks?.afterUpdate?.({\n id,\n patch: prepared,\n previous: current,\n record: updated,\n model: this.model,\n manager: this,\n });\n return updated;\n }\n\n async delete(id: TModelRow[keyof TModelRow]): Promise<void> {\n const current = await this.getOrThrow(id);\n await this.model.hooks?.beforeDelete?.({\n id,\n current,\n model: this.model,\n manager: this,\n });\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'delete',\n meta: this.meta,\n });\n const compiled = this.mutationCompiler.compileDelete(validatedPlan, id);\n await this.queryExecutor.client.query(compiled.sql, compiled.params);\n await this.model.hooks?.afterDelete?.({\n id,\n previous: current,\n model: this.model,\n manager: this,\n });\n }\n\n async bulkCreate(inputs: Partial<TModelRow>[]): Promise<TModelRow[]> {\n if (inputs.length === 0) {\n return [];\n }\n\n const perRowPrepared = await Promise.all(inputs.map((input) => this.runBeforeCreate(input)));\n const batchPrepared: Partial<TModelRow>[] =\n (await this.model.hooks?.beforeBulkCreate?.({\n rows: perRowPrepared,\n model: this.model,\n manager: this,\n })) ?? perRowPrepared;\n const preparedKeys = Object.keys(batchPrepared[0] ?? {});\n if (preparedKeys.length === 0) {\n throw new Error(`Cannot create ${this.model.metadata.name} without any values.`);\n }\n\n const validatedPlan = sqlSafetyAdapter.validate({\n kind: 'insert',\n meta: this.meta,\n writeKeys: preparedKeys,\n });\n const valueRows = batchPrepared.map((input) => preparedKeys.map((key) => input[key as keyof TModelRow]));\n const compiled = this.mutationCompiler.compileBulkInsert(validatedPlan, valueRows);\n const result = await this.queryExecutor.client.query<TModelRow>(compiled.sql, compiled.params);\n await Promise.all(\n result.rows.map((record) =>\n this.model.hooks?.afterCreate?.({\n record,\n model: this.model,\n manager: this,\n })\n )\n );\n await this.model.hooks?.afterBulkCreate?.({\n records: result.rows,\n model: this.model,\n manager: this,\n });\n return result.rows;\n }\n\n private async runBeforeCreate(data: Partial<TModelRow>): Promise<Partial<TModelRow>> {\n return (\n (await this.model.hooks?.beforeCreate?.({\n data,\n model: this.model,\n manager: this,\n })) ?? data\n );\n }\n\n private async runBeforeUpdate(\n id: TModelRow[keyof TModelRow],\n patch: Partial<TModelRow>,\n current: TModelRow\n ): Promise<Partial<TModelRow>> {\n return (\n (await this.model.hooks?.beforeUpdate?.({\n id,\n patch,\n current,\n model: this.model,\n manager: this,\n })) ?? patch\n );\n }\n}\n","import type { LoadedConfig } from '@danceroutine/tango-config';\nimport type { DBClient } from '../connection/index';\nimport { connectDB } from '../connection/index';\nimport type { Dialect } from '../query/domain/index';\n\n/**\n * Framework-owned database runtime that resolves Tango config and lazily\n * creates the shared DB client used by manager-backed models.\n */\nexport class TangoRuntime {\n static readonly BRAND = 'tango.orm.runtime' as const;\n readonly __tangoBrand: typeof TangoRuntime.BRAND = TangoRuntime.BRAND;\n private readonly loadedConfig: LoadedConfig;\n private clientPromise: Promise<DBClient> | null = null;\n\n constructor(loadLoadedConfig: () => LoadedConfig) {\n this.loadedConfig = loadLoadedConfig();\n }\n\n /**\n * Narrow an unknown value to `TangoRuntime`.\n */\n static isTangoRuntime(value: unknown): value is TangoRuntime {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoRuntime.BRAND\n );\n }\n\n /**\n * Return the loaded Tango config snapshot for the active environment.\n */\n getConfig(): LoadedConfig {\n return this.loadedConfig;\n }\n\n /**\n * Return the configured SQL dialect for the current runtime.\n */\n getDialect(): Dialect {\n return this.loadedConfig.current.db.adapter;\n }\n\n /**\n * Return the shared DB client, creating it once on first access.\n */\n async getClient(): Promise<DBClient> {\n if (!this.clientPromise) {\n const db = this.loadedConfig.current.db;\n this.clientPromise = connectDB({\n adapter: db.adapter,\n url: db.url,\n host: db.host,\n port: db.port,\n database: db.database,\n user: db.user,\n password: db.password,\n filename: db.filename,\n maxConnections: db.maxConnections,\n });\n }\n\n return this.clientPromise;\n }\n\n /**\n * Close and clear the cached DB client so tests can start fresh.\n */\n async reset(): Promise<void> {\n if (!this.clientPromise) {\n return;\n }\n\n const client = await this.clientPromise;\n this.clientPromise = null;\n await client.close();\n }\n}\n","import { loadConfig, loadConfigFromProjectRoot } from '@danceroutine/tango-config';\nimport { TangoRuntime } from './TangoRuntime';\n\nlet defaultRuntime: TangoRuntime | null = null;\n\n/**\n * Initialize the process-default Tango runtime from a Tango config loader.\n */\nexport function initializeTangoRuntime(fromFile: () => unknown): TangoRuntime {\n defaultRuntime = new TangoRuntime(() => loadConfig(fromFile));\n return defaultRuntime;\n}\n\n/**\n * Return the process-default Tango runtime, lazily loading Tango config on first access.\n */\nexport function getTangoRuntime(): TangoRuntime {\n if (!defaultRuntime) {\n defaultRuntime = new TangoRuntime(() => loadConfigFromProjectRoot());\n }\n\n return defaultRuntime;\n}\n\n/**\n * Reset the process-default Tango runtime and release any cached client.\n */\nexport async function resetTangoRuntime(): Promise<void> {\n if (!defaultRuntime) {\n return;\n }\n\n const runtime = defaultRuntime;\n defaultRuntime = null;\n await runtime.reset();\n}\n","import type { z } from 'zod';\nimport type { Model as SchemaModel, PersistedModelOutput } from '@danceroutine/tango-schema/domain';\nimport { registerModelAugmentor } from '@danceroutine/tango-schema';\nimport { ModelManager } from './ModelManager';\nimport type { TangoRuntime } from '../runtime/TangoRuntime';\nimport { getTangoRuntime } from '../runtime/defaultRuntime';\n\nconst managerCache = new WeakMap<object, { runtime: TangoRuntime; manager: ModelManager<Record<string, unknown>> }>();\nlet hasRegisteredModelObjects = false;\n\ntype AugmentableSchemaModel<TSchema extends z.ZodObject<z.ZodRawShape>> = {\n metadata: {\n key?: string;\n name: string;\n table: string;\n fields: Array<{ name: string; type: string; primaryKey?: boolean }>;\n };\n schema: {\n parse(input: unknown): PersistedModelOutput<TSchema>;\n };\n hooks?: SchemaModel<TSchema>['hooks'];\n};\n\nfunction defineObjectsProperty<TSchema extends z.ZodObject<z.ZodRawShape>, TKey extends string>(\n model: SchemaModel<TSchema, TKey>\n): void {\n Object.defineProperty(model, 'objects', {\n configurable: true,\n enumerable: true,\n get() {\n const runtime = getTangoRuntime();\n const cached = managerCache.get(model);\n if (cached && cached.runtime === runtime) {\n return cached.manager;\n }\n\n const manager = new ModelManager<PersistedModelOutput<TSchema>, SchemaModel<TSchema, TKey>>(\n model as unknown as AugmentableSchemaModel<TSchema>,\n runtime\n );\n managerCache.set(model, {\n runtime,\n manager: manager as ModelManager<Record<string, unknown>>,\n });\n return manager;\n },\n });\n}\n\n/**\n * Install the schema model augmentor that exposes `Model.objects`.\n * This registration is idempotent so multiple Tango entrypoints can safely call it.\n */\nexport function registerModelObjects(): void {\n if (hasRegisteredModelObjects) {\n return;\n }\n\n registerModelAugmentor(defineObjectsProperty);\n hasRegisteredModelObjects = true;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"transaction-DooTMuAl.js","names":["client: DBClient","value: unknown"],"sources":["../src/transaction/UnitOfWork.ts","../src/transaction/index.ts"],"sourcesContent":["import type { DBClient } from '../connection/clients/DBClient';\n\n/**\n * Unit of Work pattern implementation for managing database transactions.\n * Ensures that a set of operations either all succeed or all fail together.\n *\n * @example\n * ```typescript\n * const uow = await UnitOfWork.start(dbClient);\n * try {\n * await userRepo.create({ email: 'test@example.com' });\n * await postRepo.create({ title: 'Hello' });\n * await uow.commit();\n * } catch (error) {\n * await uow.rollback();\n * throw error;\n * }\n * ```\n */\nexport class UnitOfWork {\n static readonly BRAND = 'tango.orm.unit_of_work' as const;\n readonly __tangoBrand: typeof UnitOfWork.BRAND = UnitOfWork.BRAND;\n protected client: DBClient;\n protected isActive = false;\n\n constructor(client: DBClient) {\n this.client = client;\n }\n\n /**\n * Narrow an unknown value to `UnitOfWork`.\n */\n static isUnitOfWork(value: unknown): value is UnitOfWork {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === UnitOfWork.BRAND\n );\n }\n\n /**\n * Convenience factory that constructs and begins a unit of work.\n */\n static async start(client: DBClient): Promise<UnitOfWork> {\n const uow = new UnitOfWork(client);\n await uow.begin();\n return uow;\n }\n\n /**\n * Begin a transaction if one is not already active.\n */\n async begin(): Promise<void> {\n if (!this.isActive) {\n await this.client.begin();\n this.isActive = true;\n }\n }\n\n /**\n * Commit the active transaction.\n */\n async commit(): Promise<void> {\n if (this.isActive) {\n await this.client.commit();\n this.isActive = false;\n }\n }\n\n /**\n * Return the underlying database client.\n */\n getClient(): DBClient {\n return this.client;\n }\n\n /**\n * Roll back the active transaction.\n */\n async rollback(): Promise<void> {\n if (this.isActive) {\n await this.client.rollback();\n this.isActive = false;\n }\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { UnitOfWork } from './UnitOfWork';\n"],"mappings":";;;IAmBa,aAAN,MAAM,WAAW;CACpB,OAAgB,QAAQ;CACxB,eAAiD,WAAW;CAC5D;CACA,WAAqB;CAErB,YAAYA,QAAkB;AAC1B,OAAK,SAAS;CACjB;;;;CAKD,OAAO,aAAaC,OAAqC;AACrD,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,WAAW;CAEzE;;;;CAKD,aAAa,MAAMD,QAAuC;EACtD,MAAM,MAAM,IAAI,WAAW;AAC3B,QAAM,IAAI,OAAO;AACjB,SAAO;CACV;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,KAAK,UAAU;AAChB,SAAM,KAAK,OAAO,OAAO;AACzB,QAAK,WAAW;EACnB;CACJ;;;;CAKD,MAAM,SAAwB;AAC1B,MAAI,KAAK,UAAU;AACf,SAAM,KAAK,OAAO,QAAQ;AAC1B,QAAK,WAAW;EACnB;CACJ;;;;CAKD,YAAsB;AAClB,SAAO,KAAK;CACf;;;;CAKD,MAAM,WAA0B;AAC5B,MAAI,KAAK,UAAU;AACf,SAAM,KAAK,OAAO,UAAU;AAC5B,QAAK,WAAW;EACnB;CACJ;AACJ"}