@danceroutine/tango-orm 1.6.0 → 1.8.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.
- package/dist/InternalDialect-ClSaUNso.js +10 -0
- package/dist/InternalDialect-ClSaUNso.js.map +1 -0
- package/dist/PostgresAdapter-CXKdKBG-.js +4 -0
- package/dist/PostgresAdapter-DySFW6vy.js +128 -0
- package/dist/PostgresAdapter-DySFW6vy.js.map +1 -0
- package/dist/{SqliteClient-CjOK9-ki.js → SqliteAdapter-CDdOjRmW.js} +57 -3
- package/dist/SqliteAdapter-CDdOjRmW.js.map +1 -0
- package/dist/SqliteAdapter-mjtXuVTg.js +4 -0
- package/dist/connection/adapters/Adapter.d.ts +32 -1
- package/dist/connection/adapters/dialects/PostgresAdapter.d.ts +5 -6
- package/dist/connection/adapters/dialects/SqliteAdapter.d.ts +4 -6
- package/dist/connection/adapters/index.d.ts +1 -1
- package/dist/connection/index.d.ts +1 -1
- package/dist/connection/index.js +4 -5
- package/dist/{connection-B_K2ZAf7.js → connection-Dmhgx31M.js} +5 -7
- package/dist/{connection-B_K2ZAf7.js.map → connection-Dmhgx31M.js.map} +1 -1
- package/dist/{defaultRuntime-BPK9kWEW.js → defaultRuntime-DzqBQ9Hb.js} +63 -16
- package/dist/defaultRuntime-DzqBQ9Hb.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +11 -12
- package/dist/manager/ManagerLike.d.ts +19 -0
- package/dist/manager/ModelManager.d.ts +45 -2
- package/dist/manager/index.d.ts +6 -0
- package/dist/manager/index.js +8 -7
- package/dist/manager/internal/MutationCompiler.d.ts +14 -6
- package/dist/manager/relations/ManyToManyRelatedManager.d.ts +147 -0
- package/dist/manager/relations/ManyToManyRelatedQuerySet.d.ts +62 -0
- package/dist/manager/relations/MaterializedModelRecord.d.ts +28 -0
- package/dist/manager/relations/index.d.ts +9 -0
- package/dist/manager/relations/internal/ThroughTableManager.d.ts +79 -0
- package/dist/manager-DrDTiCAz.js +24 -0
- package/dist/manager-DrDTiCAz.js.map +1 -0
- package/dist/query/ModelQuerySet.d.ts +20 -0
- package/dist/query/QBuilder.d.ts +3 -3
- package/dist/query/QuerySet.d.ts +58 -18
- package/dist/query/compiler/QueryCompiler.d.ts +13 -4
- package/dist/query/domain/CompiledQuery.d.ts +169 -2
- package/dist/query/domain/FilterInput.d.ts +1 -1
- package/dist/query/domain/FilterKey.d.ts +4 -2
- package/dist/query/domain/QNode.d.ts +4 -4
- package/dist/query/domain/QuerySetState.d.ts +3 -3
- package/dist/query/domain/RelationMeta.d.ts +9 -0
- package/dist/query/domain/RelationTyping.d.ts +47 -0
- package/dist/query/domain/TableMetaFactory.d.ts +1 -14
- package/dist/query/domain/index.d.ts +1 -1
- package/dist/query/domain/internal/InternalPrefetchQueryKind.d.ts +20 -0
- package/dist/query/index.d.ts +1 -0
- package/dist/query/index.js +3 -2
- package/dist/query/internal/isQNodeLike.d.ts +3 -0
- package/dist/query/planning/QueryPlanner.d.ts +1 -1
- package/dist/{query-C6So1r6H.js → query-DUZnBFhf.js} +474 -156
- package/dist/query-DUZnBFhf.js.map +1 -0
- package/dist/registerModelObjects-DxlBfuUN.js +797 -0
- package/dist/registerModelObjects-DxlBfuUN.js.map +1 -0
- package/dist/runtime/TangoRuntime.d.ts +9 -0
- package/dist/runtime/index.d.ts +3 -2
- package/dist/runtime/index.js +7 -6
- package/dist/runtime/internal/SqliteDBClientProvider.d.ts +3 -0
- package/dist/{runtime-ByXbpVBS.js → runtime-1H88J3nN.js} +3 -3
- package/dist/runtime-1H88J3nN.js.map +1 -0
- package/dist/transaction/index.js +5 -4
- package/dist/{transaction-Cs0Z9tbW.js → transaction-ZhfDf-f8.js} +2 -2
- package/dist/{transaction-Cs0Z9tbW.js.map → transaction-ZhfDf-f8.js.map} +1 -1
- package/dist/validation/SQLValidationEngine.d.ts +22 -5
- package/dist/validation/SqlValidationPlan.d.ts +5 -4
- package/dist/validation/internal/InternalSqlValidationPlanKind.d.ts +25 -0
- package/dist/validation/internal/InternalValidatedFilterDescriptorKind.d.ts +4 -0
- package/package.json +6 -6
- package/dist/PostgresAdapter-BFdo_nIt.js +0 -4
- package/dist/PostgresAdapter-CMiEpHya.js +0 -49
- package/dist/PostgresAdapter-CMiEpHya.js.map +0 -1
- package/dist/PostgresClient-BQJZfEOT.js +0 -68
- package/dist/PostgresClient-BQJZfEOT.js.map +0 -1
- package/dist/SqliteAdapter-A-P9zUhP.js +0 -4
- package/dist/SqliteAdapter-CeqhyrPC.js +0 -44
- package/dist/SqliteAdapter-CeqhyrPC.js.map +0 -1
- package/dist/SqliteClient-CjOK9-ki.js.map +0 -1
- package/dist/defaultRuntime-BPK9kWEW.js.map +0 -1
- package/dist/manager-C6oJ2tAF.js +0 -13
- package/dist/manager-C6oJ2tAF.js.map +0 -1
- package/dist/query-C6So1r6H.js.map +0 -1
- package/dist/registerModelObjects-BKMpfc4Z.js +0 -263
- package/dist/registerModelObjects-BKMpfc4Z.js.map +0 -1
- package/dist/runtime-ByXbpVBS.js.map +0 -1
|
@@ -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,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
|
-
|
|
97
|
-
|
|
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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"}
|
|
@@ -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
|
-
*
|
|
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
|
-
|
|
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
|
|
11
|
-
|
|
12
|
-
|
|
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';
|
package/dist/connection/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { PostgresClient } from "../
|
|
2
|
-
import
|
|
3
|
-
import { SqliteClient } from "../
|
|
4
|
-
import {
|
|
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 "./
|
|
3
|
-
import {
|
|
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-
|
|
34
|
-
const { SqliteAdapter: SqliteAdapter$1 } = await import("./SqliteAdapter-
|
|
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-
|
|
117
|
+
//# sourceMappingURL=connection-Dmhgx31M.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-
|
|
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 "./
|
|
2
|
-
import {
|
|
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
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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-
|
|
494
|
+
//# sourceMappingURL=defaultRuntime-DzqBQ9Hb.js.map
|