@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.
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/dist/{PostgresAdapter-_X36-mLL.js → PostgresAdapter-C9a1XJRx.js} +31 -7
- package/dist/PostgresAdapter-C9a1XJRx.js.map +1 -0
- package/dist/PostgresAdapter-CBc1u8eT.js +3 -0
- package/dist/SqliteAdapter-BJKNxCvS.js +3 -0
- package/dist/SqliteAdapter-Dp6VRXmz.js +118 -0
- package/dist/SqliteAdapter-Dp6VRXmz.js.map +1 -0
- package/dist/connection/adapters/Adapter.d.ts +9 -0
- package/dist/connection/adapters/AdapterRegistry.d.ts +28 -1
- package/dist/connection/adapters/dialects/PostgresAdapter.d.ts +10 -1
- package/dist/connection/adapters/dialects/SqliteAdapter.d.ts +11 -1
- package/dist/connection/clients/DBClient.d.ts +8 -0
- package/dist/connection/clients/dialects/PostgresClient.d.ts +22 -1
- package/dist/connection/clients/dialects/SqliteClient.d.ts +26 -1
- package/dist/connection/index.js +3 -3
- package/dist/{connection-DytAsjC9.js → connection-CVvycXus.js} +21 -6
- package/dist/connection-CVvycXus.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +9 -8
- package/dist/manager/ManagerLike.d.ts +15 -0
- package/dist/manager/ModelManager.d.ts +48 -0
- package/dist/manager/index.d.ts +6 -0
- package/dist/manager/index.js +8 -0
- package/dist/manager/internal/MutationCompiler.d.ts +15 -0
- package/dist/manager/internal/RuntimeBoundClient.d.ts +16 -0
- package/dist/manager/registerModelObjects.d.ts +5 -0
- package/dist/manager-D6tU8xTO.js +13 -0
- package/dist/manager-D6tU8xTO.js.map +1 -0
- package/dist/query/QBuilder.d.ts +18 -0
- package/dist/query/QuerySet.d.ts +60 -9
- package/dist/query/compiler/QueryCompiler.d.ts +19 -2
- package/dist/query/domain/{RepositoryMeta.d.ts → TableMeta.d.ts} +1 -1
- package/dist/query/domain/index.d.ts +1 -1
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +1 -2
- package/dist/query-wnl4h2o7.js +671 -0
- package/dist/query-wnl4h2o7.js.map +1 -0
- package/dist/registerModelObjects-emX7Hja9.js +354 -0
- package/dist/registerModelObjects-emX7Hja9.js.map +1 -0
- package/dist/runtime/TangoRuntime.d.ts +34 -0
- package/dist/runtime/defaultRuntime.d.ts +13 -0
- package/dist/runtime/index.d.ts +13 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime-7U5_XDad.js +17 -0
- package/dist/runtime-7U5_XDad.js.map +1 -0
- package/dist/transaction/UnitOfWork.d.ts +21 -3
- package/dist/transaction/index.js +1 -1
- package/dist/{transaction-DIGJnp19.js → transaction-DooTMuAl.js} +29 -11
- package/dist/transaction-DooTMuAl.js.map +1 -0
- package/dist/validation/OrmSqlSafetyAdapter.d.ts +22 -0
- package/dist/validation/SQLValidationEngine.d.ts +51 -0
- package/dist/validation/SqlValidationPlan.d.ts +42 -0
- package/dist/validation/index.d.ts +3 -0
- package/package.json +81 -74
- package/dist/PostgresAdapter-DCF8T4vh.js +0 -3
- package/dist/PostgresAdapter-_X36-mLL.js.map +0 -1
- package/dist/QuerySet-BzR5QzGi.js +0 -411
- package/dist/QuerySet-BzR5QzGi.js.map +0 -1
- package/dist/SqliteAdapter-CBnxCznk.js +0 -3
- package/dist/SqliteAdapter-J03fEjmr.js +0 -70
- package/dist/SqliteAdapter-J03fEjmr.js.map +0 -1
- package/dist/connection/clients/DBClient.js +0 -1
- package/dist/connection/clients/dialects/PostgresClient.js +0 -32
- package/dist/connection/clients/dialects/SqliteClient.js +0 -44
- package/dist/connection-DytAsjC9.js.map +0 -1
- package/dist/query/QuerySet.js +0 -108
- package/dist/query/compiler/QueryCompiler.js +0 -183
- package/dist/query/domain/CompiledQuery.js +0 -1
- package/dist/query/domain/WhereClause.js +0 -1
- package/dist/query-CQbvLeuh.js +0 -21
- package/dist/query-CQbvLeuh.js.map +0 -1
- package/dist/repository/Repository.d.ts +0 -40
- package/dist/repository/Repository.js +0 -100
- package/dist/repository/index.d.ts +0 -4
- package/dist/repository/index.js +0 -4
- package/dist/repository-DaRvsfjs.js +0 -78
- package/dist/repository-DaRvsfjs.js.map +0 -1
- package/dist/transaction-DIGJnp19.js.map +0 -1
package/dist/query/QuerySet.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { InternalDialect } from '../domain/internal/InternalDialect';
|
|
2
|
-
import { InternalQNodeType } from '../domain/internal/InternalQNodeType';
|
|
3
|
-
import { InternalLookupType } from '../domain/internal/InternalLookupType';
|
|
4
|
-
export class QueryCompiler {
|
|
5
|
-
meta;
|
|
6
|
-
dialect;
|
|
7
|
-
static BRAND = 'tango.orm.query_compiler';
|
|
8
|
-
__tangoBrand = QueryCompiler.BRAND;
|
|
9
|
-
static isQueryCompiler(value) {
|
|
10
|
-
return (typeof value === 'object' &&
|
|
11
|
-
value !== null &&
|
|
12
|
-
value.__tangoBrand === QueryCompiler.BRAND);
|
|
13
|
-
}
|
|
14
|
-
constructor(meta, dialect = InternalDialect.POSTGRES) {
|
|
15
|
-
this.meta = meta;
|
|
16
|
-
this.dialect = dialect;
|
|
17
|
-
}
|
|
18
|
-
compile(state) {
|
|
19
|
-
const whereParts = [];
|
|
20
|
-
const params = [];
|
|
21
|
-
if (state.q) {
|
|
22
|
-
const result = this.compileQNode(state.q, params.length + 1);
|
|
23
|
-
if (result.sql) {
|
|
24
|
-
whereParts.push(result.sql);
|
|
25
|
-
params.push(...result.params);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
state.excludes?.forEach((exclude) => {
|
|
29
|
-
const result = this.compileQNode({ kind: InternalQNodeType.NOT, node: exclude }, params.length + 1);
|
|
30
|
-
if (result.sql) {
|
|
31
|
-
whereParts.push(result.sql);
|
|
32
|
-
params.push(...result.params);
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
const select = state.select?.map(String).join(', ') || `${this.meta.table}.*`;
|
|
36
|
-
const joins = (state.selectRelated ?? [])
|
|
37
|
-
.map((rel) => {
|
|
38
|
-
const r = this.meta.relations?.[rel];
|
|
39
|
-
if (!r || r.kind !== 'belongsTo') {
|
|
40
|
-
return '';
|
|
41
|
-
}
|
|
42
|
-
return `LEFT JOIN ${r.table} ${r.alias} ON ${r.alias}.${r.targetPk} = ${this.meta.table}.${r.localKey}`;
|
|
43
|
-
})
|
|
44
|
-
.filter(Boolean)
|
|
45
|
-
.join(' ');
|
|
46
|
-
const whereSQL = whereParts.length ? ` WHERE ${whereParts.join(' AND ')}` : '';
|
|
47
|
-
const orderSQL = ` ORDER BY ${state.order?.length
|
|
48
|
-
? state.order.map((o) => `${this.meta.table}.${String(o.by)} ${o.dir.toUpperCase()}`).join(', ')
|
|
49
|
-
: `${this.meta.table}.${this.meta.pk} ASC`}`;
|
|
50
|
-
const limitSQL = state.limit ? ` LIMIT ${state.limit}` : '';
|
|
51
|
-
const offsetSQL = state.offset ? ` OFFSET ${state.offset}` : '';
|
|
52
|
-
const sql = `SELECT ${select} FROM ${this.meta.table}${joins ? ' ' + joins : ''}${whereSQL}${orderSQL}${limitSQL}${offsetSQL}`;
|
|
53
|
-
return { sql, params };
|
|
54
|
-
}
|
|
55
|
-
compileQNode(node, paramIndex) {
|
|
56
|
-
switch (node.kind) {
|
|
57
|
-
case InternalQNodeType.ATOM:
|
|
58
|
-
return this.compileAtom(node.where || {}, paramIndex);
|
|
59
|
-
case InternalQNodeType.AND:
|
|
60
|
-
return this.compileAnd(node.nodes || [], paramIndex);
|
|
61
|
-
case InternalQNodeType.OR:
|
|
62
|
-
return this.compileOr(node.nodes || [], paramIndex);
|
|
63
|
-
case InternalQNodeType.NOT:
|
|
64
|
-
return this.compileNot(node.node, paramIndex);
|
|
65
|
-
default:
|
|
66
|
-
return { sql: '', params: [] };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
compileAtom(where, paramIndex) {
|
|
70
|
-
const entries = Object.entries(where).filter(([, value]) => value !== undefined);
|
|
71
|
-
const { parts, params } = entries.reduce((accumulator, [key, value]) => {
|
|
72
|
-
const [field, lookup = InternalLookupType.EXACT] = String(key).split('__');
|
|
73
|
-
const col = `${this.meta.table}.${field}`;
|
|
74
|
-
const idx = paramIndex + accumulator.params.length;
|
|
75
|
-
const clause = this.lookupToSQL(col, lookup, value, idx);
|
|
76
|
-
accumulator.parts.push(clause.sql);
|
|
77
|
-
accumulator.params.push(...clause.params);
|
|
78
|
-
return accumulator;
|
|
79
|
-
}, { parts: [], params: [] });
|
|
80
|
-
return {
|
|
81
|
-
sql: parts.length ? `(${parts.join(' AND ')})` : '',
|
|
82
|
-
params,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
compileAnd(nodes, paramIndex) {
|
|
86
|
-
const { parts, params } = nodes.reduce((accumulator, node) => {
|
|
87
|
-
const result = this.compileQNode(node, paramIndex + accumulator.params.length);
|
|
88
|
-
if (result.sql) {
|
|
89
|
-
accumulator.parts.push(result.sql);
|
|
90
|
-
accumulator.params.push(...result.params);
|
|
91
|
-
}
|
|
92
|
-
return accumulator;
|
|
93
|
-
}, { parts: [], params: [] });
|
|
94
|
-
return {
|
|
95
|
-
sql: parts.length ? `(${parts.join(' AND ')})` : '',
|
|
96
|
-
params,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
compileOr(nodes, paramIndex) {
|
|
100
|
-
const { parts, params } = nodes.reduce((accumulator, node) => {
|
|
101
|
-
const result = this.compileQNode(node, paramIndex + accumulator.params.length);
|
|
102
|
-
if (result.sql) {
|
|
103
|
-
accumulator.parts.push(result.sql);
|
|
104
|
-
accumulator.params.push(...result.params);
|
|
105
|
-
}
|
|
106
|
-
return accumulator;
|
|
107
|
-
}, { parts: [], params: [] });
|
|
108
|
-
return {
|
|
109
|
-
sql: parts.length ? `(${parts.join(' OR ')})` : '',
|
|
110
|
-
params,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
compileNot(node, paramIndex) {
|
|
114
|
-
const result = this.compileQNode(node, paramIndex);
|
|
115
|
-
if (!result.sql) {
|
|
116
|
-
return { sql: '', params: [] };
|
|
117
|
-
}
|
|
118
|
-
return {
|
|
119
|
-
sql: `(NOT ${result.sql})`,
|
|
120
|
-
params: result.params,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
lookupToSQL(col, lookup, value, paramIndex) {
|
|
124
|
-
const placeholder = this.dialect === InternalDialect.POSTGRES ? `$${paramIndex}` : '?';
|
|
125
|
-
const normalized = this.normalizeParam(value);
|
|
126
|
-
switch (lookup) {
|
|
127
|
-
case InternalLookupType.EXACT:
|
|
128
|
-
if (value === null) {
|
|
129
|
-
return { sql: `${col} IS NULL`, params: [] };
|
|
130
|
-
}
|
|
131
|
-
return { sql: `${col} = ${placeholder}`, params: [normalized] };
|
|
132
|
-
case InternalLookupType.LT:
|
|
133
|
-
return { sql: `${col} < ${placeholder}`, params: [normalized] };
|
|
134
|
-
case InternalLookupType.LTE:
|
|
135
|
-
return { sql: `${col} <= ${placeholder}`, params: [normalized] };
|
|
136
|
-
case InternalLookupType.GT:
|
|
137
|
-
return { sql: `${col} > ${placeholder}`, params: [normalized] };
|
|
138
|
-
case InternalLookupType.GTE:
|
|
139
|
-
return { sql: `${col} >= ${placeholder}`, params: [normalized] };
|
|
140
|
-
case InternalLookupType.IN: {
|
|
141
|
-
const arr = (Array.isArray(value) ? value : [value]).map((entry) => this.normalizeParam(entry));
|
|
142
|
-
if (arr.length === 0) {
|
|
143
|
-
return { sql: '1=0', params: [] };
|
|
144
|
-
}
|
|
145
|
-
const placeholders = this.dialect === InternalDialect.POSTGRES
|
|
146
|
-
? arr.map((_, i) => `$${paramIndex + i}`).join(', ')
|
|
147
|
-
: arr.map(() => '?').join(', ');
|
|
148
|
-
return { sql: `${col} IN (${placeholders})`, params: arr };
|
|
149
|
-
}
|
|
150
|
-
case InternalLookupType.ISNULL:
|
|
151
|
-
return { sql: value ? `${col} IS NULL` : `${col} IS NOT NULL`, params: [] };
|
|
152
|
-
case InternalLookupType.CONTAINS:
|
|
153
|
-
return { sql: `${col} LIKE ${placeholder}`, params: [`%${value}%`] };
|
|
154
|
-
case InternalLookupType.ICONTAINS: {
|
|
155
|
-
const lowerCol = this.dialect === InternalDialect.POSTGRES ? `LOWER(${col})` : `${col}`;
|
|
156
|
-
const lowerValue = String(value).toLowerCase();
|
|
157
|
-
return { sql: `${lowerCol} LIKE ${placeholder}`, params: [`%${lowerValue}%`] };
|
|
158
|
-
}
|
|
159
|
-
case InternalLookupType.STARTSWITH:
|
|
160
|
-
return { sql: `${col} LIKE ${placeholder}`, params: [`${value}%`] };
|
|
161
|
-
case InternalLookupType.ISTARTSWITH: {
|
|
162
|
-
const lowerCol = this.dialect === InternalDialect.POSTGRES ? `LOWER(${col})` : `${col}`;
|
|
163
|
-
const lowerValue = String(value).toLowerCase();
|
|
164
|
-
return { sql: `${lowerCol} LIKE ${placeholder}`, params: [`${lowerValue}%`] };
|
|
165
|
-
}
|
|
166
|
-
case InternalLookupType.ENDSWITH:
|
|
167
|
-
return { sql: `${col} LIKE ${placeholder}`, params: [`%${value}`] };
|
|
168
|
-
case InternalLookupType.IENDSWITH: {
|
|
169
|
-
const lowerCol = this.dialect === InternalDialect.POSTGRES ? `LOWER(${col})` : `${col}`;
|
|
170
|
-
const lowerValue = String(value).toLowerCase();
|
|
171
|
-
return { sql: `${lowerCol} LIKE ${placeholder}`, params: [`%${lowerValue}`] };
|
|
172
|
-
}
|
|
173
|
-
default:
|
|
174
|
-
throw new Error(`Unknown lookup: ${lookup}`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
normalizeParam(value) {
|
|
178
|
-
if (this.dialect === InternalDialect.SQLITE && typeof value === 'boolean') {
|
|
179
|
-
return value ? 1 : 0;
|
|
180
|
-
}
|
|
181
|
-
return value;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/query-CQbvLeuh.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { __export } from "./chunk-DLY2FNSh.js";
|
|
2
|
-
import { QBuilder, QueryCompiler, QuerySet, compiler_exports } from "./QuerySet-BzR5QzGi.js";
|
|
3
|
-
|
|
4
|
-
//#region src/query/domain/index.ts
|
|
5
|
-
var domain_exports = {};
|
|
6
|
-
|
|
7
|
-
//#endregion
|
|
8
|
-
//#region src/query/index.ts
|
|
9
|
-
var query_exports = {};
|
|
10
|
-
__export(query_exports, {
|
|
11
|
-
Q: () => QBuilder,
|
|
12
|
-
QBuilder: () => QBuilder,
|
|
13
|
-
QueryCompiler: () => QueryCompiler,
|
|
14
|
-
QuerySet: () => QuerySet,
|
|
15
|
-
compiler: () => compiler_exports,
|
|
16
|
-
domain: () => domain_exports
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
//#endregion
|
|
20
|
-
export { domain_exports, query_exports };
|
|
21
|
-
//# sourceMappingURL=query-CQbvLeuh.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"query-CQbvLeuh.js","names":[],"sources":["../src/query/domain/index.ts","../src/query/index.ts"],"sourcesContent":["/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport type { CompiledQuery } from './CompiledQuery';\nexport type { Dialect } from './Dialect';\nexport type { Direction } from './Direction';\nexport type { FilterInput } from './FilterInput';\nexport type { FilterKey } from './FilterKey';\nexport type { FilterValue } from './FilterValue';\nexport type { LookupType } from './LookupType';\nexport type { OrderSpec } from './OrderSpec';\nexport type { OrderToken } from './OrderToken';\nexport type { QNode } from './QNode';\nexport type { QueryResult } from './QueryResult';\nexport type { QuerySetState } from './QuerySetState';\nexport type { RelationMeta } from './RelationMeta';\nexport type { RepositoryMeta as RepoMeta } from './RepositoryMeta';\nexport type { WhereClause } from './WhereClause';\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 compiler from './compiler/index';\nexport * as domain from './domain/index';\n\nexport type * from './domain/index';\nexport type { RepoMeta } from './domain/index';\nexport { QuerySet } from './QuerySet';\nexport type { RepositoryLike } from './QuerySet';\nexport { QBuilder, QBuilder as Q } from './QBuilder';\nexport { QueryCompiler } from './compiler/index';\n"],"mappings":""}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { DBClient } from '../connection/clients/DBClient';
|
|
2
|
-
import { QuerySet } from '../query/QuerySet';
|
|
3
|
-
import type { RepositoryMeta } from '../query/domain/RepositoryMeta';
|
|
4
|
-
/**
|
|
5
|
-
* Base repository class providing CRUD operations and query building capabilities.
|
|
6
|
-
* Extend this class to create model-specific repositories with custom business logic.
|
|
7
|
-
*
|
|
8
|
-
* @template T - The model type this repository manages
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```typescript
|
|
12
|
-
* class UserRepository extends Repository<User> {
|
|
13
|
-
* meta = {
|
|
14
|
-
* table: 'users',
|
|
15
|
-
* pk: 'id',
|
|
16
|
-
* columns: { id: 'int', email: 'text', name: 'text' },
|
|
17
|
-
* };
|
|
18
|
-
*
|
|
19
|
-
* async findByEmail(email: string): Promise<User | null> {
|
|
20
|
-
* return this.query().filter({ email }).fetchOne();
|
|
21
|
-
* }
|
|
22
|
-
* }
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
export declare abstract class Repository<T extends Record<string, unknown>> {
|
|
26
|
-
static readonly BRAND: "tango.orm.repository";
|
|
27
|
-
readonly __tangoBrand: typeof Repository.BRAND;
|
|
28
|
-
abstract meta: RepositoryMeta;
|
|
29
|
-
protected client: DBClient;
|
|
30
|
-
protected dialect: 'postgres' | 'sqlite';
|
|
31
|
-
static isRepository<T extends Record<string, unknown>>(value: unknown): value is Repository<T>;
|
|
32
|
-
constructor(client: DBClient, dialect?: 'postgres' | 'sqlite');
|
|
33
|
-
query(): QuerySet<T>;
|
|
34
|
-
findById(id: T[keyof T]): Promise<T | null>;
|
|
35
|
-
getOrThrow(id: T[keyof T]): Promise<T>;
|
|
36
|
-
create(input: Partial<T>): Promise<T>;
|
|
37
|
-
update(id: T[keyof T], patch: Partial<T>): Promise<T>;
|
|
38
|
-
delete(id: T[keyof T]): Promise<void>;
|
|
39
|
-
bulkCreate(inputs: Partial<T>[]): Promise<T[]>;
|
|
40
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { NotFoundError } from '@danceroutine/tango-core';
|
|
2
|
-
import { QuerySet } from '../query/QuerySet';
|
|
3
|
-
/**
|
|
4
|
-
* Base repository class providing CRUD operations and query building capabilities.
|
|
5
|
-
* Extend this class to create model-specific repositories with custom business logic.
|
|
6
|
-
*
|
|
7
|
-
* @template T - The model type this repository manages
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* class UserRepository extends Repository<User> {
|
|
12
|
-
* meta = {
|
|
13
|
-
* table: 'users',
|
|
14
|
-
* pk: 'id',
|
|
15
|
-
* columns: { id: 'int', email: 'text', name: 'text' },
|
|
16
|
-
* };
|
|
17
|
-
*
|
|
18
|
-
* async findByEmail(email: string): Promise<User | null> {
|
|
19
|
-
* return this.query().filter({ email }).fetchOne();
|
|
20
|
-
* }
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export class Repository {
|
|
25
|
-
static BRAND = 'tango.orm.repository';
|
|
26
|
-
__tangoBrand = Repository.BRAND;
|
|
27
|
-
client;
|
|
28
|
-
dialect;
|
|
29
|
-
static isRepository(value) {
|
|
30
|
-
return (typeof value === 'object' &&
|
|
31
|
-
value !== null &&
|
|
32
|
-
value.__tangoBrand === Repository.BRAND);
|
|
33
|
-
}
|
|
34
|
-
constructor(client, dialect = 'postgres') {
|
|
35
|
-
this.client = client;
|
|
36
|
-
this.dialect = dialect;
|
|
37
|
-
}
|
|
38
|
-
query() {
|
|
39
|
-
return new QuerySet({
|
|
40
|
-
meta: this.meta,
|
|
41
|
-
client: this.client,
|
|
42
|
-
dialect: this.dialect,
|
|
43
|
-
run: async (compiled) => {
|
|
44
|
-
const result = await this.client.query(compiled.sql, compiled.params);
|
|
45
|
-
return result.rows;
|
|
46
|
-
},
|
|
47
|
-
}, {});
|
|
48
|
-
}
|
|
49
|
-
async findById(id) {
|
|
50
|
-
const filter = { [this.meta.pk]: id };
|
|
51
|
-
const result = await this.query().filter(filter).fetchOne();
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
async getOrThrow(id) {
|
|
55
|
-
const result = await this.findById(id);
|
|
56
|
-
if (!result) {
|
|
57
|
-
throw new NotFoundError(`${this.meta.table} with ${this.meta.pk}=${String(id)} not found`);
|
|
58
|
-
}
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
async create(input) {
|
|
62
|
-
const keys = Object.keys(input);
|
|
63
|
-
const values = Object.values(input);
|
|
64
|
-
const placeholder = this.dialect === 'postgres' ? keys.map((_, i) => `$${i + 1}`).join(', ') : keys.map(() => '?').join(', ');
|
|
65
|
-
const sql = `INSERT INTO ${this.meta.table} (${keys.join(', ')}) VALUES (${placeholder}) RETURNING *`;
|
|
66
|
-
const result = await this.client.query(sql, values);
|
|
67
|
-
return result.rows[0];
|
|
68
|
-
}
|
|
69
|
-
async update(id, patch) {
|
|
70
|
-
const keys = Object.keys(patch);
|
|
71
|
-
const values = Object.values(patch);
|
|
72
|
-
const sets = this.dialect === 'postgres'
|
|
73
|
-
? keys.map((k, i) => `${k} = $${i + 1}`).join(', ')
|
|
74
|
-
: keys.map((k) => `${k} = ?`).join(', ');
|
|
75
|
-
const whereParam = this.dialect === 'postgres' ? `$${keys.length + 1}` : '?';
|
|
76
|
-
const sql = `UPDATE ${this.meta.table} SET ${sets} WHERE ${this.meta.pk} = ${whereParam} RETURNING *`;
|
|
77
|
-
const result = await this.client.query(sql, [...values, id]);
|
|
78
|
-
return result.rows[0];
|
|
79
|
-
}
|
|
80
|
-
async delete(id) {
|
|
81
|
-
const placeholder = this.dialect === 'postgres' ? '$1' : '?';
|
|
82
|
-
const sql = `DELETE FROM ${this.meta.table} WHERE ${this.meta.pk} = ${placeholder}`;
|
|
83
|
-
await this.client.query(sql, [id]);
|
|
84
|
-
}
|
|
85
|
-
async bulkCreate(inputs) {
|
|
86
|
-
if (inputs.length === 0)
|
|
87
|
-
return [];
|
|
88
|
-
const keys = Object.keys(inputs[0]);
|
|
89
|
-
const valueRows = inputs.map((input) => Object.values(input));
|
|
90
|
-
const placeholders = this.dialect === 'postgres'
|
|
91
|
-
? valueRows
|
|
92
|
-
.map((_, rowIdx) => `(${keys.map((_, colIdx) => `$${rowIdx * keys.length + colIdx + 1}`).join(', ')})`)
|
|
93
|
-
.join(', ')
|
|
94
|
-
: valueRows.map(() => `(${keys.map(() => '?').join(', ')})`).join(', ');
|
|
95
|
-
const sql = `INSERT INTO ${this.meta.table} (${keys.join(', ')}) VALUES ${placeholders} RETURNING *`;
|
|
96
|
-
const allValues = valueRows.flat();
|
|
97
|
-
const result = await this.client.query(sql, allValues);
|
|
98
|
-
return result.rows;
|
|
99
|
-
}
|
|
100
|
-
}
|
package/dist/repository/index.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { __export } from "./chunk-DLY2FNSh.js";
|
|
2
|
-
import { QuerySet } from "./QuerySet-BzR5QzGi.js";
|
|
3
|
-
|
|
4
|
-
//#region src/repository/Repository.ts
|
|
5
|
-
var Repository = class Repository {
|
|
6
|
-
static BRAND = "tango.orm.repository";
|
|
7
|
-
__tangoBrand = Repository.BRAND;
|
|
8
|
-
client;
|
|
9
|
-
dialect;
|
|
10
|
-
static isRepository(value) {
|
|
11
|
-
return typeof value === "object" && value !== null && value.__tangoBrand === Repository.BRAND;
|
|
12
|
-
}
|
|
13
|
-
constructor(client, dialect = "postgres") {
|
|
14
|
-
this.client = client;
|
|
15
|
-
this.dialect = dialect;
|
|
16
|
-
}
|
|
17
|
-
query() {
|
|
18
|
-
return new QuerySet({
|
|
19
|
-
meta: this.meta,
|
|
20
|
-
client: this.client,
|
|
21
|
-
dialect: this.dialect,
|
|
22
|
-
run: async (compiled) => {
|
|
23
|
-
const result = await this.client.query(compiled.sql, compiled.params);
|
|
24
|
-
return result.rows;
|
|
25
|
-
}
|
|
26
|
-
}, {});
|
|
27
|
-
}
|
|
28
|
-
async findById(id) {
|
|
29
|
-
const result = await this.query().filter({ [this.meta.pk]: id }).fetchOne();
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
async getOrThrow(id) {
|
|
33
|
-
const result = await this.findById(id);
|
|
34
|
-
if (!result) throw new Error(`${this.meta.table} with ${this.meta.pk}=${String(id)} not found`);
|
|
35
|
-
return result;
|
|
36
|
-
}
|
|
37
|
-
async create(input) {
|
|
38
|
-
const keys = Object.keys(input);
|
|
39
|
-
const values = Object.values(input);
|
|
40
|
-
const placeholder = this.dialect === "postgres" ? keys.map((_, i) => `$${i + 1}`).join(", ") : keys.map(() => "?").join(", ");
|
|
41
|
-
const sql = `INSERT INTO ${this.meta.table} (${keys.join(", ")}) VALUES (${placeholder}) RETURNING *`;
|
|
42
|
-
const result = await this.client.query(sql, values);
|
|
43
|
-
return result.rows[0];
|
|
44
|
-
}
|
|
45
|
-
async update(id, patch) {
|
|
46
|
-
const keys = Object.keys(patch);
|
|
47
|
-
const values = Object.values(patch);
|
|
48
|
-
const sets = this.dialect === "postgres" ? keys.map((k, i) => `${k} = $${i + 1}`).join(", ") : keys.map((k) => `${k} = ?`).join(", ");
|
|
49
|
-
const whereParam = this.dialect === "postgres" ? `$${keys.length + 1}` : "?";
|
|
50
|
-
const sql = `UPDATE ${this.meta.table} SET ${sets} WHERE ${this.meta.pk} = ${whereParam} RETURNING *`;
|
|
51
|
-
const result = await this.client.query(sql, [...values, id]);
|
|
52
|
-
return result.rows[0];
|
|
53
|
-
}
|
|
54
|
-
async delete(id) {
|
|
55
|
-
const placeholder = this.dialect === "postgres" ? "$1" : "?";
|
|
56
|
-
const sql = `DELETE FROM ${this.meta.table} WHERE ${this.meta.pk} = ${placeholder}`;
|
|
57
|
-
await this.client.query(sql, [id]);
|
|
58
|
-
}
|
|
59
|
-
async bulkCreate(inputs) {
|
|
60
|
-
if (inputs.length === 0) return [];
|
|
61
|
-
const keys = Object.keys(inputs[0]);
|
|
62
|
-
const valueRows = inputs.map((input) => Object.values(input));
|
|
63
|
-
const placeholders = this.dialect === "postgres" ? valueRows.map((_, rowIdx) => `(${keys.map((_$1, colIdx) => `$${rowIdx * keys.length + colIdx + 1}`).join(", ")})`).join(", ") : valueRows.map(() => `(${keys.map(() => "?").join(", ")})`).join(", ");
|
|
64
|
-
const sql = `INSERT INTO ${this.meta.table} (${keys.join(", ")}) VALUES ${placeholders} RETURNING *`;
|
|
65
|
-
const allValues = valueRows.flat();
|
|
66
|
-
const result = await this.client.query(sql, allValues);
|
|
67
|
-
return result.rows;
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/repository/index.ts
|
|
73
|
-
var repository_exports = {};
|
|
74
|
-
__export(repository_exports, { Repository: () => Repository });
|
|
75
|
-
|
|
76
|
-
//#endregion
|
|
77
|
-
export { Repository, repository_exports };
|
|
78
|
-
//# sourceMappingURL=repository-DaRvsfjs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"repository-DaRvsfjs.js","names":["value: unknown","client: DBClient","dialect: 'postgres' | 'sqlite'","id: T[keyof T]","input: Partial<T>","patch: Partial<T>","inputs: Partial<T>[]"],"sources":["../src/repository/Repository.ts","../src/repository/index.ts"],"sourcesContent":["import type { DBClient } from '../connection/clients/DBClient';\nimport { QuerySet } from '../query/QuerySet';\nimport type { RepositoryMeta } from '../query/domain/RepositoryMeta';\n\n/**\n * Base repository class providing CRUD operations and query building capabilities.\n * Extend this class to create model-specific repositories with custom business logic.\n *\n * @template T - The model type this repository manages\n *\n * @example\n * ```typescript\n * class UserRepository extends Repository<User> {\n * meta = {\n * table: 'users',\n * pk: 'id',\n * columns: { id: 'int', email: 'text', name: 'text' },\n * };\n *\n * async findByEmail(email: string): Promise<User | null> {\n * return this.query().filter({ email }).fetchOne();\n * }\n * }\n * ```\n */\nexport abstract class Repository<T extends Record<string, any>> {\n static readonly BRAND = 'tango.orm.repository' as const;\n readonly __tangoBrand: typeof Repository.BRAND = Repository.BRAND;\n abstract meta: RepositoryMeta;\n protected client: DBClient;\n protected dialect: 'postgres' | 'sqlite';\n\n static isRepository<T extends Record<string, any>>(value: unknown): value is Repository<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === Repository.BRAND\n );\n }\n\n constructor(client: DBClient, dialect: 'postgres' | 'sqlite' = 'postgres') {\n this.client = client;\n this.dialect = dialect;\n }\n\n query(): QuerySet<T> {\n return new QuerySet<T>(\n {\n meta: this.meta,\n client: this.client,\n dialect: this.dialect,\n run: async (compiled) => {\n const result = await this.client.query<T>(compiled.sql, compiled.params);\n return result.rows;\n },\n },\n {}\n );\n }\n\n async findById(id: T[keyof T]): Promise<T | null> {\n const result = await this.query()\n .filter({ [this.meta.pk]: id } as any)\n .fetchOne();\n return result;\n }\n\n async getOrThrow(id: T[keyof T]): Promise<T> {\n const result = await this.findById(id);\n if (!result) {\n throw new Error(`${this.meta.table} with ${this.meta.pk}=${String(id)} not found`);\n }\n return result;\n }\n\n async create(input: Partial<T>): Promise<T> {\n const keys = Object.keys(input);\n const values = Object.values(input);\n\n const placeholder =\n this.dialect === 'postgres' ? keys.map((_, i) => `$${i + 1}`).join(', ') : keys.map(() => '?').join(', ');\n\n const sql = `INSERT INTO ${this.meta.table} (${keys.join(', ')}) VALUES (${placeholder}) RETURNING *`;\n\n const result = await this.client.query<T>(sql, values);\n return result.rows[0]!;\n }\n\n async update(id: T[keyof T], patch: Partial<T>): Promise<T> {\n const keys = Object.keys(patch);\n const values = Object.values(patch);\n\n const sets =\n this.dialect === 'postgres'\n ? keys.map((k, i) => `${k} = $${i + 1}`).join(', ')\n : keys.map((k) => `${k} = ?`).join(', ');\n\n const whereParam = this.dialect === 'postgres' ? `$${keys.length + 1}` : '?';\n\n const sql = `UPDATE ${this.meta.table} SET ${sets} WHERE ${this.meta.pk} = ${whereParam} RETURNING *`;\n\n const result = await this.client.query<T>(sql, [...values, id]);\n return result.rows[0]!;\n }\n\n async delete(id: T[keyof T]): Promise<void> {\n const placeholder = this.dialect === 'postgres' ? '$1' : '?';\n const sql = `DELETE FROM ${this.meta.table} WHERE ${this.meta.pk} = ${placeholder}`;\n await this.client.query(sql, [id]);\n }\n\n async bulkCreate(inputs: Partial<T>[]): Promise<T[]> {\n if (inputs.length === 0) return [];\n\n const keys = Object.keys(inputs[0]!);\n const valueRows = inputs.map((input) => Object.values(input));\n\n const placeholders =\n this.dialect === 'postgres'\n ? valueRows\n .map(\n (_, rowIdx) =>\n `(${keys.map((_, colIdx) => `$${rowIdx * keys.length + colIdx + 1}`).join(', ')})`\n )\n .join(', ')\n : valueRows.map(() => `(${keys.map(() => '?').join(', ')})`).join(', ');\n\n const sql = `INSERT INTO ${this.meta.table} (${keys.join(', ')}) VALUES ${placeholders} RETURNING *`;\n\n const allValues = valueRows.flat();\n const result = await this.client.query<T>(sql, allValues);\n return result.rows;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { Repository } from './Repository';\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-DIGJnp19.js","names":["value: unknown","client: DBClient"],"sources":["../src/transaction/UnitOfWork.ts","../src/transaction/index.ts"],"sourcesContent":["import type { DBClient } from '../connection/clients/DBClient';\n\n/**\n * Unit of Work pattern implementation for managing database transactions.\n * Ensures that a set of operations either all succeed or all fail together.\n *\n * @example\n * ```typescript\n * const uow = await UnitOfWork.start(dbClient);\n * try {\n * await userRepo.create({ email: 'test@example.com' });\n * await postRepo.create({ title: 'Hello' });\n * await uow.commit();\n * } catch (error) {\n * await uow.rollback();\n * throw error;\n * }\n * ```\n */\nexport class UnitOfWork {\n static readonly BRAND = 'tango.orm.unit_of_work' as const;\n readonly __tangoBrand: typeof UnitOfWork.BRAND = UnitOfWork.BRAND;\n protected client: DBClient;\n protected isActive = false;\n\n static isUnitOfWork(value: unknown): value is UnitOfWork {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === UnitOfWork.BRAND\n );\n }\n\n constructor(client: DBClient) {\n this.client = client;\n }\n\n async begin(): Promise<void> {\n if (!this.isActive) {\n await this.client.begin();\n this.isActive = true;\n }\n }\n\n async commit(): Promise<void> {\n if (this.isActive) {\n await this.client.commit();\n this.isActive = false;\n }\n }\n\n async rollback(): Promise<void> {\n if (this.isActive) {\n await this.client.rollback();\n this.isActive = false;\n }\n }\n\n getClient(): DBClient {\n return this.client;\n }\n\n static async start(client: DBClient): Promise<UnitOfWork> {\n const uow = new UnitOfWork(client);\n await uow.begin();\n return uow;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { UnitOfWork } from './UnitOfWork';\n"],"mappings":";;;IAmBa,aAAN,MAAM,WAAW;CACpB,OAAgB,QAAQ;CACxB,eAAiD,WAAW;CAC5D;CACA,WAAqB;CAErB,OAAO,aAAaA,OAAqC;AACrD,gBACW,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,WAAW;CAEzE;CAED,YAAYC,QAAkB;AAC1B,OAAK,SAAS;CACjB;CAED,MAAM,QAAuB;AACzB,OAAK,KAAK,UAAU;AAChB,SAAM,KAAK,OAAO,OAAO;AACzB,QAAK,WAAW;EACnB;CACJ;CAED,MAAM,SAAwB;AAC1B,MAAI,KAAK,UAAU;AACf,SAAM,KAAK,OAAO,QAAQ;AAC1B,QAAK,WAAW;EACnB;CACJ;CAED,MAAM,WAA0B;AAC5B,MAAI,KAAK,UAAU;AACf,SAAM,KAAK,OAAO,UAAU;AAC5B,QAAK,WAAW;EACnB;CACJ;CAED,YAAsB;AAClB,SAAO,KAAK;CACf;CAED,aAAa,MAAMA,QAAuC;EACtD,MAAM,MAAM,IAAI,WAAW;AAC3B,QAAM,IAAI,OAAO;AACjB,SAAO;CACV;AACJ"}
|