@danceroutine/tango-orm 0.1.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/PostgresAdapter-DCF8T4vh.js +3 -0
- package/dist/PostgresAdapter-_X36-mLL.js +73 -0
- package/dist/PostgresAdapter-_X36-mLL.js.map +1 -0
- package/dist/QuerySet-BzR5QzGi.js +411 -0
- package/dist/QuerySet-BzR5QzGi.js.map +1 -0
- package/dist/SqliteAdapter-CBnxCznk.js +3 -0
- package/dist/SqliteAdapter-J03fEjmr.js +70 -0
- package/dist/SqliteAdapter-J03fEjmr.js.map +1 -0
- package/dist/chunk-DLY2FNSh.js +12 -0
- package/dist/connection/adapters/Adapter.d.ts +20 -0
- package/dist/connection/adapters/AdapterRegistry.d.ts +17 -0
- package/dist/connection/adapters/dialects/PostgresAdapter.d.ts +22 -0
- package/dist/connection/adapters/dialects/SqliteAdapter.d.ts +14 -0
- package/dist/connection/adapters/dialects/index.d.ts +5 -0
- package/dist/connection/adapters/index.d.ts +8 -0
- package/dist/connection/clients/DBClient.d.ts +9 -0
- package/dist/connection/clients/DBClient.js +1 -0
- package/dist/connection/clients/dialects/PostgresClient.d.ts +17 -0
- package/dist/connection/clients/dialects/PostgresClient.js +32 -0
- package/dist/connection/clients/dialects/SqliteClient.d.ts +17 -0
- package/dist/connection/clients/dialects/SqliteClient.js +44 -0
- package/dist/connection/clients/dialects/index.d.ts +5 -0
- package/dist/connection/clients/index.d.ts +7 -0
- package/dist/connection/index.d.ts +11 -0
- package/dist/connection/index.js +5 -0
- package/dist/connection-DytAsjC9.js +102 -0
- package/dist/connection-DytAsjC9.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +9 -0
- package/dist/query/QBuilder.d.ts +11 -0
- package/dist/query/QuerySet.d.ts +64 -0
- package/dist/query/QuerySet.js +108 -0
- package/dist/query/compiler/QueryCompiler.d.ts +20 -0
- package/dist/query/compiler/QueryCompiler.js +183 -0
- package/dist/query/compiler/index.d.ts +4 -0
- package/dist/query/domain/CompiledQuery.d.ts +4 -0
- package/dist/query/domain/CompiledQuery.js +1 -0
- package/dist/query/domain/Dialect.d.ts +2 -0
- package/dist/query/domain/Direction.d.ts +2 -0
- package/dist/query/domain/FilterInput.d.ts +3 -0
- package/dist/query/domain/FilterKey.d.ts +2 -0
- package/dist/query/domain/FilterValue.d.ts +1 -0
- package/dist/query/domain/LookupType.d.ts +2 -0
- package/dist/query/domain/OrderSpec.d.ts +5 -0
- package/dist/query/domain/OrderToken.d.ts +1 -0
- package/dist/query/domain/QNode.d.ts +9 -0
- package/dist/query/domain/QueryResult.d.ts +4 -0
- package/dist/query/domain/QuerySetState.d.ts +13 -0
- package/dist/query/domain/RelationMeta.d.ts +10 -0
- package/dist/query/domain/RepositoryMeta.d.ts +7 -0
- package/dist/query/domain/WhereClause.d.ts +4 -0
- package/dist/query/domain/WhereClause.js +1 -0
- package/dist/query/domain/index.d.ts +18 -0
- package/dist/query/domain/internal/InternalDialect.d.ts +4 -0
- package/dist/query/domain/internal/InternalDirection.d.ts +4 -0
- package/dist/query/domain/internal/InternalLookupType.d.ts +15 -0
- package/dist/query/domain/internal/InternalQNodeType.d.ts +6 -0
- package/dist/query/domain/internal/InternalRelationKind.d.ts +5 -0
- package/dist/query/index.d.ts +12 -0
- package/dist/query/index.js +4 -0
- package/dist/query-CQbvLeuh.js +21 -0
- package/dist/query-CQbvLeuh.js.map +1 -0
- package/dist/repository/Repository.d.ts +40 -0
- package/dist/repository/Repository.js +100 -0
- package/dist/repository/index.d.ts +4 -0
- package/dist/repository/index.js +4 -0
- package/dist/repository-DaRvsfjs.js +78 -0
- package/dist/repository-DaRvsfjs.js.map +1 -0
- package/dist/transaction/UnitOfWork.d.ts +31 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction-DIGJnp19.js +50 -0
- package/dist/transaction-DIGJnp19.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DBClient } from '../clients/DBClient';
|
|
2
|
+
export interface AdapterConfig {
|
|
3
|
+
url?: string;
|
|
4
|
+
host?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
database?: string;
|
|
7
|
+
user?: string;
|
|
8
|
+
password?: string;
|
|
9
|
+
filename?: string;
|
|
10
|
+
maxConnections?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface Adapter {
|
|
13
|
+
name: string;
|
|
14
|
+
connect(config: AdapterConfig): Promise<DBClient>;
|
|
15
|
+
features: {
|
|
16
|
+
transactionalDDL: boolean;
|
|
17
|
+
concurrentIndex: boolean;
|
|
18
|
+
validateForeignKeys: boolean;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Adapter, AdapterConfig } from './Adapter';
|
|
2
|
+
import type { DBClient } from '../clients/DBClient';
|
|
3
|
+
export declare class AdapterRegistry {
|
|
4
|
+
static readonly BRAND: "tango.orm.adapter_registry";
|
|
5
|
+
readonly __tangoBrand: typeof AdapterRegistry.BRAND;
|
|
6
|
+
private static defaultRegistryInstance;
|
|
7
|
+
private adapters;
|
|
8
|
+
static isAdapterRegistry(value: unknown): value is AdapterRegistry;
|
|
9
|
+
static getDefaultRegistry(): Promise<AdapterRegistry>;
|
|
10
|
+
register(adapter: Adapter): this;
|
|
11
|
+
get(name: string): Adapter;
|
|
12
|
+
has(name: string): boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function connectDB(config: AdapterConfig & {
|
|
15
|
+
adapter: string;
|
|
16
|
+
}, registry?: AdapterRegistry): Promise<DBClient>;
|
|
17
|
+
export declare function getDefaultAdapterRegistry(): Promise<AdapterRegistry>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Adapter, AdapterConfig } from '../Adapter';
|
|
2
|
+
import type { DBClient } from '../../clients/DBClient';
|
|
3
|
+
export declare class PostgresAdapter implements Adapter {
|
|
4
|
+
static readonly BRAND: "tango.orm.postgres_adapter";
|
|
5
|
+
readonly __tangoBrand: typeof PostgresAdapter.BRAND;
|
|
6
|
+
readonly name = "postgres";
|
|
7
|
+
static isPostgresAdapter(value: unknown): value is PostgresAdapter;
|
|
8
|
+
/**
|
|
9
|
+
* Declares capabilities of this database adapter.
|
|
10
|
+
* Used by the migration runner and query compiler to determine which
|
|
11
|
+
* SQL features can be safely used:
|
|
12
|
+
* - transactionalDDL: Postgres supports DDL inside transactions (safe rollback of schema changes)
|
|
13
|
+
* - concurrentIndex: Supports CREATE INDEX CONCURRENTLY (non-blocking index builds)
|
|
14
|
+
* - validateForeignKeys: Supports deferred FK validation via NOT VALID + VALIDATE CONSTRAINT
|
|
15
|
+
*/
|
|
16
|
+
readonly features: {
|
|
17
|
+
transactionalDDL: boolean;
|
|
18
|
+
concurrentIndex: boolean;
|
|
19
|
+
validateForeignKeys: boolean;
|
|
20
|
+
};
|
|
21
|
+
connect(config: AdapterConfig): Promise<DBClient>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Adapter, AdapterConfig } from '../Adapter';
|
|
2
|
+
import type { DBClient } from '../../clients/DBClient';
|
|
3
|
+
export declare class SqliteAdapter implements Adapter {
|
|
4
|
+
static readonly BRAND: "tango.orm.sqlite_adapter";
|
|
5
|
+
readonly __tangoBrand: typeof SqliteAdapter.BRAND;
|
|
6
|
+
readonly name = "sqlite";
|
|
7
|
+
readonly features: {
|
|
8
|
+
transactionalDDL: boolean;
|
|
9
|
+
concurrentIndex: boolean;
|
|
10
|
+
validateForeignKeys: boolean;
|
|
11
|
+
};
|
|
12
|
+
static isSqliteAdapter(value: unknown): value is SqliteAdapter;
|
|
13
|
+
connect(config: AdapterConfig): Promise<DBClient>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain boundary barrel: exposes namespaced exports for Django-style drill-down
|
|
3
|
+
* imports and curated flat exports for TS-native ergonomics.
|
|
4
|
+
*/
|
|
5
|
+
export * as dialects from './dialects/index';
|
|
6
|
+
export { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './AdapterRegistry';
|
|
7
|
+
export type { Adapter, AdapterConfig } from './Adapter';
|
|
8
|
+
export { PostgresAdapter, SqliteAdapter } from './dialects/index';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type pg from 'pg';
|
|
2
|
+
import type { DBClient } from '../DBClient';
|
|
3
|
+
export declare class PostgresClient implements DBClient {
|
|
4
|
+
private pool;
|
|
5
|
+
private client;
|
|
6
|
+
static readonly BRAND: "tango.orm.postgres_client";
|
|
7
|
+
readonly __tangoBrand: typeof PostgresClient.BRAND;
|
|
8
|
+
static isPostgresClient(value: unknown): value is PostgresClient;
|
|
9
|
+
constructor(pool: pg.Pool, client: pg.PoolClient);
|
|
10
|
+
query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
|
|
11
|
+
rows: T[];
|
|
12
|
+
}>;
|
|
13
|
+
begin(): Promise<void>;
|
|
14
|
+
commit(): Promise<void>;
|
|
15
|
+
rollback(): Promise<void>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class PostgresClient {
|
|
2
|
+
pool;
|
|
3
|
+
client;
|
|
4
|
+
static BRAND = 'tango.orm.postgres_client';
|
|
5
|
+
__tangoBrand = PostgresClient.BRAND;
|
|
6
|
+
static isPostgresClient(value) {
|
|
7
|
+
return (typeof value === 'object' &&
|
|
8
|
+
value !== null &&
|
|
9
|
+
value.__tangoBrand === PostgresClient.BRAND);
|
|
10
|
+
}
|
|
11
|
+
constructor(pool, client) {
|
|
12
|
+
this.pool = pool;
|
|
13
|
+
this.client = client;
|
|
14
|
+
}
|
|
15
|
+
async query(sql, params) {
|
|
16
|
+
const result = await this.client.query(sql, params);
|
|
17
|
+
return { rows: result.rows };
|
|
18
|
+
}
|
|
19
|
+
async begin() {
|
|
20
|
+
await this.client.query('BEGIN');
|
|
21
|
+
}
|
|
22
|
+
async commit() {
|
|
23
|
+
await this.client.query('COMMIT');
|
|
24
|
+
}
|
|
25
|
+
async rollback() {
|
|
26
|
+
await this.client.query('ROLLBACK');
|
|
27
|
+
}
|
|
28
|
+
async close() {
|
|
29
|
+
this.client.release();
|
|
30
|
+
await this.pool.end();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3';
|
|
2
|
+
import type { DBClient } from '../DBClient';
|
|
3
|
+
export declare class SqliteClient implements DBClient {
|
|
4
|
+
private db;
|
|
5
|
+
static readonly BRAND: "tango.orm.sqlite_client";
|
|
6
|
+
readonly __tangoBrand: typeof SqliteClient.BRAND;
|
|
7
|
+
private inTransaction;
|
|
8
|
+
static isSqliteClient(value: unknown): value is SqliteClient;
|
|
9
|
+
constructor(db: Database.Database);
|
|
10
|
+
query<T = unknown>(sql: string, params?: readonly unknown[]): Promise<{
|
|
11
|
+
rows: T[];
|
|
12
|
+
}>;
|
|
13
|
+
begin(): Promise<void>;
|
|
14
|
+
commit(): Promise<void>;
|
|
15
|
+
rollback(): Promise<void>;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export class SqliteClient {
|
|
2
|
+
db;
|
|
3
|
+
static BRAND = 'tango.orm.sqlite_client';
|
|
4
|
+
__tangoBrand = SqliteClient.BRAND;
|
|
5
|
+
inTransaction = false;
|
|
6
|
+
static isSqliteClient(value) {
|
|
7
|
+
return (typeof value === 'object' &&
|
|
8
|
+
value !== null &&
|
|
9
|
+
value.__tangoBrand === SqliteClient.BRAND);
|
|
10
|
+
}
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
}
|
|
14
|
+
async query(sql, params) {
|
|
15
|
+
const stmt = this.db.prepare(sql);
|
|
16
|
+
if (/^\s*(SELECT|PRAGMA)/i.test(sql)) {
|
|
17
|
+
const rows = params ? stmt.all(...params) : stmt.all();
|
|
18
|
+
return { rows: rows };
|
|
19
|
+
}
|
|
20
|
+
params ? stmt.run(...params) : stmt.run();
|
|
21
|
+
return { rows: [] };
|
|
22
|
+
}
|
|
23
|
+
async begin() {
|
|
24
|
+
if (!this.inTransaction) {
|
|
25
|
+
this.db.prepare('BEGIN').run();
|
|
26
|
+
this.inTransaction = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async commit() {
|
|
30
|
+
if (this.inTransaction) {
|
|
31
|
+
this.db.prepare('COMMIT').run();
|
|
32
|
+
this.inTransaction = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async rollback() {
|
|
36
|
+
if (this.inTransaction) {
|
|
37
|
+
this.db.prepare('ROLLBACK').run();
|
|
38
|
+
this.inTransaction = false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async close() {
|
|
42
|
+
this.db.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain boundary barrel: exposes namespaced exports for Django-style drill-down
|
|
3
|
+
* imports and curated flat exports for TS-native ergonomics.
|
|
4
|
+
*/
|
|
5
|
+
export * as dialects from './dialects/index';
|
|
6
|
+
export type { DBClient } from './DBClient';
|
|
7
|
+
export { PostgresClient, SqliteClient } from './dialects/index';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain boundary barrel: exposes namespaced exports for Django-style drill-down
|
|
3
|
+
* imports and curated flat exports for TS-native ergonomics.
|
|
4
|
+
*/
|
|
5
|
+
export * as adapters from './adapters/index';
|
|
6
|
+
export * as clients from './clients/index';
|
|
7
|
+
export { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './adapters/index';
|
|
8
|
+
export type { Adapter, AdapterConfig } from './adapters/index';
|
|
9
|
+
export type { DBClient } from './clients/DBClient';
|
|
10
|
+
export { PostgresAdapter, SqliteAdapter } from './adapters/index';
|
|
11
|
+
export { PostgresClient, SqliteClient } from './clients/index';
|
|
@@ -0,0 +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";
|
|
4
|
+
|
|
5
|
+
export { AdapterRegistry, PostgresAdapter, PostgresClient, SqliteAdapter, SqliteClient, adapters_exports as adapters, clients_exports as clients, connectDB, getDefaultAdapterRegistry };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { __export } from "./chunk-DLY2FNSh.js";
|
|
2
|
+
import { PostgresAdapter, PostgresClient } from "./PostgresAdapter-_X36-mLL.js";
|
|
3
|
+
import { SqliteAdapter, SqliteClient } from "./SqliteAdapter-J03fEjmr.js";
|
|
4
|
+
|
|
5
|
+
//#region src/connection/adapters/dialects/index.ts
|
|
6
|
+
var dialects_exports$1 = {};
|
|
7
|
+
__export(dialects_exports$1, {
|
|
8
|
+
PostgresAdapter: () => PostgresAdapter,
|
|
9
|
+
SqliteAdapter: () => SqliteAdapter
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/connection/adapters/AdapterRegistry.ts
|
|
14
|
+
var AdapterRegistry = class AdapterRegistry {
|
|
15
|
+
static BRAND = "tango.orm.adapter_registry";
|
|
16
|
+
__tangoBrand = AdapterRegistry.BRAND;
|
|
17
|
+
static defaultRegistryInstance;
|
|
18
|
+
adapters = new Map();
|
|
19
|
+
static isAdapterRegistry(value) {
|
|
20
|
+
return typeof value === "object" && value !== null && value.__tangoBrand === AdapterRegistry.BRAND;
|
|
21
|
+
}
|
|
22
|
+
static async getDefaultRegistry() {
|
|
23
|
+
if (AdapterRegistry.defaultRegistryInstance) return AdapterRegistry.defaultRegistryInstance;
|
|
24
|
+
AdapterRegistry.defaultRegistryInstance = new AdapterRegistry();
|
|
25
|
+
const { PostgresAdapter: PostgresAdapter$1 } = await import("./PostgresAdapter-DCF8T4vh.js");
|
|
26
|
+
const { SqliteAdapter: SqliteAdapter$1 } = await import("./SqliteAdapter-CBnxCznk.js");
|
|
27
|
+
AdapterRegistry.defaultRegistryInstance.register(new PostgresAdapter$1());
|
|
28
|
+
AdapterRegistry.defaultRegistryInstance.register(new SqliteAdapter$1());
|
|
29
|
+
return AdapterRegistry.defaultRegistryInstance;
|
|
30
|
+
}
|
|
31
|
+
register(adapter) {
|
|
32
|
+
this.adapters.set(adapter.name, adapter);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
get(name) {
|
|
36
|
+
const adapter = this.adapters.get(name);
|
|
37
|
+
if (!adapter) {
|
|
38
|
+
const available = [...this.adapters.keys()].join(", ");
|
|
39
|
+
throw new Error(`Unknown adapter: ${name}. Available adapters: ${available || "none"}`);
|
|
40
|
+
}
|
|
41
|
+
return adapter;
|
|
42
|
+
}
|
|
43
|
+
has(name) {
|
|
44
|
+
return this.adapters.has(name);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
async function connectDB(config, registry) {
|
|
48
|
+
const effectiveRegistry = registry ?? await AdapterRegistry.getDefaultRegistry();
|
|
49
|
+
const adapter = effectiveRegistry.get(config.adapter);
|
|
50
|
+
return adapter.connect(config);
|
|
51
|
+
}
|
|
52
|
+
async function getDefaultAdapterRegistry() {
|
|
53
|
+
return AdapterRegistry.getDefaultRegistry();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/connection/adapters/index.ts
|
|
58
|
+
var adapters_exports = {};
|
|
59
|
+
__export(adapters_exports, {
|
|
60
|
+
AdapterRegistry: () => AdapterRegistry,
|
|
61
|
+
PostgresAdapter: () => PostgresAdapter,
|
|
62
|
+
SqliteAdapter: () => SqliteAdapter,
|
|
63
|
+
connectDB: () => connectDB,
|
|
64
|
+
dialects: () => dialects_exports$1,
|
|
65
|
+
getDefaultAdapterRegistry: () => getDefaultAdapterRegistry
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/connection/clients/dialects/index.ts
|
|
70
|
+
var dialects_exports = {};
|
|
71
|
+
__export(dialects_exports, {
|
|
72
|
+
PostgresClient: () => PostgresClient,
|
|
73
|
+
SqliteClient: () => SqliteClient
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/connection/clients/index.ts
|
|
78
|
+
var clients_exports = {};
|
|
79
|
+
__export(clients_exports, {
|
|
80
|
+
PostgresClient: () => PostgresClient,
|
|
81
|
+
SqliteClient: () => SqliteClient,
|
|
82
|
+
dialects: () => dialects_exports
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/connection/index.ts
|
|
87
|
+
var connection_exports = {};
|
|
88
|
+
__export(connection_exports, {
|
|
89
|
+
AdapterRegistry: () => AdapterRegistry,
|
|
90
|
+
PostgresAdapter: () => PostgresAdapter,
|
|
91
|
+
PostgresClient: () => PostgresClient,
|
|
92
|
+
SqliteAdapter: () => SqliteAdapter,
|
|
93
|
+
SqliteClient: () => SqliteClient,
|
|
94
|
+
adapters: () => adapters_exports,
|
|
95
|
+
clients: () => clients_exports,
|
|
96
|
+
connectDB: () => connectDB,
|
|
97
|
+
getDefaultAdapterRegistry: () => getDefaultAdapterRegistry
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
export { AdapterRegistry, adapters_exports, clients_exports, connectDB, connection_exports, getDefaultAdapterRegistry };
|
|
102
|
+
//# sourceMappingURL=connection-DytAsjC9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection-DytAsjC9.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';\nexport class AdapterRegistry {\n static readonly BRAND = 'tango.orm.adapter_registry' as const;\n readonly __tangoBrand: typeof AdapterRegistry.BRAND = AdapterRegistry.BRAND;\n private static defaultRegistryInstance: AdapterRegistry | undefined;\n\n private adapters = new Map<string, Adapter>();\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 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 register(adapter: Adapter): this {\n this.adapters.set(adapter.name, adapter);\n return this;\n }\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 has(name: string): boolean {\n return this.adapters.has(name);\n }\n}\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\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":";;;;;;;;;;;;;ICEa,kBAAN,MAAM,gBAAgB;CACzB,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;CACtE,OAAe;CAEf,WAAmB,IAAI;CAEvB,OAAO,kBAAkBA,OAA0C;AAC/D,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE9E;CAED,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;CAED,SAASC,SAAwB;AAC7B,OAAK,SAAS,IAAI,QAAQ,MAAM,QAAQ;AACxC,SAAO;CACV;CAED,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;CAED,IAAIA,MAAuB;AACvB,SAAO,KAAK,SAAS,IAAI,KAAK;CACjC;AACJ;AAEM,eAAe,UAClBC,QACAC,UACiB;CACjB,MAAM,oBAAoB,YAAa,MAAM,gBAAgB,oBAAoB;CACjF,MAAM,UAAU,kBAAkB,IAAI,OAAO,QAAQ;AACrD,QAAO,QAAQ,QAAQ,OAAO;AACjC;AAEM,eAAe,4BAAsD;AACxE,QAAO,gBAAgB,oBAAoB;AAC9C"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundled exports for Django users who are used to Django domain-drill-down imports
|
|
3
|
+
*/
|
|
4
|
+
export * as connection from './connection/index';
|
|
5
|
+
export * as query from './query/index';
|
|
6
|
+
export * as repository from './repository/index';
|
|
7
|
+
export * as transaction from './transaction/index';
|
|
8
|
+
/**
|
|
9
|
+
* Unbundled exports for more TS native developers
|
|
10
|
+
*/
|
|
11
|
+
export { AdapterRegistry, connectDB, getDefaultAdapterRegistry } from './connection/index';
|
|
12
|
+
export type { Adapter, AdapterConfig, DBClient } from './connection/index';
|
|
13
|
+
export { PostgresAdapter, SqliteAdapter } from './connection/index';
|
|
14
|
+
export { Q, QBuilder, QueryCompiler, QuerySet } from './query/index';
|
|
15
|
+
export type { RepositoryLike } from './query/index';
|
|
16
|
+
export type { CompiledQuery, Dialect, Direction, FilterInput, FilterKey, FilterValue, LookupType, OrderSpec, OrderToken, QNode, QueryResult, QuerySetState, RelationMeta, RepoMeta, WhereClause, } from './query/domain/index';
|
|
17
|
+
export { Repository } from './repository/index';
|
|
18
|
+
export { UnitOfWork } from './transaction/index';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PostgresAdapter } from "./PostgresAdapter-_X36-mLL.js";
|
|
2
|
+
import { SqliteAdapter } from "./SqliteAdapter-J03fEjmr.js";
|
|
3
|
+
import { AdapterRegistry, connectDB, connection_exports, getDefaultAdapterRegistry } from "./connection-DytAsjC9.js";
|
|
4
|
+
import { QBuilder, QueryCompiler, QuerySet } from "./QuerySet-BzR5QzGi.js";
|
|
5
|
+
import { query_exports } from "./query-CQbvLeuh.js";
|
|
6
|
+
import { Repository, repository_exports } from "./repository-DaRvsfjs.js";
|
|
7
|
+
import { UnitOfWork, transaction_exports } from "./transaction-DIGJnp19.js";
|
|
8
|
+
|
|
9
|
+
export { AdapterRegistry, PostgresAdapter, QBuilder as Q, QBuilder, QueryCompiler, QuerySet, Repository, SqliteAdapter, UnitOfWork, connectDB, connection_exports as connection, getDefaultAdapterRegistry, query_exports as query, repository_exports as repository, transaction_exports as transaction };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { QNode } from './domain/QNode';
|
|
2
|
+
import type { FilterInput } from './domain/FilterInput';
|
|
3
|
+
export declare class QBuilder {
|
|
4
|
+
static readonly BRAND: "tango.orm.q_builder";
|
|
5
|
+
readonly __tangoBrand: typeof QBuilder.BRAND;
|
|
6
|
+
static isQBuilder(value: unknown): value is QBuilder;
|
|
7
|
+
static and<T>(...nodes: Array<FilterInput<T> | QNode<T>>): QNode<T>;
|
|
8
|
+
static or<T>(...nodes: Array<FilterInput<T> | QNode<T>>): QNode<T>;
|
|
9
|
+
static not<T>(node: FilterInput<T> | QNode<T>): QNode<T>;
|
|
10
|
+
private static wrapNode;
|
|
11
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { DBClient } from '../connection/clients/DBClient';
|
|
2
|
+
import type { Dialect } from './domain/Dialect';
|
|
3
|
+
import type { QuerySetState } from './domain/QuerySetState';
|
|
4
|
+
import type { RepositoryMeta } from './domain/RepositoryMeta';
|
|
5
|
+
import type { QNode } from './domain/QNode';
|
|
6
|
+
import type { QueryResult } from './domain/QueryResult';
|
|
7
|
+
import type { OrderToken } from './domain/OrderToken';
|
|
8
|
+
import type { FilterInput } from './domain/FilterInput';
|
|
9
|
+
/**
|
|
10
|
+
* Interface for repository-like objects that can execute queries.
|
|
11
|
+
* Used internally by QuerySet to remain decoupled from specific repository implementations.
|
|
12
|
+
*
|
|
13
|
+
* @template T - The model type
|
|
14
|
+
*/
|
|
15
|
+
export interface RepositoryLike<T> {
|
|
16
|
+
meta: RepositoryMeta;
|
|
17
|
+
client: DBClient;
|
|
18
|
+
dialect: Dialect;
|
|
19
|
+
run(compiled: {
|
|
20
|
+
sql: string;
|
|
21
|
+
params: readonly unknown[];
|
|
22
|
+
}): Promise<T[]>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Django-inspired query builder for constructing and executing database queries.
|
|
26
|
+
* Provides a fluent API for filtering, ordering, pagination, and eager loading.
|
|
27
|
+
*
|
|
28
|
+
* @template T - The model type being queried
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const users = await repository
|
|
33
|
+
* .query()
|
|
34
|
+
* .filter({ active: true })
|
|
35
|
+
* .filter(Q.or({ role: 'admin' }, { role: 'moderator' }))
|
|
36
|
+
* .orderBy('-createdAt')
|
|
37
|
+
* .limit(10)
|
|
38
|
+
* .fetchAll();
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare class QuerySet<T extends Record<string, unknown>> {
|
|
42
|
+
private repo;
|
|
43
|
+
private state;
|
|
44
|
+
static readonly BRAND: "tango.orm.query_set";
|
|
45
|
+
readonly __tangoBrand: typeof QuerySet.BRAND;
|
|
46
|
+
static isQuerySet<T extends Record<string, unknown>>(value: unknown): value is QuerySet<T>;
|
|
47
|
+
constructor(repo: RepositoryLike<T>, state?: QuerySetState<T>);
|
|
48
|
+
filter(q: FilterInput<T> | QNode<T>): QuerySet<T>;
|
|
49
|
+
exclude(q: FilterInput<T> | QNode<T>): QuerySet<T>;
|
|
50
|
+
orderBy(...tokens: OrderToken<T>[]): QuerySet<T>;
|
|
51
|
+
limit(n: number): QuerySet<T>;
|
|
52
|
+
offset(n: number): QuerySet<T>;
|
|
53
|
+
select(cols: (keyof T)[]): QuerySet<T>;
|
|
54
|
+
selectRelated(...rels: string[]): QuerySet<T>;
|
|
55
|
+
prefetchRelated(...rels: string[]): QuerySet<T>;
|
|
56
|
+
fetch<Out = T>(shape?: ((r: T) => Out) | {
|
|
57
|
+
parse: (r: T) => Out;
|
|
58
|
+
}): Promise<QueryResult<Out>>;
|
|
59
|
+
fetchOne<Out = T>(shape?: ((r: T) => Out) | {
|
|
60
|
+
parse: (r: T) => Out;
|
|
61
|
+
}): Promise<Out | null>;
|
|
62
|
+
count(): Promise<number>;
|
|
63
|
+
exists(): Promise<boolean>;
|
|
64
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { InternalQNodeType } from './domain/internal/InternalQNodeType';
|
|
2
|
+
import { InternalDirection } from './domain/internal/InternalDirection';
|
|
3
|
+
import { QBuilder as Q } from './QBuilder';
|
|
4
|
+
import { QueryCompiler } from './compiler';
|
|
5
|
+
/**
|
|
6
|
+
* Django-inspired query builder for constructing and executing database queries.
|
|
7
|
+
* Provides a fluent API for filtering, ordering, pagination, and eager loading.
|
|
8
|
+
*
|
|
9
|
+
* @template T - The model type being queried
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const users = await repository
|
|
14
|
+
* .query()
|
|
15
|
+
* .filter({ active: true })
|
|
16
|
+
* .filter(Q.or({ role: 'admin' }, { role: 'moderator' }))
|
|
17
|
+
* .orderBy('-createdAt')
|
|
18
|
+
* .limit(10)
|
|
19
|
+
* .fetchAll();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export class QuerySet {
|
|
23
|
+
repo;
|
|
24
|
+
state;
|
|
25
|
+
static BRAND = 'tango.orm.query_set';
|
|
26
|
+
__tangoBrand = QuerySet.BRAND;
|
|
27
|
+
static isQuerySet(value) {
|
|
28
|
+
return (typeof value === 'object' &&
|
|
29
|
+
value !== null &&
|
|
30
|
+
value.__tangoBrand === QuerySet.BRAND);
|
|
31
|
+
}
|
|
32
|
+
constructor(repo, state = {}) {
|
|
33
|
+
this.repo = repo;
|
|
34
|
+
this.state = state;
|
|
35
|
+
}
|
|
36
|
+
filter(q) {
|
|
37
|
+
const wrapped = q.kind
|
|
38
|
+
? q
|
|
39
|
+
: { kind: InternalQNodeType.ATOM, where: q };
|
|
40
|
+
const merged = this.state.q ? Q.and(this.state.q, wrapped) : wrapped;
|
|
41
|
+
return new QuerySet(this.repo, { ...this.state, q: merged });
|
|
42
|
+
}
|
|
43
|
+
exclude(q) {
|
|
44
|
+
const wrapped = q.kind
|
|
45
|
+
? q
|
|
46
|
+
: { kind: InternalQNodeType.ATOM, where: q };
|
|
47
|
+
const excludes = [...(this.state.excludes ?? []), wrapped];
|
|
48
|
+
return new QuerySet(this.repo, { ...this.state, excludes });
|
|
49
|
+
}
|
|
50
|
+
orderBy(...tokens) {
|
|
51
|
+
const order = tokens.map((t) => {
|
|
52
|
+
const str = String(t);
|
|
53
|
+
if (str.startsWith('-')) {
|
|
54
|
+
return { by: str.slice(1), dir: InternalDirection.DESC };
|
|
55
|
+
}
|
|
56
|
+
return { by: t, dir: InternalDirection.ASC };
|
|
57
|
+
});
|
|
58
|
+
return new QuerySet(this.repo, { ...this.state, order });
|
|
59
|
+
}
|
|
60
|
+
limit(n) {
|
|
61
|
+
return new QuerySet(this.repo, { ...this.state, limit: n });
|
|
62
|
+
}
|
|
63
|
+
offset(n) {
|
|
64
|
+
return new QuerySet(this.repo, { ...this.state, offset: n });
|
|
65
|
+
}
|
|
66
|
+
select(cols) {
|
|
67
|
+
return new QuerySet(this.repo, { ...this.state, select: cols });
|
|
68
|
+
}
|
|
69
|
+
selectRelated(...rels) {
|
|
70
|
+
return new QuerySet(this.repo, { ...this.state, selectRelated: rels });
|
|
71
|
+
}
|
|
72
|
+
prefetchRelated(...rels) {
|
|
73
|
+
return new QuerySet(this.repo, { ...this.state, prefetchRelated: rels });
|
|
74
|
+
}
|
|
75
|
+
async fetch(shape) {
|
|
76
|
+
const compiler = new QueryCompiler(this.repo.meta, this.repo.dialect);
|
|
77
|
+
const compiled = compiler.compile(this.state);
|
|
78
|
+
const rows = await this.repo.run(compiled);
|
|
79
|
+
const results = !shape
|
|
80
|
+
? rows
|
|
81
|
+
: typeof shape === 'function'
|
|
82
|
+
? rows.map(shape)
|
|
83
|
+
: rows.map((r) => shape.parse(r));
|
|
84
|
+
return {
|
|
85
|
+
results,
|
|
86
|
+
nextCursor: null,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async fetchOne(shape) {
|
|
90
|
+
const limited = this.limit(1);
|
|
91
|
+
const result = await limited.fetch(shape);
|
|
92
|
+
return result.results[0] ?? null;
|
|
93
|
+
}
|
|
94
|
+
async count() {
|
|
95
|
+
const compiler = new QueryCompiler(this.repo.meta, this.repo.dialect);
|
|
96
|
+
const compiled = compiler.compile({
|
|
97
|
+
...this.state,
|
|
98
|
+
select: ['COUNT(*) as count'],
|
|
99
|
+
});
|
|
100
|
+
const countQuery = compiled.sql.replace(/SELECT .+ FROM/, 'SELECT COUNT(*) as count FROM');
|
|
101
|
+
const rows = await this.repo.client.query(countQuery, compiled.params);
|
|
102
|
+
return Number(rows.rows[0]?.count ?? 0);
|
|
103
|
+
}
|
|
104
|
+
async exists() {
|
|
105
|
+
const count = await this.count();
|
|
106
|
+
return count > 0;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { QuerySetState } from '../domain/QuerySetState';
|
|
2
|
+
import type { RepositoryMeta } from '../domain/RepositoryMeta';
|
|
3
|
+
import type { CompiledQuery } from '../domain/CompiledQuery';
|
|
4
|
+
import type { Dialect } from '../domain/Dialect';
|
|
5
|
+
export declare class QueryCompiler {
|
|
6
|
+
private meta;
|
|
7
|
+
private dialect;
|
|
8
|
+
static readonly BRAND: "tango.orm.query_compiler";
|
|
9
|
+
readonly __tangoBrand: typeof QueryCompiler.BRAND;
|
|
10
|
+
static isQueryCompiler(value: unknown): value is QueryCompiler;
|
|
11
|
+
constructor(meta: RepositoryMeta, dialect?: Dialect);
|
|
12
|
+
compile<T>(state: QuerySetState<T>): CompiledQuery;
|
|
13
|
+
private compileQNode;
|
|
14
|
+
private compileAtom;
|
|
15
|
+
private compileAnd;
|
|
16
|
+
private compileOr;
|
|
17
|
+
private compileNot;
|
|
18
|
+
private lookupToSQL;
|
|
19
|
+
private normalizeParam;
|
|
20
|
+
}
|