@danceroutine/tango-orm 1.7.0 → 1.8.1

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 (82) hide show
  1. package/dist/InternalDialect-ClSaUNso.js +10 -0
  2. package/dist/InternalDialect-ClSaUNso.js.map +1 -0
  3. package/dist/PostgresAdapter-CXKdKBG-.js +4 -0
  4. package/dist/PostgresAdapter-DySFW6vy.js +128 -0
  5. package/dist/PostgresAdapter-DySFW6vy.js.map +1 -0
  6. package/dist/{SqliteClient-CjOK9-ki.js → SqliteAdapter-CDdOjRmW.js} +57 -3
  7. package/dist/SqliteAdapter-CDdOjRmW.js.map +1 -0
  8. package/dist/SqliteAdapter-mjtXuVTg.js +4 -0
  9. package/dist/connection/adapters/Adapter.d.ts +32 -1
  10. package/dist/connection/adapters/dialects/PostgresAdapter.d.ts +5 -6
  11. package/dist/connection/adapters/dialects/SqliteAdapter.d.ts +4 -6
  12. package/dist/connection/adapters/index.d.ts +1 -1
  13. package/dist/connection/index.d.ts +1 -1
  14. package/dist/connection/index.js +4 -5
  15. package/dist/{connection-B_K2ZAf7.js → connection-Dmhgx31M.js} +5 -7
  16. package/dist/{connection-B_K2ZAf7.js.map → connection-Dmhgx31M.js.map} +1 -1
  17. package/dist/{defaultRuntime-BPK9kWEW.js → defaultRuntime-DzqBQ9Hb.js} +63 -16
  18. package/dist/defaultRuntime-DzqBQ9Hb.js.map +1 -0
  19. package/dist/index.d.ts +3 -3
  20. package/dist/index.js +11 -12
  21. package/dist/manager/ModelManager.d.ts +25 -5
  22. package/dist/manager/index.d.ts +6 -0
  23. package/dist/manager/index.js +8 -7
  24. package/dist/manager/internal/MutationCompiler.d.ts +14 -6
  25. package/dist/manager/relations/ManyToManyRelatedManager.d.ts +147 -0
  26. package/dist/manager/relations/ManyToManyRelatedQuerySet.d.ts +62 -0
  27. package/dist/manager/relations/MaterializedModelRecord.d.ts +28 -0
  28. package/dist/manager/relations/index.d.ts +9 -0
  29. package/dist/manager/relations/internal/ThroughTableManager.d.ts +79 -0
  30. package/dist/manager-DrDTiCAz.js +24 -0
  31. package/dist/manager-DrDTiCAz.js.map +1 -0
  32. package/dist/query/ModelQuerySet.d.ts +20 -0
  33. package/dist/query/QBuilder.d.ts +3 -3
  34. package/dist/query/QuerySet.d.ts +49 -21
  35. package/dist/query/compiler/QueryCompiler.d.ts +13 -4
  36. package/dist/query/domain/CompiledQuery.d.ts +169 -2
  37. package/dist/query/domain/FilterInput.d.ts +1 -1
  38. package/dist/query/domain/FilterKey.d.ts +4 -2
  39. package/dist/query/domain/QNode.d.ts +4 -4
  40. package/dist/query/domain/QuerySetState.d.ts +3 -3
  41. package/dist/query/domain/RelationMeta.d.ts +9 -0
  42. package/dist/query/domain/RelationTyping.d.ts +47 -0
  43. package/dist/query/domain/TableMetaFactory.d.ts +1 -14
  44. package/dist/query/domain/index.d.ts +1 -1
  45. package/dist/query/domain/internal/InternalPrefetchQueryKind.d.ts +20 -0
  46. package/dist/query/index.d.ts +1 -0
  47. package/dist/query/index.js +3 -2
  48. package/dist/query/planning/QueryPlanner.d.ts +1 -1
  49. package/dist/{query-FZJoSCg4.js → query-DUZnBFhf.js} +425 -166
  50. package/dist/query-DUZnBFhf.js.map +1 -0
  51. package/dist/registerModelObjects-DxlBfuUN.js +797 -0
  52. package/dist/registerModelObjects-DxlBfuUN.js.map +1 -0
  53. package/dist/runtime/TangoRuntime.d.ts +9 -0
  54. package/dist/runtime/index.d.ts +3 -2
  55. package/dist/runtime/index.js +7 -6
  56. package/dist/runtime/internal/SqliteDBClientProvider.d.ts +3 -0
  57. package/dist/{runtime-ByXbpVBS.js → runtime-1H88J3nN.js} +3 -3
  58. package/dist/runtime-1H88J3nN.js.map +1 -0
  59. package/dist/transaction/index.js +5 -4
  60. package/dist/{transaction-Cs0Z9tbW.js → transaction-ZhfDf-f8.js} +2 -2
  61. package/dist/{transaction-Cs0Z9tbW.js.map → transaction-ZhfDf-f8.js.map} +1 -1
  62. package/dist/validation/SQLValidationEngine.d.ts +22 -5
  63. package/dist/validation/SqlValidationPlan.d.ts +5 -4
  64. package/dist/validation/internal/InternalSqlValidationPlanKind.d.ts +25 -0
  65. package/dist/validation/internal/InternalValidatedFilterDescriptorKind.d.ts +4 -0
  66. package/package.json +6 -6
  67. package/dist/PostgresAdapter-BFdo_nIt.js +0 -4
  68. package/dist/PostgresAdapter-CMiEpHya.js +0 -49
  69. package/dist/PostgresAdapter-CMiEpHya.js.map +0 -1
  70. package/dist/PostgresClient-BQJZfEOT.js +0 -68
  71. package/dist/PostgresClient-BQJZfEOT.js.map +0 -1
  72. package/dist/SqliteAdapter-A-P9zUhP.js +0 -4
  73. package/dist/SqliteAdapter-CeqhyrPC.js +0 -44
  74. package/dist/SqliteAdapter-CeqhyrPC.js.map +0 -1
  75. package/dist/SqliteClient-CjOK9-ki.js.map +0 -1
  76. package/dist/defaultRuntime-BPK9kWEW.js.map +0 -1
  77. package/dist/manager-C6oJ2tAF.js +0 -13
  78. package/dist/manager-C6oJ2tAF.js.map +0 -1
  79. package/dist/query-FZJoSCg4.js.map +0 -1
  80. package/dist/registerModelObjects-C-1RbUHS.js +0 -385
  81. package/dist/registerModelObjects-C-1RbUHS.js.map +0 -1
  82. package/dist/runtime-ByXbpVBS.js.map +0 -1
@@ -0,0 +1,10 @@
1
+
2
+ //#region src/query/domain/internal/InternalDialect.ts
3
+ const InternalDialect = {
4
+ POSTGRES: "postgres",
5
+ SQLITE: "sqlite"
6
+ };
7
+
8
+ //#endregion
9
+ export { InternalDialect };
10
+ //# sourceMappingURL=InternalDialect-ClSaUNso.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InternalDialect-ClSaUNso.js","names":[],"sources":["../src/query/domain/internal/InternalDialect.ts"],"sourcesContent":["export const InternalDialect = {\n POSTGRES: 'postgres',\n SQLITE: 'sqlite',\n} as const;\n"],"mappings":";;MAAa,kBAAkB;CAC3B,UAAU;CACV,QAAQ;AACX"}
@@ -0,0 +1,4 @@
1
+ import { PostgresAdapter } from "./PostgresAdapter-DySFW6vy.js";
2
+ import "./InternalDialect-ClSaUNso.js";
3
+
4
+ export { PostgresAdapter };
@@ -0,0 +1,128 @@
1
+ import { InternalDialect } from "./InternalDialect-ClSaUNso.js";
2
+ import pg from "pg";
3
+
4
+ //#region src/connection/clients/dialects/PostgresClient.ts
5
+ var PostgresClient = class PostgresClient {
6
+ static BRAND = "tango.orm.postgres_client";
7
+ __tangoBrand = PostgresClient.BRAND;
8
+ constructor(client) {
9
+ this.client = client;
10
+ }
11
+ /**
12
+ * Narrow an unknown value to `PostgresClient`.
13
+ */
14
+ static isPostgresClient(value) {
15
+ return typeof value === "object" && value !== null && value.__tangoBrand === PostgresClient.BRAND;
16
+ }
17
+ /**
18
+ * Execute a SQL statement with optional bound parameters.
19
+ */
20
+ async query(sql, params) {
21
+ const result = await this.client.query(sql, params);
22
+ return { rows: result.rows };
23
+ }
24
+ /**
25
+ * Begin a database transaction.
26
+ */
27
+ async begin() {
28
+ await this.client.query("BEGIN");
29
+ }
30
+ /**
31
+ * Commit the active transaction.
32
+ */
33
+ async commit() {
34
+ await this.client.query("COMMIT");
35
+ }
36
+ /**
37
+ * Roll back the active transaction.
38
+ */
39
+ async rollback() {
40
+ await this.client.query("ROLLBACK");
41
+ }
42
+ /**
43
+ * Create a savepoint inside the active transaction.
44
+ */
45
+ async createSavepoint(name) {
46
+ await this.client.query(`SAVEPOINT ${name}`);
47
+ }
48
+ /**
49
+ * Release a previously-created savepoint.
50
+ */
51
+ async releaseSavepoint(name) {
52
+ await this.client.query(`RELEASE SAVEPOINT ${name}`);
53
+ }
54
+ /**
55
+ * Roll back the active transaction to a savepoint.
56
+ */
57
+ async rollbackToSavepoint(name) {
58
+ await this.client.query(`ROLLBACK TO SAVEPOINT ${name}`);
59
+ }
60
+ /**
61
+ * Release the leased PostgreSQL client back to its owning pool.
62
+ */
63
+ async close() {
64
+ this.client.release();
65
+ }
66
+ };
67
+
68
+ //#endregion
69
+ //#region src/connection/adapters/dialects/PostgresAdapter.ts
70
+ const { Pool } = pg;
71
+ var PostgresAdapter = class PostgresAdapter {
72
+ static BRAND = "tango.orm.postgres_adapter";
73
+ __tangoBrand = PostgresAdapter.BRAND;
74
+ name = "postgres";
75
+ dialect = InternalDialect.POSTGRES;
76
+ /**
77
+ * Declares capabilities of this database adapter.
78
+ * Used by the migration runner and query compiler to determine which
79
+ * SQL features can be safely used:
80
+ * - transactionalDDL: Postgres supports DDL inside transactions (safe rollback of schema changes)
81
+ * - concurrentIndex: Supports CREATE INDEX CONCURRENTLY (non-blocking index builds)
82
+ * - validateForeignKeys: Supports deferred FK validation via NOT VALID + VALIDATE CONSTRAINT
83
+ * - ignoreDuplicateInsert: Supports duplicate-safe insert semantics for manager-owned link writes
84
+ */
85
+ features = {
86
+ transactionalDDL: true,
87
+ concurrentIndex: true,
88
+ validateForeignKeys: true,
89
+ ignoreDuplicateInsert: true
90
+ };
91
+ placeholders = {
92
+ at(index) {
93
+ return `$${index}`;
94
+ },
95
+ list(count) {
96
+ return this.listFromOffset(count, 0);
97
+ },
98
+ listFromOffset(count, startOffset) {
99
+ return Array.from({ length: count }, (_value, index) => `$${startOffset + index + 1}`).join(", ");
100
+ }
101
+ };
102
+ /**
103
+ * Narrow an unknown value to `PostgresAdapter`.
104
+ */
105
+ static isPostgresAdapter(value) {
106
+ return typeof value === "object" && value !== null && value.__tangoBrand === PostgresAdapter.BRAND;
107
+ }
108
+ /**
109
+ * Open a Postgres connection pool and return a client-backed DB abstraction.
110
+ */
111
+ async connect(config) {
112
+ const pool = new Pool({
113
+ connectionString: config.url,
114
+ host: config.host,
115
+ port: config.port,
116
+ database: config.database,
117
+ user: config.user,
118
+ password: config.password,
119
+ max: config.maxConnections || 10
120
+ });
121
+ const client = await pool.connect();
122
+ return new PostgresClient(client);
123
+ }
124
+ };
125
+
126
+ //#endregion
127
+ export { PostgresAdapter, PostgresClient };
128
+ //# sourceMappingURL=PostgresAdapter-DySFW6vy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresAdapter-DySFW6vy.js","names":["client: PostgresPoolClientLike","value: unknown","sql: string","params?: readonly unknown[]","name: string","index: number","count: number","startOffset: number","value: unknown","config: AdapterConfig"],"sources":["../src/connection/clients/dialects/PostgresClient.ts","../src/connection/adapters/dialects/PostgresAdapter.ts"],"sourcesContent":["import type { DBClient } from '../DBClient';\n\nexport interface PostgresPoolClientLike {\n query(sql: string, params?: readonly unknown[]): Promise<{ rows: unknown[] }>;\n release(): void;\n}\n\n/**\n * Transaction-capable client 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(private client: PostgresPoolClientLike) {}\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 * Create a savepoint inside the active transaction.\n */\n async createSavepoint(name: string): Promise<void> {\n await this.client.query(`SAVEPOINT ${name}`);\n }\n\n /**\n * Release a previously-created savepoint.\n */\n async releaseSavepoint(name: string): Promise<void> {\n await this.client.query(`RELEASE SAVEPOINT ${name}`);\n }\n\n /**\n * Roll back the active transaction to a savepoint.\n */\n async rollbackToSavepoint(name: string): Promise<void> {\n await this.client.query(`ROLLBACK TO SAVEPOINT ${name}`);\n }\n\n /**\n * Release the leased PostgreSQL client back to its owning pool.\n */\n async close(): Promise<void> {\n this.client.release();\n }\n}\n","import pg from 'pg';\nimport type { Adapter, AdapterConfig, SqlPlaceholders } from '../Adapter';\nimport type { DBClient } from '../../clients/DBClient';\nimport { PostgresClient } from '../../clients/dialects/PostgresClient';\nimport { InternalDialect } from '../../../query/domain/internal/InternalDialect';\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 readonly dialect: Adapter['dialect'] = InternalDialect.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 * - ignoreDuplicateInsert: Supports duplicate-safe insert semantics for manager-owned link writes\n */\n readonly features: Adapter['features'] = {\n transactionalDDL: true,\n concurrentIndex: true,\n validateForeignKeys: true,\n ignoreDuplicateInsert: true,\n };\n readonly placeholders: SqlPlaceholders = {\n at(index: number): string {\n return `$${index}`;\n },\n list(count: number): string {\n return this.listFromOffset(count, 0);\n },\n listFromOffset(count: number, startOffset: number): string {\n return Array.from({ length: count }, (_value, index) => `$${startOffset + index + 1}`).join(', ');\n },\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(client);\n }\n}\n"],"mappings":";;;;IAUa,iBAAN,MAAM,eAAmC;CAC5C,OAAgB,QAAQ;CACxB,eAAqD,eAAe;CAEpE,YAAoBA,QAAgC;AAAA,OAAhC,SAAA;CAAkC;;;;CAKtD,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,gBAAgBC,MAA6B;AAC/C,QAAM,KAAK,OAAO,OAAO,YAAY,KAAK,EAAE;CAC/C;;;;CAKD,MAAM,iBAAiBA,MAA6B;AAChD,QAAM,KAAK,OAAO,OAAO,oBAAoB,KAAK,EAAE;CACvD;;;;CAKD,MAAM,oBAAoBA,MAA6B;AACnD,QAAM,KAAK,OAAO,OAAO,wBAAwB,KAAK,EAAE;CAC3D;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,OAAO,SAAS;CACxB;AACJ;;;;AC7ED,MAAM,EAAE,MAAM,GAAG;IAKJ,kBAAN,MAAM,gBAAmC;CAC5C,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;CACtE,OAAgB;CAChB,UAAuC,gBAAgB;;;;;;;;;;CAUvD,WAAyC;EACrC,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB;EACrB,uBAAuB;CAC1B;CACD,eAAyC;EACrC,GAAGC,OAAuB;AACtB,WAAQ,GAAG,MAAM;EACpB;EACD,KAAKC,OAAuB;AACxB,UAAO,KAAK,eAAe,OAAO,EAAE;EACvC;EACD,eAAeA,OAAeC,aAA6B;AACvD,UAAO,MAAM,KAAK,EAAE,QAAQ,MAAO,GAAE,CAAC,QAAQ,WAAW,GAAG,cAAc,QAAQ,EAAE,EAAE,CAAC,KAAK,KAAK;EACpG;CACJ;;;;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;CAC7B;AACJ"}
@@ -1,3 +1,5 @@
1
+ import { InternalDialect } from "./InternalDialect-ClSaUNso.js";
2
+ import { createRequire } from "node:module";
1
3
 
2
4
  //#region src/connection/clients/dialects/SqliteClient.ts
3
5
  var SqliteClient = class SqliteClient {
@@ -36,7 +38,7 @@ else stmt.run();
36
38
  */
37
39
  async begin() {
38
40
  if (!this.inTransaction) {
39
- this.db.prepare("BEGIN").run();
41
+ this.db.prepare("BEGIN IMMEDIATE").run();
40
42
  this.inTransaction = true;
41
43
  }
42
44
  }
@@ -93,5 +95,57 @@ function isDateValue(value) {
93
95
  }
94
96
 
95
97
  //#endregion
96
- export { SqliteClient };
97
- //# sourceMappingURL=SqliteClient-CjOK9-ki.js.map
98
+ //#region src/connection/adapters/dialects/SqliteAdapter.ts
99
+ var SqliteAdapter = class SqliteAdapter {
100
+ static BRAND = "tango.orm.sqlite_adapter";
101
+ __tangoBrand = SqliteAdapter.BRAND;
102
+ name = "sqlite";
103
+ dialect = InternalDialect.SQLITE;
104
+ features = {
105
+ transactionalDDL: true,
106
+ concurrentIndex: false,
107
+ validateForeignKeys: false,
108
+ ignoreDuplicateInsert: true
109
+ };
110
+ placeholders = {
111
+ at() {
112
+ return "?";
113
+ },
114
+ list(count) {
115
+ return Array.from({ length: count }, () => "?").join(", ");
116
+ },
117
+ listFromOffset(count) {
118
+ return this.list(count);
119
+ }
120
+ };
121
+ /**
122
+ * Narrow an unknown value to `SqliteAdapter`.
123
+ */
124
+ static isSqliteAdapter(value) {
125
+ return typeof value === "object" && value !== null && value.__tangoBrand === SqliteAdapter.BRAND;
126
+ }
127
+ /**
128
+ * Open a SQLite database and apply baseline pragmas for durability/safety.
129
+ */
130
+ async connect(config = {}) {
131
+ const Database = this.getDatabaseCtor();
132
+ const filename = typeof config.filename === "string" && config.filename.length > 0 ? config.filename : ":memory:";
133
+ const db = new Database(filename);
134
+ db.pragma("journal_mode = WAL");
135
+ db.pragma("foreign_keys = ON");
136
+ db.pragma("busy_timeout = 5000");
137
+ return new SqliteClient(db);
138
+ }
139
+ getDatabaseCtor() {
140
+ const require = createRequire(import.meta.url);
141
+ const moduleValue = require("better-sqlite3");
142
+ if (typeof moduleValue === "function") return moduleValue;
143
+ const defaultExport = moduleValue.default;
144
+ if (typeof defaultExport === "function") return defaultExport;
145
+ throw new TypeError("Failed to load better-sqlite3 constructor.");
146
+ }
147
+ };
148
+
149
+ //#endregion
150
+ export { SqliteAdapter, SqliteClient };
151
+ //# sourceMappingURL=SqliteAdapter-CDdOjRmW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqliteAdapter-CDdOjRmW.js","names":["db: Database.Database","value: unknown","sql: string","params?: readonly unknown[]","name: string","count: number","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 * Transaction-capable client 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 IMMEDIATE').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 * Create a savepoint inside the active transaction.\n */\n async createSavepoint(name: string): Promise<void> {\n this.db.prepare(`SAVEPOINT ${name}`).run();\n }\n\n /**\n * Release a previously-created savepoint.\n */\n async releaseSavepoint(name: string): Promise<void> {\n this.db.prepare(`RELEASE SAVEPOINT ${name}`).run();\n }\n\n /**\n * Roll back the active transaction to a savepoint.\n */\n async rollbackToSavepoint(name: string): Promise<void> {\n this.db.prepare(`ROLLBACK TO SAVEPOINT ${name}`).run();\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, SqlPlaceholders } from '../Adapter';\nimport type { DBClient } from '../../clients/DBClient';\nimport { SqliteClient } from '../../clients/dialects/SqliteClient';\nimport { InternalDialect } from '../../../query/domain/internal/InternalDialect';\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 dialect: Adapter['dialect'] = InternalDialect.SQLITE;\n readonly features: Adapter['features'] = {\n transactionalDDL: true,\n concurrentIndex: false,\n validateForeignKeys: false,\n ignoreDuplicateInsert: true,\n };\n readonly placeholders: SqlPlaceholders = {\n at(): string {\n return '?';\n },\n list(count: number): string {\n return Array.from({ length: count }, () => '?').join(', ');\n },\n listFromOffset(count: number): string {\n return this.list(count);\n },\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 db.pragma('busy_timeout = 5000');\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":"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"}
@@ -0,0 +1,4 @@
1
+ import "./InternalDialect-ClSaUNso.js";
2
+ import { SqliteAdapter } from "./SqliteAdapter-CDdOjRmW.js";
3
+
4
+ export { SqliteAdapter };
@@ -1,4 +1,5 @@
1
1
  import type { DBClient } from '../clients/DBClient';
2
+ import type { Dialect } from '../../query/domain/Dialect';
2
3
  /**
3
4
  * Connection options shared by built-in DB adapters.
4
5
  */
@@ -13,11 +14,38 @@ export interface AdapterConfig {
13
14
  maxConnections?: number;
14
15
  }
15
16
  /**
16
- * Runtime adapter contract for establishing `DBClient` connections.
17
+ * Dialect-aware SQL parameter placeholder generator supplied by an
18
+ * {@link Adapter}. Consolidates the `$N` vs `?` decision on the adapter so
19
+ * compilers and manager-side SQL builders do not branch on dialect to emit
20
+ * parameter placeholders.
21
+ */
22
+ export interface SqlPlaceholders {
23
+ /** Placeholder for a single parameter at the given 1-based index. */
24
+ at(index: number): string;
25
+ /** Comma-joined placeholder list for `count` parameters numbered starting at 1. */
26
+ list(count: number): string;
27
+ /**
28
+ * Comma-joined placeholder list for `count` parameters, skipping the
29
+ * first `startOffset` placeholder positions. Used when a statement
30
+ * already bound some parameters before the list (for example, an
31
+ * `UPDATE ... WHERE` clause).
32
+ */
33
+ listFromOffset(count: number, startOffset: number): string;
34
+ }
35
+ /**
36
+ * Runtime adapter contract for establishing `DBClient` connections and
37
+ * supplying dialect-specific SQL primitives (placeholders, feature flags)
38
+ * to manager-side compilers.
17
39
  */
18
40
  export interface Adapter {
19
41
  /** Stable adapter name used in configuration and registry lookup. */
20
42
  name: string;
43
+ /**
44
+ * Declared SQL dialect this adapter targets. Consumers branch on the
45
+ * adapter, not on a free-standing dialect string, so dialect-awareness
46
+ * is funnelled through the adapter interface.
47
+ */
48
+ dialect: Dialect;
21
49
  /** Open a database connection and return a client abstraction. */
22
50
  connect(config: AdapterConfig): Promise<DBClient>;
23
51
  /** SQL capability flags used by migrations/query orchestration. */
@@ -25,5 +53,8 @@ export interface Adapter {
25
53
  transactionalDDL: boolean;
26
54
  concurrentIndex: boolean;
27
55
  validateForeignKeys: boolean;
56
+ ignoreDuplicateInsert: boolean;
28
57
  };
58
+ /** Dialect-aware SQL parameter placeholder generator. */
59
+ placeholders: SqlPlaceholders;
29
60
  }
@@ -1,4 +1,4 @@
1
- import type { Adapter, AdapterConfig } from '../Adapter';
1
+ import type { Adapter, AdapterConfig, SqlPlaceholders } from '../Adapter';
2
2
  import type { DBClient } from '../../clients/DBClient';
3
3
  /**
4
4
  * Postgres adapter that turns adapter config into a transactional `DBClient`.
@@ -7,6 +7,7 @@ export declare class PostgresAdapter implements Adapter {
7
7
  static readonly BRAND: "tango.orm.postgres_adapter";
8
8
  readonly __tangoBrand: typeof PostgresAdapter.BRAND;
9
9
  readonly name = "postgres";
10
+ readonly dialect: Adapter['dialect'];
10
11
  /**
11
12
  * Declares capabilities of this database adapter.
12
13
  * Used by the migration runner and query compiler to determine which
@@ -14,12 +15,10 @@ export declare class PostgresAdapter implements Adapter {
14
15
  * - transactionalDDL: Postgres supports DDL inside transactions (safe rollback of schema changes)
15
16
  * - concurrentIndex: Supports CREATE INDEX CONCURRENTLY (non-blocking index builds)
16
17
  * - validateForeignKeys: Supports deferred FK validation via NOT VALID + VALIDATE CONSTRAINT
18
+ * - ignoreDuplicateInsert: Supports duplicate-safe insert semantics for manager-owned link writes
17
19
  */
18
- readonly features: {
19
- transactionalDDL: boolean;
20
- concurrentIndex: boolean;
21
- validateForeignKeys: boolean;
22
- };
20
+ readonly features: Adapter['features'];
21
+ readonly placeholders: SqlPlaceholders;
23
22
  /**
24
23
  * Narrow an unknown value to `PostgresAdapter`.
25
24
  */
@@ -1,4 +1,4 @@
1
- import type { Adapter, AdapterConfig } from '../Adapter';
1
+ import type { Adapter, AdapterConfig, SqlPlaceholders } from '../Adapter';
2
2
  import type { DBClient } from '../../clients/DBClient';
3
3
  /**
4
4
  * SQLite adapter that creates a `better-sqlite3` backed `DBClient`.
@@ -7,11 +7,9 @@ export declare class SqliteAdapter implements Adapter {
7
7
  static readonly BRAND: "tango.orm.sqlite_adapter";
8
8
  readonly __tangoBrand: typeof SqliteAdapter.BRAND;
9
9
  readonly name = "sqlite";
10
- readonly features: {
11
- transactionalDDL: boolean;
12
- concurrentIndex: boolean;
13
- validateForeignKeys: boolean;
14
- };
10
+ readonly dialect: Adapter['dialect'];
11
+ readonly features: Adapter['features'];
12
+ readonly placeholders: SqlPlaceholders;
15
13
  /**
16
14
  * Narrow an unknown value to `SqliteAdapter`.
17
15
  */
@@ -4,5 +4,5 @@
4
4
  */
5
5
  export * as dialects from './dialects/index';
6
6
  export { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './AdapterRegistry';
7
- export type { Adapter, AdapterConfig } from './Adapter';
7
+ export type { Adapter, AdapterConfig, SqlPlaceholders } from './Adapter';
8
8
  export { PostgresAdapter, SqliteAdapter } from './dialects/index';
@@ -5,7 +5,7 @@
5
5
  export * as adapters from './adapters/index';
6
6
  export * as clients from './clients/index';
7
7
  export { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './adapters/index';
8
- export type { Adapter, AdapterConfig } from './adapters/index';
8
+ export type { Adapter, AdapterConfig, SqlPlaceholders } from './adapters/index';
9
9
  export type { DBClient } from './clients/DBClient';
10
10
  export { PostgresAdapter, SqliteAdapter } from './adapters/index';
11
11
  export { PostgresClient, SqliteClient } from './clients/index';
@@ -1,7 +1,6 @@
1
- import { PostgresClient } from "../PostgresClient-BQJZfEOT.js";
2
- import { PostgresAdapter } from "../PostgresAdapter-CMiEpHya.js";
3
- import { SqliteClient } from "../SqliteClient-CjOK9-ki.js";
4
- import { SqliteAdapter } from "../SqliteAdapter-CeqhyrPC.js";
5
- import { AdapterRegistry, adapters_exports, clients_exports, connectDB, getDefaultAdapterRegistry } from "../connection-B_K2ZAf7.js";
1
+ import { PostgresAdapter, PostgresClient } from "../PostgresAdapter-DySFW6vy.js";
2
+ import "../InternalDialect-ClSaUNso.js";
3
+ import { SqliteAdapter, SqliteClient } from "../SqliteAdapter-CDdOjRmW.js";
4
+ import { AdapterRegistry, adapters_exports, clients_exports, connectDB, getDefaultAdapterRegistry } from "../connection-Dmhgx31M.js";
6
5
 
7
6
  export { AdapterRegistry, PostgresAdapter, PostgresClient, SqliteAdapter, SqliteClient, adapters_exports as adapters, clients_exports as clients, connectDB, getDefaultAdapterRegistry };
@@ -1,8 +1,6 @@
1
1
  import { __export } from "./chunk-DLY2FNSh.js";
2
- import { PostgresClient } from "./PostgresClient-BQJZfEOT.js";
3
- import { PostgresAdapter } from "./PostgresAdapter-CMiEpHya.js";
4
- import { SqliteClient } from "./SqliteClient-CjOK9-ki.js";
5
- import { SqliteAdapter } from "./SqliteAdapter-CeqhyrPC.js";
2
+ import { PostgresAdapter, PostgresClient } from "./PostgresAdapter-DySFW6vy.js";
3
+ import { SqliteAdapter, SqliteClient } from "./SqliteAdapter-CDdOjRmW.js";
6
4
 
7
5
  //#region src/connection/adapters/dialects/index.ts
8
6
  var dialects_exports$1 = {};
@@ -30,8 +28,8 @@ var AdapterRegistry = class AdapterRegistry {
30
28
  static async getDefaultRegistry() {
31
29
  if (AdapterRegistry.defaultRegistryInstance) return AdapterRegistry.defaultRegistryInstance;
32
30
  AdapterRegistry.defaultRegistryInstance = new AdapterRegistry();
33
- const { PostgresAdapter: PostgresAdapter$1 } = await import("./PostgresAdapter-BFdo_nIt.js");
34
- const { SqliteAdapter: SqliteAdapter$1 } = await import("./SqliteAdapter-A-P9zUhP.js");
31
+ const { PostgresAdapter: PostgresAdapter$1 } = await import("./PostgresAdapter-CXKdKBG-.js");
32
+ const { SqliteAdapter: SqliteAdapter$1 } = await import("./SqliteAdapter-mjtXuVTg.js");
35
33
  AdapterRegistry.defaultRegistryInstance.register(new PostgresAdapter$1());
36
34
  AdapterRegistry.defaultRegistryInstance.register(new SqliteAdapter$1());
37
35
  return AdapterRegistry.defaultRegistryInstance;
@@ -116,4 +114,4 @@ __export(connection_exports, {
116
114
 
117
115
  //#endregion
118
116
  export { AdapterRegistry, adapters_exports, clients_exports, connectDB, connection_exports, getDefaultAdapterRegistry };
119
- //# sourceMappingURL=connection-B_K2ZAf7.js.map
117
+ //# sourceMappingURL=connection-Dmhgx31M.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection-B_K2ZAf7.js","names":["value: unknown","adapter: Adapter","name: string","config: AdapterConfig & { adapter: string }","registry?: AdapterRegistry"],"sources":["../src/connection/adapters/dialects/index.ts","../src/connection/adapters/AdapterRegistry.ts","../src/connection/adapters/index.ts","../src/connection/clients/dialects/index.ts","../src/connection/clients/index.ts","../src/connection/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { PostgresAdapter } from './PostgresAdapter';\nexport { SqliteAdapter } from './SqliteAdapter';\n","import type { Adapter, AdapterConfig } from './Adapter';\nimport type { DBClient } from '../clients/DBClient';\n\n/**\n * Runtime registry for database adapters.\n *\n * Use a custom instance when tests or applications need explicit control\n * over supported adapters; use `getDefaultRegistry()` for the built-in set.\n */\nexport class AdapterRegistry {\n static readonly BRAND = 'tango.orm.adapter_registry' as const;\n private static defaultRegistryInstance: AdapterRegistry | undefined;\n readonly __tangoBrand: typeof AdapterRegistry.BRAND = AdapterRegistry.BRAND;\n private adapters = new Map<string, Adapter>();\n\n /**\n * Narrow an unknown value to `AdapterRegistry`.\n */\n static isAdapterRegistry(value: unknown): value is AdapterRegistry {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === AdapterRegistry.BRAND\n );\n }\n\n /**\n * Return a lazily-initialized registry preloaded with built-in adapters.\n */\n static async getDefaultRegistry(): Promise<AdapterRegistry> {\n if (AdapterRegistry.defaultRegistryInstance) {\n return AdapterRegistry.defaultRegistryInstance;\n }\n\n AdapterRegistry.defaultRegistryInstance = new AdapterRegistry();\n\n const { PostgresAdapter } = await import('./dialects/PostgresAdapter');\n const { SqliteAdapter } = await import('./dialects/SqliteAdapter');\n\n AdapterRegistry.defaultRegistryInstance.register(new PostgresAdapter());\n AdapterRegistry.defaultRegistryInstance.register(new SqliteAdapter());\n\n return AdapterRegistry.defaultRegistryInstance;\n }\n\n /**\n * Register an adapter under its declared `name`.\n */\n register(adapter: Adapter): this {\n this.adapters.set(adapter.name, adapter);\n return this;\n }\n\n /**\n * Resolve an adapter by name, or throw a descriptive error.\n */\n get(name: string): Adapter {\n const adapter = this.adapters.get(name);\n if (!adapter) {\n const available = [...this.adapters.keys()].join(', ');\n throw new Error(`Unknown adapter: ${name}. Available adapters: ${available || 'none'}`);\n }\n return adapter;\n }\n\n /**\n * Check whether an adapter has been registered.\n */\n has(name: string): boolean {\n return this.adapters.has(name);\n }\n}\n\n/**\n * Connect to a database by adapter name using the provided (or default) registry.\n */\nexport async function connectDB(\n config: AdapterConfig & { adapter: string },\n registry?: AdapterRegistry\n): Promise<DBClient> {\n const effectiveRegistry = registry ?? (await AdapterRegistry.getDefaultRegistry());\n const adapter = effectiveRegistry.get(config.adapter);\n return adapter.connect(config);\n}\n\n/**\n * Convenience helper that exposes the singleton default adapter registry.\n */\nexport async function getDefaultAdapterRegistry(): Promise<AdapterRegistry> {\n return AdapterRegistry.getDefaultRegistry();\n}\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as dialects from './dialects/index';\n\nexport { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './AdapterRegistry';\nexport type { Adapter, AdapterConfig } from './Adapter';\nexport { PostgresAdapter, SqliteAdapter } from './dialects/index';\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { PostgresClient } from './PostgresClient';\nexport { SqliteClient } from './SqliteClient';\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as dialects from './dialects/index';\n\nexport type { DBClient } from './DBClient';\nexport { PostgresClient, SqliteClient } from './dialects/index';\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as adapters from './adapters/index';\nexport * as clients from './clients/index';\n\nexport { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './adapters/index';\nexport type { Adapter, AdapterConfig } from './adapters/index';\nexport type { DBClient } from './clients/DBClient';\nexport { PostgresAdapter, SqliteAdapter } from './adapters/index';\nexport { PostgresClient, SqliteClient } from './clients/index';\n"],"mappings":";;;;;;;;;;;;;;;ICSa,kBAAN,MAAM,gBAAgB;CACzB,OAAgB,QAAQ;CACxB,OAAe;CACf,eAAsD,gBAAgB;CACtE,WAAmB,IAAI;;;;CAKvB,OAAO,kBAAkBA,OAA0C;AAC/D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE9E;;;;CAKD,aAAa,qBAA+C;AACxD,MAAI,gBAAgB,wBAChB,QAAO,gBAAgB;AAG3B,kBAAgB,0BAA0B,IAAI;EAE9C,MAAM,EAAE,oCAAiB,GAAG,MAAM,OAAO;EACzC,MAAM,EAAE,gCAAe,GAAG,MAAM,OAAO;AAEvC,kBAAgB,wBAAwB,SAAS,IAAI,oBAAkB;AACvE,kBAAgB,wBAAwB,SAAS,IAAI,kBAAgB;AAErE,SAAO,gBAAgB;CAC1B;;;;CAKD,SAASC,SAAwB;AAC7B,OAAK,SAAS,IAAI,QAAQ,MAAM,QAAQ;AACxC,SAAO;CACV;;;;CAKD,IAAIC,MAAuB;EACvB,MAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AACvC,OAAK,SAAS;GACV,MAAM,YAAY,CAAC,GAAG,KAAK,SAAS,MAAM,AAAC,EAAC,KAAK,KAAK;AACtD,SAAM,IAAI,OAAO,mBAAmB,KAAK,wBAAwB,aAAa,OAAO;EACxF;AACD,SAAO;CACV;;;;CAKD,IAAIA,MAAuB;AACvB,SAAO,KAAK,SAAS,IAAI,KAAK;CACjC;AACJ;AAKM,eAAe,UAClBC,QACAC,UACiB;CACjB,MAAM,oBAAoB,YAAa,MAAM,gBAAgB,oBAAoB;CACjF,MAAM,UAAU,kBAAkB,IAAI,OAAO,QAAQ;AACrD,QAAO,QAAQ,QAAQ,OAAO;AACjC;AAKM,eAAe,4BAAsD;AACxE,QAAO,gBAAgB,oBAAoB;AAC9C"}
1
+ {"version":3,"file":"connection-Dmhgx31M.js","names":["value: unknown","adapter: Adapter","name: string","config: AdapterConfig & { adapter: string }","registry?: AdapterRegistry"],"sources":["../src/connection/adapters/dialects/index.ts","../src/connection/adapters/AdapterRegistry.ts","../src/connection/adapters/index.ts","../src/connection/clients/dialects/index.ts","../src/connection/clients/index.ts","../src/connection/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { PostgresAdapter } from './PostgresAdapter';\nexport { SqliteAdapter } from './SqliteAdapter';\n","import type { Adapter, AdapterConfig } from './Adapter';\nimport type { DBClient } from '../clients/DBClient';\n\n/**\n * Runtime registry for database adapters.\n *\n * Use a custom instance when tests or applications need explicit control\n * over supported adapters; use `getDefaultRegistry()` for the built-in set.\n */\nexport class AdapterRegistry {\n static readonly BRAND = 'tango.orm.adapter_registry' as const;\n private static defaultRegistryInstance: AdapterRegistry | undefined;\n readonly __tangoBrand: typeof AdapterRegistry.BRAND = AdapterRegistry.BRAND;\n private adapters = new Map<string, Adapter>();\n\n /**\n * Narrow an unknown value to `AdapterRegistry`.\n */\n static isAdapterRegistry(value: unknown): value is AdapterRegistry {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === AdapterRegistry.BRAND\n );\n }\n\n /**\n * Return a lazily-initialized registry preloaded with built-in adapters.\n */\n static async getDefaultRegistry(): Promise<AdapterRegistry> {\n if (AdapterRegistry.defaultRegistryInstance) {\n return AdapterRegistry.defaultRegistryInstance;\n }\n\n AdapterRegistry.defaultRegistryInstance = new AdapterRegistry();\n\n const { PostgresAdapter } = await import('./dialects/PostgresAdapter');\n const { SqliteAdapter } = await import('./dialects/SqliteAdapter');\n\n AdapterRegistry.defaultRegistryInstance.register(new PostgresAdapter());\n AdapterRegistry.defaultRegistryInstance.register(new SqliteAdapter());\n\n return AdapterRegistry.defaultRegistryInstance;\n }\n\n /**\n * Register an adapter under its declared `name`.\n */\n register(adapter: Adapter): this {\n this.adapters.set(adapter.name, adapter);\n return this;\n }\n\n /**\n * Resolve an adapter by name, or throw a descriptive error.\n */\n get(name: string): Adapter {\n const adapter = this.adapters.get(name);\n if (!adapter) {\n const available = [...this.adapters.keys()].join(', ');\n throw new Error(`Unknown adapter: ${name}. Available adapters: ${available || 'none'}`);\n }\n return adapter;\n }\n\n /**\n * Check whether an adapter has been registered.\n */\n has(name: string): boolean {\n return this.adapters.has(name);\n }\n}\n\n/**\n * Connect to a database by adapter name using the provided (or default) registry.\n */\nexport async function connectDB(\n config: AdapterConfig & { adapter: string },\n registry?: AdapterRegistry\n): Promise<DBClient> {\n const effectiveRegistry = registry ?? (await AdapterRegistry.getDefaultRegistry());\n const adapter = effectiveRegistry.get(config.adapter);\n return adapter.connect(config);\n}\n\n/**\n * Convenience helper that exposes the singleton default adapter registry.\n */\nexport async function getDefaultAdapterRegistry(): Promise<AdapterRegistry> {\n return AdapterRegistry.getDefaultRegistry();\n}\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as dialects from './dialects/index';\n\nexport { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './AdapterRegistry';\nexport type { Adapter, AdapterConfig, SqlPlaceholders } from './Adapter';\nexport { PostgresAdapter, SqliteAdapter } from './dialects/index';\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { PostgresClient } from './PostgresClient';\nexport { SqliteClient } from './SqliteClient';\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as dialects from './dialects/index';\n\nexport type { DBClient } from './DBClient';\nexport { PostgresClient, SqliteClient } from './dialects/index';\n","/**\n * Domain boundary barrel: exposes namespaced exports for Django-style drill-down\n * imports and curated flat exports for TS-native ergonomics.\n */\n\nexport * as adapters from './adapters/index';\nexport * as clients from './clients/index';\n\nexport { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './adapters/index';\nexport type { Adapter, AdapterConfig, SqlPlaceholders } from './adapters/index';\nexport type { DBClient } from './clients/DBClient';\nexport { PostgresAdapter, SqliteAdapter } from './adapters/index';\nexport { PostgresClient, SqliteClient } from './clients/index';\n"],"mappings":";;;;;;;;;;;;;ICSa,kBAAN,MAAM,gBAAgB;CACzB,OAAgB,QAAQ;CACxB,OAAe;CACf,eAAsD,gBAAgB;CACtE,WAAmB,IAAI;;;;CAKvB,OAAO,kBAAkBA,OAA0C;AAC/D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE9E;;;;CAKD,aAAa,qBAA+C;AACxD,MAAI,gBAAgB,wBAChB,QAAO,gBAAgB;AAG3B,kBAAgB,0BAA0B,IAAI;EAE9C,MAAM,EAAE,oCAAiB,GAAG,MAAM,OAAO;EACzC,MAAM,EAAE,gCAAe,GAAG,MAAM,OAAO;AAEvC,kBAAgB,wBAAwB,SAAS,IAAI,oBAAkB;AACvE,kBAAgB,wBAAwB,SAAS,IAAI,kBAAgB;AAErE,SAAO,gBAAgB;CAC1B;;;;CAKD,SAASC,SAAwB;AAC7B,OAAK,SAAS,IAAI,QAAQ,MAAM,QAAQ;AACxC,SAAO;CACV;;;;CAKD,IAAIC,MAAuB;EACvB,MAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AACvC,OAAK,SAAS;GACV,MAAM,YAAY,CAAC,GAAG,KAAK,SAAS,MAAM,AAAC,EAAC,KAAK,KAAK;AACtD,SAAM,IAAI,OAAO,mBAAmB,KAAK,wBAAwB,aAAa,OAAO;EACxF;AACD,SAAO;CACV;;;;CAKD,IAAIA,MAAuB;AACvB,SAAO,KAAK,SAAS,IAAI,KAAK;CACjC;AACJ;AAKM,eAAe,UAClBC,QACAC,UACiB;CACjB,MAAM,oBAAoB,YAAa,MAAM,gBAAgB,oBAAoB;CACjF,MAAM,UAAU,kBAAkB,IAAI,OAAO,QAAQ;AACrD,QAAO,QAAQ,QAAQ,OAAO;AACjC;AAKM,eAAe,4BAAsD;AACxE,QAAO,gBAAgB,oBAAoB;AAC9C"}
@@ -1,5 +1,6 @@
1
- import { PostgresClient } from "./PostgresClient-BQJZfEOT.js";
2
- import { SqliteClient } from "./SqliteClient-CjOK9-ki.js";
1
+ import { PostgresAdapter, PostgresClient } from "./PostgresAdapter-DySFW6vy.js";
2
+ import { InternalDialect } from "./InternalDialect-ClSaUNso.js";
3
+ import { SqliteAdapter, SqliteClient } from "./SqliteAdapter-CDdOjRmW.js";
3
4
  import pg from "pg";
4
5
  import { createRequire } from "node:module";
5
6
  import { getLogger } from "@danceroutine/tango-core";
@@ -288,28 +289,39 @@ var SqliteDBClientProvider = class {
288
289
  Database;
289
290
  autocommitClient;
290
291
  activeLeaseCount = 0;
292
+ exclusiveTail = Promise.resolve();
291
293
  constructor(config = {}) {
292
294
  this.Database = this.getDatabaseCtor();
293
295
  this.filename = typeof config.filename === "string" && config.filename.length > 0 ? config.filename : ":memory:";
294
296
  this.autocommitClient = this.openClient(this.filename);
295
297
  }
296
298
  async query(sql, params) {
297
- return this.autocommitClient.query(sql, params);
299
+ return this.runExclusive(() => this.autocommitClient.query(sql, params));
298
300
  }
299
301
  async leaseTransactionClient() {
300
302
  if (this.filename === ":memory:") throw new Error("transaction.atomic(...) requires a file-backed SQLite database. :memory: is unsupported.");
301
- const client = this.openClient(this.filename);
302
- this.activeLeaseCount += 1;
303
- let released = false;
304
- return {
305
- client,
306
- release: async () => {
307
- if (released) return;
308
- released = true;
309
- this.activeLeaseCount -= 1;
310
- await client.close();
311
- }
312
- };
303
+ const releaseExclusive = await this.acquireExclusive();
304
+ try {
305
+ const client = this.openClient(this.filename);
306
+ this.activeLeaseCount += 1;
307
+ let released = false;
308
+ return {
309
+ client,
310
+ release: async () => {
311
+ if (released) return;
312
+ released = true;
313
+ this.activeLeaseCount -= 1;
314
+ try {
315
+ await client.close();
316
+ } finally {
317
+ releaseExclusive();
318
+ }
319
+ }
320
+ };
321
+ } catch (error) {
322
+ releaseExclusive();
323
+ throw error;
324
+ }
313
325
  }
314
326
  async reset() {
315
327
  if (this.activeLeaseCount > 0) throw new Error("Cannot reset Tango runtime while transaction leases are still active.");
@@ -322,6 +334,25 @@ var SqliteDBClientProvider = class {
322
334
  db.pragma("busy_timeout = 5000");
323
335
  return new SqliteClient(db);
324
336
  }
337
+ async runExclusive(work) {
338
+ const release = await this.acquireExclusive();
339
+ try {
340
+ return await work();
341
+ } finally {
342
+ release();
343
+ }
344
+ }
345
+ async acquireExclusive() {
346
+ const previous = this.exclusiveTail;
347
+ let release = null;
348
+ this.exclusiveTail = new Promise((resolve) => {
349
+ release = resolve;
350
+ });
351
+ await previous;
352
+ return () => {
353
+ release?.();
354
+ };
355
+ }
325
356
  getDatabaseCtor() {
326
357
  const require = createRequire(import.meta.url);
327
358
  const moduleValue = require("better-sqlite3");
@@ -350,6 +381,7 @@ var TangoRuntime = class TangoRuntime {
350
381
  loadedConfig;
351
382
  providerPromise = null;
352
383
  runtimeClientPromise = null;
384
+ cachedAdapter = null;
353
385
  constructor(loadLoadedConfig) {
354
386
  this.loadedConfig = loadLoadedConfig();
355
387
  }
@@ -372,6 +404,15 @@ var TangoRuntime = class TangoRuntime {
372
404
  return this.loadedConfig.current.db.adapter;
373
405
  }
374
406
  /**
407
+ * Return the adapter backing the configured dialect. Manager-side
408
+ * compilers use this to obtain placeholder formatters and dialect
409
+ * capabilities without branching on the raw dialect string.
410
+ */
411
+ getAdapter() {
412
+ if (!this.cachedAdapter) this.cachedAdapter = this.buildAdapterForDialect(this.getDialect());
413
+ return this.cachedAdapter;
414
+ }
415
+ /**
375
416
  * Return the runtime-bound DB client facade used by manager-backed code.
376
417
  */
377
418
  async getClient() {
@@ -405,6 +446,12 @@ var TangoRuntime = class TangoRuntime {
405
446
  this.runtimeClientPromise = null;
406
447
  await provider.reset();
407
448
  }
449
+ buildAdapterForDialect(dialect) {
450
+ switch (dialect) {
451
+ case InternalDialect.POSTGRES: return new PostgresAdapter();
452
+ case InternalDialect.SQLITE: return new SqliteAdapter();
453
+ }
454
+ }
408
455
  async getProvider() {
409
456
  if (!this.providerPromise) {
410
457
  const db = this.loadedConfig.current.db;
@@ -444,4 +491,4 @@ async function resetTangoRuntime() {
444
491
 
445
492
  //#endregion
446
493
  export { RuntimeBoundClient, TangoRuntime, TransactionEngine, getTangoRuntime, initializeTangoRuntime, resetTangoRuntime };
447
- //# sourceMappingURL=defaultRuntime-BPK9kWEW.js.map
494
+ //# sourceMappingURL=defaultRuntime-DzqBQ9Hb.js.map