@danceroutine/tango-orm 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +104 -0
  3. package/dist/{PostgresAdapter-_X36-mLL.js → PostgresAdapter-C9a1XJRx.js} +31 -7
  4. package/dist/PostgresAdapter-C9a1XJRx.js.map +1 -0
  5. package/dist/PostgresAdapter-CBc1u8eT.js +3 -0
  6. package/dist/SqliteAdapter-BJKNxCvS.js +3 -0
  7. package/dist/SqliteAdapter-Dp6VRXmz.js +118 -0
  8. package/dist/SqliteAdapter-Dp6VRXmz.js.map +1 -0
  9. package/dist/connection/adapters/Adapter.d.ts +9 -0
  10. package/dist/connection/adapters/AdapterRegistry.d.ts +28 -1
  11. package/dist/connection/adapters/dialects/PostgresAdapter.d.ts +10 -1
  12. package/dist/connection/adapters/dialects/SqliteAdapter.d.ts +11 -1
  13. package/dist/connection/clients/DBClient.d.ts +8 -0
  14. package/dist/connection/clients/dialects/PostgresClient.d.ts +22 -1
  15. package/dist/connection/clients/dialects/SqliteClient.d.ts +26 -1
  16. package/dist/connection/index.js +3 -3
  17. package/dist/{connection-DytAsjC9.js → connection-CVvycXus.js} +21 -6
  18. package/dist/connection-CVvycXus.js.map +1 -0
  19. package/dist/index.d.ts +7 -4
  20. package/dist/index.js +9 -8
  21. package/dist/manager/ManagerLike.d.ts +15 -0
  22. package/dist/manager/ModelManager.d.ts +48 -0
  23. package/dist/manager/index.d.ts +6 -0
  24. package/dist/manager/index.js +8 -0
  25. package/dist/manager/internal/MutationCompiler.d.ts +15 -0
  26. package/dist/manager/internal/RuntimeBoundClient.d.ts +16 -0
  27. package/dist/manager/registerModelObjects.d.ts +5 -0
  28. package/dist/manager-D6tU8xTO.js +13 -0
  29. package/dist/manager-D6tU8xTO.js.map +1 -0
  30. package/dist/query/QBuilder.d.ts +18 -0
  31. package/dist/query/QuerySet.d.ts +60 -9
  32. package/dist/query/compiler/QueryCompiler.d.ts +19 -2
  33. package/dist/query/domain/{RepositoryMeta.d.ts → TableMeta.d.ts} +1 -1
  34. package/dist/query/domain/index.d.ts +1 -1
  35. package/dist/query/index.d.ts +2 -2
  36. package/dist/query/index.js +1 -2
  37. package/dist/query-wnl4h2o7.js +671 -0
  38. package/dist/query-wnl4h2o7.js.map +1 -0
  39. package/dist/registerModelObjects-emX7Hja9.js +354 -0
  40. package/dist/registerModelObjects-emX7Hja9.js.map +1 -0
  41. package/dist/runtime/TangoRuntime.d.ts +34 -0
  42. package/dist/runtime/defaultRuntime.d.ts +13 -0
  43. package/dist/runtime/index.d.ts +13 -0
  44. package/dist/runtime/index.js +8 -0
  45. package/dist/runtime-7U5_XDad.js +17 -0
  46. package/dist/runtime-7U5_XDad.js.map +1 -0
  47. package/dist/transaction/UnitOfWork.d.ts +21 -3
  48. package/dist/transaction/index.js +1 -1
  49. package/dist/{transaction-DIGJnp19.js → transaction-DooTMuAl.js} +29 -11
  50. package/dist/transaction-DooTMuAl.js.map +1 -0
  51. package/dist/validation/OrmSqlSafetyAdapter.d.ts +22 -0
  52. package/dist/validation/SQLValidationEngine.d.ts +51 -0
  53. package/dist/validation/SqlValidationPlan.d.ts +42 -0
  54. package/dist/validation/index.d.ts +3 -0
  55. package/package.json +81 -74
  56. package/dist/PostgresAdapter-DCF8T4vh.js +0 -3
  57. package/dist/PostgresAdapter-_X36-mLL.js.map +0 -1
  58. package/dist/QuerySet-BzR5QzGi.js +0 -411
  59. package/dist/QuerySet-BzR5QzGi.js.map +0 -1
  60. package/dist/SqliteAdapter-CBnxCznk.js +0 -3
  61. package/dist/SqliteAdapter-J03fEjmr.js +0 -70
  62. package/dist/SqliteAdapter-J03fEjmr.js.map +0 -1
  63. package/dist/connection/clients/DBClient.js +0 -1
  64. package/dist/connection/clients/dialects/PostgresClient.js +0 -32
  65. package/dist/connection/clients/dialects/SqliteClient.js +0 -44
  66. package/dist/connection-DytAsjC9.js.map +0 -1
  67. package/dist/query/QuerySet.js +0 -108
  68. package/dist/query/compiler/QueryCompiler.js +0 -183
  69. package/dist/query/domain/CompiledQuery.js +0 -1
  70. package/dist/query/domain/WhereClause.js +0 -1
  71. package/dist/query-CQbvLeuh.js +0 -21
  72. package/dist/query-CQbvLeuh.js.map +0 -1
  73. package/dist/repository/Repository.d.ts +0 -40
  74. package/dist/repository/Repository.js +0 -100
  75. package/dist/repository/index.d.ts +0 -4
  76. package/dist/repository/index.js +0 -4
  77. package/dist/repository-DaRvsfjs.js +0 -78
  78. package/dist/repository-DaRvsfjs.js.map +0 -1
  79. package/dist/transaction-DIGJnp19.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Pedro Del Moral Lopez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # @danceroutine/tango-orm
2
+
3
+ `@danceroutine/tango-orm` provides Tango's persistence layer.
4
+
5
+ The default Tango path is model-first. A Tango model can expose `Model.objects`, the runtime loads database configuration on first use, and most application code stays focused on queries and CRUD flows rather than client wiring.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @danceroutine/tango-orm
11
+ ```
12
+
13
+ Install the driver for the dialect you use:
14
+
15
+ ```bash
16
+ pnpm add pg
17
+ # or
18
+ pnpm add better-sqlite3
19
+ ```
20
+
21
+ ## What the package does inside Tango
22
+
23
+ The package is organized around five concerns:
24
+
25
+ - `runtime`, for Tango-owned config loading and shared DB client lifecycle
26
+ - `manager`, for Django-style `Model.objects` access
27
+ - `connection`, for adapters and concrete DB clients
28
+ - `query`, for composable query state and compilation
29
+ - `transaction`, for explicit units of work
30
+
31
+ Most applications can stay inside `Model.objects` and `QuerySet`.
32
+
33
+ ## Quick start
34
+
35
+ ```ts
36
+ import { z } from 'zod';
37
+ import '@danceroutine/tango-orm/runtime';
38
+ import { Model, t } from '@danceroutine/tango-schema';
39
+
40
+ const TodoReadSchema = z.object({
41
+ id: z.number(),
42
+ title: z.string(),
43
+ completed: z.coerce.boolean(),
44
+ });
45
+
46
+ export const TodoModel = Model({
47
+ namespace: 'app',
48
+ name: 'Todo',
49
+ schema: TodoReadSchema.extend({
50
+ id: t.primaryKey(z.number().int()),
51
+ title: z.string(),
52
+ completed: t.default(z.coerce.boolean(), 'false'),
53
+ }),
54
+ });
55
+
56
+ const todos = await TodoModel.objects.query().orderBy('-id').fetch(TodoReadSchema);
57
+ ```
58
+
59
+ The side-effect import enables Tango's runtime-backed model augmentation for the process. After that, application code can query through `Model.objects` directly.
60
+
61
+ ## Main building blocks
62
+
63
+ The root export includes:
64
+
65
+ - runtime helpers such as `getTangoRuntime`
66
+ - manager contracts such as `ModelManager`
67
+ - connection helpers such as `connectDB`, `AdapterRegistry`, `PostgresAdapter`, and `SqliteAdapter`
68
+ - query primitives such as `QuerySet`, `QBuilder`, `Q`, `QueryCompiler`, `TableMeta`, and `QueryExecutor`
69
+ - `UnitOfWork`
70
+
71
+ ## Import style
72
+
73
+ For most applications, root imports are the clearest choice:
74
+
75
+ ```ts
76
+ import { Q, QuerySet, UnitOfWork } from '@danceroutine/tango-orm';
77
+ ```
78
+
79
+ If you prefer explicit boundaries, the package also exposes `runtime`, `manager`, `connection`, `query`, and `transaction` subpaths.
80
+
81
+ ## Developer workflow
82
+
83
+ ```bash
84
+ pnpm --filter @danceroutine/tango-orm build
85
+ pnpm --filter @danceroutine/tango-orm typecheck
86
+ pnpm --filter @danceroutine/tango-orm test
87
+ ```
88
+
89
+ The package also has integration coverage for dialect-specific behavior:
90
+
91
+ ```bash
92
+ pnpm --filter @danceroutine/tango-orm test:integration
93
+ ```
94
+
95
+ ## Bugs and support
96
+
97
+ - Documentation: <https://tangowebframework.dev>
98
+ - ORM topic: <https://tangowebframework.dev/topics/orm-and-repositories>
99
+ - Query reference: <https://tangowebframework.dev/reference/orm-query-api>
100
+ - Issue tracker: <https://github.com/danceroutine/tango/issues>
101
+
102
+ ## License
103
+
104
+ MIT
@@ -4,26 +4,44 @@ import pg from "pg";
4
4
  var PostgresClient = class PostgresClient {
5
5
  static BRAND = "tango.orm.postgres_client";
6
6
  __tangoBrand = PostgresClient.BRAND;
7
- static isPostgresClient(value) {
8
- return typeof value === "object" && value !== null && value.__tangoBrand === PostgresClient.BRAND;
9
- }
10
7
  constructor(pool, client) {
11
8
  this.pool = pool;
12
9
  this.client = client;
13
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
+ */
14
20
  async query(sql, params) {
15
21
  const result = await this.client.query(sql, params);
16
22
  return { rows: result.rows };
17
23
  }
24
+ /**
25
+ * Begin a database transaction.
26
+ */
18
27
  async begin() {
19
28
  await this.client.query("BEGIN");
20
29
  }
30
+ /**
31
+ * Commit the active transaction.
32
+ */
21
33
  async commit() {
22
34
  await this.client.query("COMMIT");
23
35
  }
36
+ /**
37
+ * Roll back the active transaction.
38
+ */
24
39
  async rollback() {
25
40
  await this.client.query("ROLLBACK");
26
41
  }
42
+ /**
43
+ * Release client resources and close the associated pool.
44
+ */
27
45
  async close() {
28
46
  this.client.release();
29
47
  await this.pool.end();
@@ -37,9 +55,6 @@ var PostgresAdapter = class PostgresAdapter {
37
55
  static BRAND = "tango.orm.postgres_adapter";
38
56
  __tangoBrand = PostgresAdapter.BRAND;
39
57
  name = "postgres";
40
- static isPostgresAdapter(value) {
41
- return typeof value === "object" && value !== null && value.__tangoBrand === PostgresAdapter.BRAND;
42
- }
43
58
  /**
44
59
  * Declares capabilities of this database adapter.
45
60
  * Used by the migration runner and query compiler to determine which
@@ -53,6 +68,15 @@ var PostgresAdapter = class PostgresAdapter {
53
68
  concurrentIndex: true,
54
69
  validateForeignKeys: true
55
70
  };
71
+ /**
72
+ * Narrow an unknown value to `PostgresAdapter`.
73
+ */
74
+ static isPostgresAdapter(value) {
75
+ return typeof value === "object" && value !== null && value.__tangoBrand === PostgresAdapter.BRAND;
76
+ }
77
+ /**
78
+ * Open a Postgres connection pool and return a client-backed DB abstraction.
79
+ */
56
80
  async connect(config) {
57
81
  const pool = new Pool({
58
82
  connectionString: config.url,
@@ -70,4 +94,4 @@ var PostgresAdapter = class PostgresAdapter {
70
94
 
71
95
  //#endregion
72
96
  export { PostgresAdapter, PostgresClient };
73
- //# sourceMappingURL=PostgresAdapter-_X36-mLL.js.map
97
+ //# sourceMappingURL=PostgresAdapter-C9a1XJRx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresAdapter-C9a1XJRx.js","names":["pool: pg.Pool","client: pg.PoolClient","value: unknown","sql: string","params?: readonly unknown[]","value: unknown","config: AdapterConfig"],"sources":["../src/connection/clients/dialects/PostgresClient.ts","../src/connection/adapters/dialects/PostgresAdapter.ts"],"sourcesContent":["import type pg from 'pg';\nimport type { DBClient } from '../DBClient';\n\n/**\n * `DBClient` implementation backed by a PostgreSQL pool client.\n */\nexport class PostgresClient implements DBClient {\n static readonly BRAND = 'tango.orm.postgres_client' as const;\n readonly __tangoBrand: typeof PostgresClient.BRAND = PostgresClient.BRAND;\n\n constructor(\n private pool: pg.Pool,\n private client: pg.PoolClient\n ) {}\n\n /**\n * Narrow an unknown value to `PostgresClient`.\n */\n static isPostgresClient(value: unknown): value is PostgresClient {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === PostgresClient.BRAND\n );\n }\n\n /**\n * Execute a SQL statement with optional bound parameters.\n */\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const result = await this.client.query(sql, params as unknown[]);\n return { rows: result.rows as T[] };\n }\n\n /**\n * Begin a database transaction.\n */\n async begin(): Promise<void> {\n await this.client.query('BEGIN');\n }\n\n /**\n * Commit the active transaction.\n */\n async commit(): Promise<void> {\n await this.client.query('COMMIT');\n }\n\n /**\n * Roll back the active transaction.\n */\n async rollback(): Promise<void> {\n await this.client.query('ROLLBACK');\n }\n\n /**\n * Release client resources and close the associated pool.\n */\n async close(): Promise<void> {\n this.client.release();\n await this.pool.end();\n }\n}\n","import pg from 'pg';\nimport type { Adapter, AdapterConfig } from '../Adapter';\nimport type { DBClient } from '../../clients/DBClient';\nimport { PostgresClient } from '../../clients/dialects/PostgresClient';\n\nconst { Pool } = pg;\n\n/**\n * Postgres adapter that turns adapter config into a transactional `DBClient`.\n */\nexport class PostgresAdapter implements Adapter {\n static readonly BRAND = 'tango.orm.postgres_adapter' as const;\n readonly __tangoBrand: typeof PostgresAdapter.BRAND = PostgresAdapter.BRAND;\n readonly name = 'postgres';\n /**\n * Declares capabilities of this database adapter.\n * Used by the migration runner and query compiler to determine which\n * SQL features can be safely used:\n * - transactionalDDL: Postgres supports DDL inside transactions (safe rollback of schema changes)\n * - concurrentIndex: Supports CREATE INDEX CONCURRENTLY (non-blocking index builds)\n * - validateForeignKeys: Supports deferred FK validation via NOT VALID + VALIDATE CONSTRAINT\n */\n readonly features = {\n transactionalDDL: true,\n concurrentIndex: true,\n validateForeignKeys: true,\n };\n\n /**\n * Narrow an unknown value to `PostgresAdapter`.\n */\n static isPostgresAdapter(value: unknown): value is PostgresAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === PostgresAdapter.BRAND\n );\n }\n\n /**\n * Open a Postgres connection pool and return a client-backed DB abstraction.\n */\n async connect(config: AdapterConfig): Promise<DBClient> {\n const pool = new Pool({\n connectionString: config.url,\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n password: config.password,\n max: config.maxConnections || 10,\n });\n\n const client = await pool.connect();\n return new PostgresClient(pool, client);\n }\n}\n"],"mappings":";;;IAMa,iBAAN,MAAM,eAAmC;CAC5C,OAAgB,QAAQ;CACxB,eAAqD,eAAe;CAEpE,YACYA,MACAC,QACV;AAAA,OAFU,OAAA;AAAA,OACA,SAAA;CACR;;;;CAKJ,OAAO,iBAAiBC,OAAyC;AAC7D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,eAAe;CAE7E;;;;CAKD,MAAM,MAAmBC,KAAaC,QAAqD;EACvF,MAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,OAAoB;AAChE,SAAO,EAAE,MAAM,OAAO,KAAa;CACtC;;;;CAKD,MAAM,QAAuB;AACzB,QAAM,KAAK,OAAO,MAAM,QAAQ;CACnC;;;;CAKD,MAAM,SAAwB;AAC1B,QAAM,KAAK,OAAO,MAAM,SAAS;CACpC;;;;CAKD,MAAM,WAA0B;AAC5B,QAAM,KAAK,OAAO,MAAM,WAAW;CACtC;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,OAAO,SAAS;AACrB,QAAM,KAAK,KAAK,KAAK;CACxB;AACJ;;;;ACzDD,MAAM,EAAE,MAAM,GAAG;IAKJ,kBAAN,MAAM,gBAAmC;CAC5C,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;CACtE,OAAgB;;;;;;;;;CAShB,WAAoB;EAChB,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB;CACxB;;;;CAKD,OAAO,kBAAkBC,OAA0C;AAC/D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE9E;;;;CAKD,MAAM,QAAQC,QAA0C;EACpD,MAAM,OAAO,IAAI,KAAK;GAClB,kBAAkB,OAAO;GACzB,MAAM,OAAO;GACb,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,MAAM,OAAO;GACb,UAAU,OAAO;GACjB,KAAK,OAAO,kBAAkB;EACjC;EAED,MAAM,SAAS,MAAM,KAAK,SAAS;AACnC,SAAO,IAAI,eAAe,MAAM;CACnC;AACJ"}
@@ -0,0 +1,3 @@
1
+ import { PostgresAdapter } from "./PostgresAdapter-C9a1XJRx.js";
2
+
3
+ export { PostgresAdapter };
@@ -0,0 +1,3 @@
1
+ import { SqliteAdapter } from "./SqliteAdapter-Dp6VRXmz.js";
2
+
3
+ export { SqliteAdapter };
@@ -0,0 +1,118 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region src/connection/clients/dialects/SqliteClient.ts
4
+ var SqliteClient = class SqliteClient {
5
+ static BRAND = "tango.orm.sqlite_client";
6
+ __tangoBrand = SqliteClient.BRAND;
7
+ inTransaction = false;
8
+ constructor(db) {
9
+ this.db = db;
10
+ }
11
+ /**
12
+ * Narrow an unknown value to `SqliteClient`.
13
+ */
14
+ static isSqliteClient(value) {
15
+ return typeof value === "object" && value !== null && value.__tangoBrand === SqliteClient.BRAND;
16
+ }
17
+ /**
18
+ * Execute a SQL statement with optional parameters.
19
+ *
20
+ * `SELECT`/`PRAGMA` statements return row data; write statements return
21
+ * an empty row list.
22
+ */
23
+ async query(sql, params) {
24
+ const stmt = this.db.prepare(sql);
25
+ const isPragmaWrite = /^\s*PRAGMA\b/i.test(sql) && /=/.test(sql);
26
+ const normalizedParams = params?.map((param) => this.normalizeParam(param));
27
+ if (!isPragmaWrite && stmt.reader) {
28
+ const rows = normalizedParams ? stmt.all(...normalizedParams) : stmt.all();
29
+ return { rows };
30
+ }
31
+ if (normalizedParams) stmt.run(...normalizedParams);
32
+ else stmt.run();
33
+ return { rows: [] };
34
+ }
35
+ /**
36
+ * Begin a transaction if one is not already active.
37
+ */
38
+ async begin() {
39
+ if (!this.inTransaction) {
40
+ this.db.prepare("BEGIN").run();
41
+ this.inTransaction = true;
42
+ }
43
+ }
44
+ /**
45
+ * Commit the active transaction.
46
+ */
47
+ async commit() {
48
+ if (this.inTransaction) {
49
+ this.db.prepare("COMMIT").run();
50
+ this.inTransaction = false;
51
+ }
52
+ }
53
+ /**
54
+ * Roll back the active transaction.
55
+ */
56
+ async rollback() {
57
+ if (this.inTransaction) {
58
+ this.db.prepare("ROLLBACK").run();
59
+ this.inTransaction = false;
60
+ }
61
+ }
62
+ /**
63
+ * Close the underlying SQLite handle.
64
+ */
65
+ async close() {
66
+ this.db.close();
67
+ }
68
+ normalizeParam(value) {
69
+ if (isDateValue(value)) return value.toISOString();
70
+ if (typeof value === "boolean") return value ? 1 : 0;
71
+ return value;
72
+ }
73
+ };
74
+ function isDateValue(value) {
75
+ return typeof value === "object" && value !== null && typeof value.getTime === "function" && typeof value.toISOString === "function";
76
+ }
77
+
78
+ //#endregion
79
+ //#region src/connection/adapters/dialects/SqliteAdapter.ts
80
+ var SqliteAdapter = class SqliteAdapter {
81
+ static BRAND = "tango.orm.sqlite_adapter";
82
+ __tangoBrand = SqliteAdapter.BRAND;
83
+ name = "sqlite";
84
+ features = {
85
+ transactionalDDL: true,
86
+ concurrentIndex: false,
87
+ validateForeignKeys: false
88
+ };
89
+ /**
90
+ * Narrow an unknown value to `SqliteAdapter`.
91
+ */
92
+ static isSqliteAdapter(value) {
93
+ return typeof value === "object" && value !== null && value.__tangoBrand === SqliteAdapter.BRAND;
94
+ }
95
+ /**
96
+ * Open a SQLite database and apply baseline pragmas for durability/safety.
97
+ */
98
+ async connect(config = {}) {
99
+ const Database = this.getDatabaseCtor();
100
+ const filename = typeof config.filename === "string" && config.filename.length > 0 ? config.filename : ":memory:";
101
+ const db = new Database(filename);
102
+ db.pragma("journal_mode = WAL");
103
+ db.pragma("foreign_keys = ON");
104
+ return new SqliteClient(db);
105
+ }
106
+ getDatabaseCtor() {
107
+ const require = createRequire(import.meta.url);
108
+ const moduleValue = require("better-sqlite3");
109
+ if (typeof moduleValue === "function") return moduleValue;
110
+ const defaultExport = moduleValue.default;
111
+ if (typeof defaultExport === "function") return defaultExport;
112
+ throw new TypeError("Failed to load better-sqlite3 constructor.");
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ export { SqliteAdapter, SqliteClient };
118
+ //# sourceMappingURL=SqliteAdapter-Dp6VRXmz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SqliteAdapter-Dp6VRXmz.js","names":["db: Database.Database","value: unknown","sql: string","params?: readonly unknown[]","value: unknown","config: AdapterConfig"],"sources":["../src/connection/clients/dialects/SqliteClient.ts","../src/connection/adapters/dialects/SqliteAdapter.ts"],"sourcesContent":["import type Database from 'better-sqlite3';\nimport type { DBClient } from '../DBClient';\n\n/**\n * `DBClient` implementation backed by a synchronous `better-sqlite3` handle.\n */\nexport class SqliteClient implements DBClient {\n static readonly BRAND = 'tango.orm.sqlite_client' as const;\n readonly __tangoBrand: typeof SqliteClient.BRAND = SqliteClient.BRAND;\n private inTransaction = false;\n\n constructor(private db: Database.Database) {}\n\n /**\n * Narrow an unknown value to `SqliteClient`.\n */\n static isSqliteClient(value: unknown): value is SqliteClient {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === SqliteClient.BRAND\n );\n }\n\n /**\n * Execute a SQL statement with optional parameters.\n *\n * `SELECT`/`PRAGMA` statements return row data; write statements return\n * an empty row list.\n */\n async query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{ rows: T[] }> {\n const stmt = this.db.prepare(sql);\n const isPragmaWrite = /^\\s*PRAGMA\\b/i.test(sql) && /=/.test(sql);\n\n const normalizedParams = params?.map((param) => this.normalizeParam(param));\n\n if (!isPragmaWrite && stmt.reader) {\n const rows = normalizedParams ? stmt.all(...(normalizedParams as unknown[])) : stmt.all();\n return { rows: rows as T[] };\n }\n\n if (normalizedParams) {\n stmt.run(...(normalizedParams as unknown[]));\n } else {\n stmt.run();\n }\n return { rows: [] };\n }\n\n /**\n * Begin a transaction if one is not already active.\n */\n async begin(): Promise<void> {\n if (!this.inTransaction) {\n this.db.prepare('BEGIN').run();\n this.inTransaction = true;\n }\n }\n\n /**\n * Commit the active transaction.\n */\n async commit(): Promise<void> {\n if (this.inTransaction) {\n this.db.prepare('COMMIT').run();\n this.inTransaction = false;\n }\n }\n\n /**\n * Roll back the active transaction.\n */\n async rollback(): Promise<void> {\n if (this.inTransaction) {\n this.db.prepare('ROLLBACK').run();\n this.inTransaction = false;\n }\n }\n\n /**\n * Close the underlying SQLite handle.\n */\n async close(): Promise<void> {\n this.db.close();\n }\n\n private normalizeParam(value: unknown): unknown {\n if (isDateValue(value)) {\n return value.toISOString();\n }\n if (typeof value === 'boolean') {\n return value ? 1 : 0;\n }\n return value;\n }\n}\n\nfunction isDateValue(value: unknown): value is Date {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as { getTime?: unknown }).getTime === 'function' &&\n typeof (value as { toISOString?: unknown }).toISOString === 'function'\n );\n}\n","import { createRequire } from 'node:module';\nimport type { Database as BetterSqliteDatabase } from 'better-sqlite3';\nimport type { Adapter, AdapterConfig } from '../Adapter';\nimport type { DBClient } from '../../clients/DBClient';\nimport { SqliteClient } from '../../clients/dialects/SqliteClient';\n\ntype BetterSqliteCtor = new (filename: string, options?: unknown) => BetterSqliteDatabase;\n\n/**\n * SQLite adapter that creates a `better-sqlite3` backed `DBClient`.\n */\nexport class SqliteAdapter implements Adapter {\n static readonly BRAND = 'tango.orm.sqlite_adapter' as const;\n readonly __tangoBrand: typeof SqliteAdapter.BRAND = SqliteAdapter.BRAND;\n readonly name = 'sqlite';\n readonly features = {\n transactionalDDL: true,\n concurrentIndex: false,\n validateForeignKeys: false,\n };\n\n /**\n * Narrow an unknown value to `SqliteAdapter`.\n */\n static isSqliteAdapter(value: unknown): value is SqliteAdapter {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === SqliteAdapter.BRAND\n );\n }\n\n /**\n * Open a SQLite database and apply baseline pragmas for durability/safety.\n */\n async connect(config: AdapterConfig = {}): Promise<DBClient> {\n const Database = this.getDatabaseCtor();\n const filename =\n typeof config.filename === 'string' && config.filename.length > 0 ? config.filename : ':memory:';\n const db = new Database(filename);\n db.pragma('journal_mode = WAL');\n db.pragma('foreign_keys = ON');\n\n return new SqliteClient(db);\n }\n\n private getDatabaseCtor(): BetterSqliteCtor {\n const require = createRequire(import.meta.url);\n const moduleValue = require('better-sqlite3') as unknown;\n if (typeof moduleValue === 'function') {\n return moduleValue as BetterSqliteCtor;\n }\n\n const defaultExport = (moduleValue as { default?: unknown }).default;\n if (typeof defaultExport === 'function') {\n return defaultExport as BetterSqliteCtor;\n }\n\n throw new TypeError('Failed to load better-sqlite3 constructor.');\n }\n}\n"],"mappings":";;;IAMa,eAAN,MAAM,aAAiC;CAC1C,OAAgB,QAAQ;CACxB,eAAmD,aAAa;CAChE,gBAAwB;CAExB,YAAoBA,IAAuB;AAAA,OAAvB,KAAA;CAAyB;;;;CAK7C,OAAO,eAAeC,OAAuC;AACzD,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,aAAa;CAE3E;;;;;;;CAQD,MAAM,MAAmBC,KAAaC,QAAqD;EACvF,MAAM,OAAO,KAAK,GAAG,QAAQ,IAAI;EACjC,MAAM,gBAAgB,gBAAgB,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI;EAEhE,MAAM,mBAAmB,QAAQ,IAAI,CAAC,UAAU,KAAK,eAAe,MAAM,CAAC;AAE3E,OAAK,iBAAiB,KAAK,QAAQ;GAC/B,MAAM,OAAO,mBAAmB,KAAK,IAAI,GAAI,iBAA+B,GAAG,KAAK,KAAK;AACzF,UAAO,EAAQ,KAAa;EAC/B;AAED,MAAI,iBACA,MAAK,IAAI,GAAI,iBAA+B;IAE5C,MAAK,KAAK;AAEd,SAAO,EAAE,MAAM,CAAE,EAAE;CACtB;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,KAAK,eAAe;AACrB,QAAK,GAAG,QAAQ,QAAQ,CAAC,KAAK;AAC9B,QAAK,gBAAgB;EACxB;CACJ;;;;CAKD,MAAM,SAAwB;AAC1B,MAAI,KAAK,eAAe;AACpB,QAAK,GAAG,QAAQ,SAAS,CAAC,KAAK;AAC/B,QAAK,gBAAgB;EACxB;CACJ;;;;CAKD,MAAM,WAA0B;AAC5B,MAAI,KAAK,eAAe;AACpB,QAAK,GAAG,QAAQ,WAAW,CAAC,KAAK;AACjC,QAAK,gBAAgB;EACxB;CACJ;;;;CAKD,MAAM,QAAuB;AACzB,OAAK,GAAG,OAAO;CAClB;CAED,eAAuBF,OAAyB;AAC5C,MAAI,YAAY,MAAM,CAClB,QAAO,MAAM,aAAa;AAE9B,aAAW,UAAU,UACjB,QAAO,QAAQ,IAAI;AAEvB,SAAO;CACV;AACJ;AAED,SAAS,YAAYA,OAA+B;AAChD,eACW,UAAU,YACjB,UAAU,eACF,MAAgC,YAAY,qBAC5C,MAAoC,gBAAgB;AAEnE;;;;IC7FY,gBAAN,MAAM,cAAiC;CAC1C,OAAgB,QAAQ;CACxB,eAAoD,cAAc;CAClE,OAAgB;CAChB,WAAoB;EAChB,kBAAkB;EAClB,iBAAiB;EACjB,qBAAqB;CACxB;;;;CAKD,OAAO,gBAAgBG,OAAwC;AAC3D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,cAAc;CAE5E;;;;CAKD,MAAM,QAAQC,SAAwB,CAAE,GAAqB;EACzD,MAAM,WAAW,KAAK,iBAAiB;EACvC,MAAM,kBACK,OAAO,aAAa,YAAY,OAAO,SAAS,SAAS,IAAI,OAAO,WAAW;EAC1F,MAAM,KAAK,IAAI,SAAS;AACxB,KAAG,OAAO,qBAAqB;AAC/B,KAAG,OAAO,oBAAoB;AAE9B,SAAO,IAAI,aAAa;CAC3B;CAED,kBAA4C;EACxC,MAAM,UAAU,cAAc,OAAO,KAAK,IAAI;EAC9C,MAAM,cAAc,QAAQ,iBAAiB;AAC7C,aAAW,gBAAgB,WACvB,QAAO;EAGX,MAAM,gBAAiB,YAAsC;AAC7D,aAAW,kBAAkB,WACzB,QAAO;AAGX,QAAM,IAAI,UAAU;CACvB;AACJ"}
@@ -1,4 +1,7 @@
1
1
  import type { DBClient } from '../clients/DBClient';
2
+ /**
3
+ * Connection options shared by built-in DB adapters.
4
+ */
2
5
  export interface AdapterConfig {
3
6
  url?: string;
4
7
  host?: string;
@@ -9,9 +12,15 @@ export interface AdapterConfig {
9
12
  filename?: string;
10
13
  maxConnections?: number;
11
14
  }
15
+ /**
16
+ * Runtime adapter contract for establishing `DBClient` connections.
17
+ */
12
18
  export interface Adapter {
19
+ /** Stable adapter name used in configuration and registry lookup. */
13
20
  name: string;
21
+ /** Open a database connection and return a client abstraction. */
14
22
  connect(config: AdapterConfig): Promise<DBClient>;
23
+ /** SQL capability flags used by migrations/query orchestration. */
15
24
  features: {
16
25
  transactionalDDL: boolean;
17
26
  concurrentIndex: boolean;
@@ -1,17 +1,44 @@
1
1
  import type { Adapter, AdapterConfig } from './Adapter';
2
2
  import type { DBClient } from '../clients/DBClient';
3
+ /**
4
+ * Runtime registry for database adapters.
5
+ *
6
+ * Use a custom instance when tests or applications need explicit control
7
+ * over supported adapters; use `getDefaultRegistry()` for the built-in set.
8
+ */
3
9
  export declare class AdapterRegistry {
4
10
  static readonly BRAND: "tango.orm.adapter_registry";
5
- readonly __tangoBrand: typeof AdapterRegistry.BRAND;
6
11
  private static defaultRegistryInstance;
12
+ readonly __tangoBrand: typeof AdapterRegistry.BRAND;
7
13
  private adapters;
14
+ /**
15
+ * Narrow an unknown value to `AdapterRegistry`.
16
+ */
8
17
  static isAdapterRegistry(value: unknown): value is AdapterRegistry;
18
+ /**
19
+ * Return a lazily-initialized registry preloaded with built-in adapters.
20
+ */
9
21
  static getDefaultRegistry(): Promise<AdapterRegistry>;
22
+ /**
23
+ * Register an adapter under its declared `name`.
24
+ */
10
25
  register(adapter: Adapter): this;
26
+ /**
27
+ * Resolve an adapter by name, or throw a descriptive error.
28
+ */
11
29
  get(name: string): Adapter;
30
+ /**
31
+ * Check whether an adapter has been registered.
32
+ */
12
33
  has(name: string): boolean;
13
34
  }
35
+ /**
36
+ * Connect to a database by adapter name using the provided (or default) registry.
37
+ */
14
38
  export declare function connectDB(config: AdapterConfig & {
15
39
  adapter: string;
16
40
  }, registry?: AdapterRegistry): Promise<DBClient>;
41
+ /**
42
+ * Convenience helper that exposes the singleton default adapter registry.
43
+ */
17
44
  export declare function getDefaultAdapterRegistry(): Promise<AdapterRegistry>;
@@ -1,10 +1,12 @@
1
1
  import type { Adapter, AdapterConfig } from '../Adapter';
2
2
  import type { DBClient } from '../../clients/DBClient';
3
+ /**
4
+ * Postgres adapter that turns adapter config into a transactional `DBClient`.
5
+ */
3
6
  export declare class PostgresAdapter implements Adapter {
4
7
  static readonly BRAND: "tango.orm.postgres_adapter";
5
8
  readonly __tangoBrand: typeof PostgresAdapter.BRAND;
6
9
  readonly name = "postgres";
7
- static isPostgresAdapter(value: unknown): value is PostgresAdapter;
8
10
  /**
9
11
  * Declares capabilities of this database adapter.
10
12
  * Used by the migration runner and query compiler to determine which
@@ -18,5 +20,12 @@ export declare class PostgresAdapter implements Adapter {
18
20
  concurrentIndex: boolean;
19
21
  validateForeignKeys: boolean;
20
22
  };
23
+ /**
24
+ * Narrow an unknown value to `PostgresAdapter`.
25
+ */
26
+ static isPostgresAdapter(value: unknown): value is PostgresAdapter;
27
+ /**
28
+ * Open a Postgres connection pool and return a client-backed DB abstraction.
29
+ */
21
30
  connect(config: AdapterConfig): Promise<DBClient>;
22
31
  }
@@ -1,5 +1,8 @@
1
1
  import type { Adapter, AdapterConfig } from '../Adapter';
2
2
  import type { DBClient } from '../../clients/DBClient';
3
+ /**
4
+ * SQLite adapter that creates a `better-sqlite3` backed `DBClient`.
5
+ */
3
6
  export declare class SqliteAdapter implements Adapter {
4
7
  static readonly BRAND: "tango.orm.sqlite_adapter";
5
8
  readonly __tangoBrand: typeof SqliteAdapter.BRAND;
@@ -9,6 +12,13 @@ export declare class SqliteAdapter implements Adapter {
9
12
  concurrentIndex: boolean;
10
13
  validateForeignKeys: boolean;
11
14
  };
15
+ /**
16
+ * Narrow an unknown value to `SqliteAdapter`.
17
+ */
12
18
  static isSqliteAdapter(value: unknown): value is SqliteAdapter;
13
- connect(config: AdapterConfig): Promise<DBClient>;
19
+ /**
20
+ * Open a SQLite database and apply baseline pragmas for durability/safety.
21
+ */
22
+ connect(config?: AdapterConfig): Promise<DBClient>;
23
+ private getDatabaseCtor;
14
24
  }
@@ -1,9 +1,17 @@
1
+ /**
2
+ * Database client abstraction used by ORM and migrations.
3
+ */
1
4
  export interface DBClient {
5
+ /** Execute SQL with optional positional parameters. */
2
6
  query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
3
7
  rows: T[];
4
8
  }>;
9
+ /** Begin a transaction. */
5
10
  begin(): Promise<void>;
11
+ /** Commit current transaction. */
6
12
  commit(): Promise<void>;
13
+ /** Roll back current transaction. */
7
14
  rollback(): Promise<void>;
15
+ /** Close underlying connection resources. */
8
16
  close(): Promise<void>;
9
17
  }
@@ -1,17 +1,38 @@
1
1
  import type pg from 'pg';
2
2
  import type { DBClient } from '../DBClient';
3
+ /**
4
+ * `DBClient` implementation backed by a PostgreSQL pool client.
5
+ */
3
6
  export declare class PostgresClient implements DBClient {
4
7
  private pool;
5
8
  private client;
6
9
  static readonly BRAND: "tango.orm.postgres_client";
7
10
  readonly __tangoBrand: typeof PostgresClient.BRAND;
8
- static isPostgresClient(value: unknown): value is PostgresClient;
9
11
  constructor(pool: pg.Pool, client: pg.PoolClient);
12
+ /**
13
+ * Narrow an unknown value to `PostgresClient`.
14
+ */
15
+ static isPostgresClient(value: unknown): value is PostgresClient;
16
+ /**
17
+ * Execute a SQL statement with optional bound parameters.
18
+ */
10
19
  query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
11
20
  rows: T[];
12
21
  }>;
22
+ /**
23
+ * Begin a database transaction.
24
+ */
13
25
  begin(): Promise<void>;
26
+ /**
27
+ * Commit the active transaction.
28
+ */
14
29
  commit(): Promise<void>;
30
+ /**
31
+ * Roll back the active transaction.
32
+ */
15
33
  rollback(): Promise<void>;
34
+ /**
35
+ * Release client resources and close the associated pool.
36
+ */
16
37
  close(): Promise<void>;
17
38
  }
@@ -1,17 +1,42 @@
1
1
  import type Database from 'better-sqlite3';
2
2
  import type { DBClient } from '../DBClient';
3
+ /**
4
+ * `DBClient` implementation backed by a synchronous `better-sqlite3` handle.
5
+ */
3
6
  export declare class SqliteClient implements DBClient {
4
7
  private db;
5
8
  static readonly BRAND: "tango.orm.sqlite_client";
6
9
  readonly __tangoBrand: typeof SqliteClient.BRAND;
7
10
  private inTransaction;
8
- static isSqliteClient(value: unknown): value is SqliteClient;
9
11
  constructor(db: Database.Database);
12
+ /**
13
+ * Narrow an unknown value to `SqliteClient`.
14
+ */
15
+ static isSqliteClient(value: unknown): value is SqliteClient;
16
+ /**
17
+ * Execute a SQL statement with optional parameters.
18
+ *
19
+ * `SELECT`/`PRAGMA` statements return row data; write statements return
20
+ * an empty row list.
21
+ */
10
22
  query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
11
23
  rows: T[];
12
24
  }>;
25
+ /**
26
+ * Begin a transaction if one is not already active.
27
+ */
13
28
  begin(): Promise<void>;
29
+ /**
30
+ * Commit the active transaction.
31
+ */
14
32
  commit(): Promise<void>;
33
+ /**
34
+ * Roll back the active transaction.
35
+ */
15
36
  rollback(): Promise<void>;
37
+ /**
38
+ * Close the underlying SQLite handle.
39
+ */
16
40
  close(): Promise<void>;
41
+ private normalizeParam;
17
42
  }
@@ -1,5 +1,5 @@
1
- import { PostgresAdapter, PostgresClient } from "../PostgresAdapter-_X36-mLL.js";
2
- import { SqliteAdapter, SqliteClient } from "../SqliteAdapter-J03fEjmr.js";
3
- import { AdapterRegistry, adapters_exports, clients_exports, connectDB, getDefaultAdapterRegistry } from "../connection-DytAsjC9.js";
1
+ import { PostgresAdapter, PostgresClient } from "../PostgresAdapter-C9a1XJRx.js";
2
+ import { SqliteAdapter, SqliteClient } from "../SqliteAdapter-Dp6VRXmz.js";
3
+ import { AdapterRegistry, adapters_exports, clients_exports, connectDB, getDefaultAdapterRegistry } from "../connection-CVvycXus.js";
4
4
 
5
5
  export { AdapterRegistry, PostgresAdapter, PostgresClient, SqliteAdapter, SqliteClient, adapters_exports as adapters, clients_exports as clients, connectDB, getDefaultAdapterRegistry };
@@ -1,6 +1,6 @@
1
1
  import { __export } from "./chunk-DLY2FNSh.js";
2
- import { PostgresAdapter, PostgresClient } from "./PostgresAdapter-_X36-mLL.js";
3
- import { SqliteAdapter, SqliteClient } from "./SqliteAdapter-J03fEjmr.js";
2
+ import { PostgresAdapter, PostgresClient } from "./PostgresAdapter-C9a1XJRx.js";
3
+ import { SqliteAdapter, SqliteClient } from "./SqliteAdapter-Dp6VRXmz.js";
4
4
 
5
5
  //#region src/connection/adapters/dialects/index.ts
6
6
  var dialects_exports$1 = {};
@@ -13,25 +13,37 @@ __export(dialects_exports$1, {
13
13
  //#region src/connection/adapters/AdapterRegistry.ts
14
14
  var AdapterRegistry = class AdapterRegistry {
15
15
  static BRAND = "tango.orm.adapter_registry";
16
- __tangoBrand = AdapterRegistry.BRAND;
17
16
  static defaultRegistryInstance;
17
+ __tangoBrand = AdapterRegistry.BRAND;
18
18
  adapters = new Map();
19
+ /**
20
+ * Narrow an unknown value to `AdapterRegistry`.
21
+ */
19
22
  static isAdapterRegistry(value) {
20
23
  return typeof value === "object" && value !== null && value.__tangoBrand === AdapterRegistry.BRAND;
21
24
  }
25
+ /**
26
+ * Return a lazily-initialized registry preloaded with built-in adapters.
27
+ */
22
28
  static async getDefaultRegistry() {
23
29
  if (AdapterRegistry.defaultRegistryInstance) return AdapterRegistry.defaultRegistryInstance;
24
30
  AdapterRegistry.defaultRegistryInstance = new AdapterRegistry();
25
- const { PostgresAdapter: PostgresAdapter$1 } = await import("./PostgresAdapter-DCF8T4vh.js");
26
- const { SqliteAdapter: SqliteAdapter$1 } = await import("./SqliteAdapter-CBnxCznk.js");
31
+ const { PostgresAdapter: PostgresAdapter$1 } = await import("./PostgresAdapter-CBc1u8eT.js");
32
+ const { SqliteAdapter: SqliteAdapter$1 } = await import("./SqliteAdapter-BJKNxCvS.js");
27
33
  AdapterRegistry.defaultRegistryInstance.register(new PostgresAdapter$1());
28
34
  AdapterRegistry.defaultRegistryInstance.register(new SqliteAdapter$1());
29
35
  return AdapterRegistry.defaultRegistryInstance;
30
36
  }
37
+ /**
38
+ * Register an adapter under its declared `name`.
39
+ */
31
40
  register(adapter) {
32
41
  this.adapters.set(adapter.name, adapter);
33
42
  return this;
34
43
  }
44
+ /**
45
+ * Resolve an adapter by name, or throw a descriptive error.
46
+ */
35
47
  get(name) {
36
48
  const adapter = this.adapters.get(name);
37
49
  if (!adapter) {
@@ -40,6 +52,9 @@ var AdapterRegistry = class AdapterRegistry {
40
52
  }
41
53
  return adapter;
42
54
  }
55
+ /**
56
+ * Check whether an adapter has been registered.
57
+ */
43
58
  has(name) {
44
59
  return this.adapters.has(name);
45
60
  }
@@ -99,4 +114,4 @@ __export(connection_exports, {
99
114
 
100
115
  //#endregion
101
116
  export { AdapterRegistry, adapters_exports, clients_exports, connectDB, connection_exports, getDefaultAdapterRegistry };
102
- //# sourceMappingURL=connection-DytAsjC9.js.map
117
+ //# sourceMappingURL=connection-CVvycXus.js.map