@danceroutine/tango-orm 1.11.0 → 1.11.2
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/Adapter-DKxAaL4l.d.ts +73 -0
- package/dist/DBClient-DuYcXolQ.d.ts +27 -0
- package/dist/{InternalDialect-ClSaUNso.js → InternalDialect-U3mwJjKA.js} +3 -4
- package/dist/InternalDialect-U3mwJjKA.js.map +1 -0
- package/dist/QuerySetState-CjyvAUBs.d.ts +1310 -0
- package/dist/SqliteAdapter-6oyUmoJf.js +279 -0
- package/dist/SqliteAdapter-6oyUmoJf.js.map +1 -0
- package/dist/chunk-8H4AJuhK.js +14 -0
- package/dist/connection/index.d.ts +4 -11
- package/dist/connection/index.js +3 -6
- package/dist/{connection-Dmhgx31M.js → connection-D-E6_Yf1.js} +28 -30
- package/dist/connection-D-E6_Yf1.js.map +1 -0
- package/dist/{defaultRuntime-DzqBQ9Hb.js → defaultRuntime-CdTX8cXm.js} +41 -35
- package/dist/defaultRuntime-CdTX8cXm.js.map +1 -0
- package/dist/index-B-aibguC.d.ts +226 -0
- package/dist/index-D9B6gKez.d.ts +70 -0
- package/dist/index-rjKca3U_.d.ts +31 -0
- package/dist/index-uuG57Y7C.d.ts +97 -0
- package/dist/index.d.ts +9 -22
- package/dist/index.js +9 -12
- package/dist/manager/index.d.ts +4 -12
- package/dist/manager/index.js +3 -9
- package/dist/{manager-DrDTiCAz.js → manager-CiYqAYpn.js} +7 -11
- package/dist/{manager-DrDTiCAz.js.map → manager-CiYqAYpn.js.map} +1 -1
- package/dist/query/index.d.ts +3 -14
- package/dist/query/index.js +2 -4
- package/dist/{query-DUZnBFhf.js → query-CP1UMIX6.js} +163 -121
- package/dist/query-CP1UMIX6.js.map +1 -0
- package/dist/registerModelObjects-C-MliIiM.d.ts +229 -0
- package/dist/{registerModelObjects-Djpt45KK.js → registerModelObjects-DZfZ20fa.js} +150 -69
- package/dist/registerModelObjects-DZfZ20fa.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -15
- package/dist/runtime/index.js +15 -8
- package/dist/runtime/index.js.map +1 -0
- package/dist/transaction/index.d.ts +2 -6
- package/dist/transaction/index.js +2 -7
- package/dist/{transaction-ZhfDf-f8.js → transaction-2_2m7VUo.js} +26 -10
- package/dist/transaction-2_2m7VUo.js.map +1 -0
- package/package.json +8 -8
- package/dist/InternalDialect-ClSaUNso.js.map +0 -1
- package/dist/PostgresAdapter-CXKdKBG-.js +0 -4
- package/dist/PostgresAdapter-DySFW6vy.js +0 -128
- package/dist/PostgresAdapter-DySFW6vy.js.map +0 -1
- package/dist/SqliteAdapter-CDdOjRmW.js +0 -151
- package/dist/SqliteAdapter-CDdOjRmW.js.map +0 -1
- package/dist/SqliteAdapter-mjtXuVTg.js +0 -4
- package/dist/chunk-DLY2FNSh.js +0 -12
- package/dist/connection/adapters/Adapter.d.ts +0 -60
- package/dist/connection/adapters/AdapterRegistry.d.ts +0 -44
- package/dist/connection/adapters/dialects/PostgresAdapter.d.ts +0 -30
- package/dist/connection/adapters/dialects/SqliteAdapter.d.ts +0 -22
- package/dist/connection/adapters/dialects/index.d.ts +0 -5
- package/dist/connection/adapters/index.d.ts +0 -8
- package/dist/connection/clients/DBClient.d.ts +0 -23
- package/dist/connection/clients/dialects/PostgresClient.d.ts +0 -54
- package/dist/connection/clients/dialects/SqliteClient.d.ts +0 -54
- package/dist/connection/clients/dialects/index.d.ts +0 -5
- package/dist/connection/clients/index.d.ts +0 -7
- package/dist/connection-Dmhgx31M.js.map +0 -1
- package/dist/defaultRuntime-DzqBQ9Hb.js.map +0 -1
- package/dist/manager/ManagerLike.d.ts +0 -34
- package/dist/manager/ModelManager.d.ts +0 -97
- package/dist/manager/internal/MutationCompiler.d.ts +0 -23
- package/dist/manager/internal/RuntimeBoundClient.d.ts +0 -20
- package/dist/manager/registerModelObjects.d.ts +0 -5
- package/dist/manager/relations/ManyToManyRelatedManager.d.ts +0 -181
- package/dist/manager/relations/ManyToManyRelatedQuerySet.d.ts +0 -62
- package/dist/manager/relations/MaterializedModelRecord.d.ts +0 -28
- package/dist/manager/relations/index.d.ts +0 -9
- package/dist/manager/relations/internal/ThroughTableManager.d.ts +0 -85
- package/dist/query/ModelQuerySet.d.ts +0 -20
- package/dist/query/QBuilder.d.ts +0 -29
- package/dist/query/QuerySet.d.ts +0 -215
- package/dist/query/compiler/QueryCompiler.d.ts +0 -49
- package/dist/query/compiler/index.d.ts +0 -4
- package/dist/query/domain/CompiledQuery.d.ts +0 -209
- package/dist/query/domain/Dialect.d.ts +0 -2
- package/dist/query/domain/Direction.d.ts +0 -2
- package/dist/query/domain/FilterInput.d.ts +0 -3
- package/dist/query/domain/FilterKey.d.ts +0 -4
- package/dist/query/domain/FilterValue.d.ts +0 -1
- package/dist/query/domain/LookupType.d.ts +0 -2
- package/dist/query/domain/OrderSpec.d.ts +0 -5
- package/dist/query/domain/OrderToken.d.ts +0 -1
- package/dist/query/domain/QNode.d.ts +0 -9
- package/dist/query/domain/QueryResult.d.ts +0 -35
- package/dist/query/domain/QuerySetState.d.ts +0 -13
- package/dist/query/domain/RelationMeta.d.ts +0 -56
- package/dist/query/domain/RelationTyping.d.ts +0 -163
- package/dist/query/domain/TableMeta.d.ts +0 -16
- package/dist/query/domain/TableMetaFactory.d.ts +0 -10
- package/dist/query/domain/WhereClause.d.ts +0 -4
- package/dist/query/domain/index.d.ts +0 -21
- package/dist/query/domain/internal/InternalDialect.d.ts +0 -4
- package/dist/query/domain/internal/InternalDirection.d.ts +0 -4
- package/dist/query/domain/internal/InternalLookupType.d.ts +0 -15
- package/dist/query/domain/internal/InternalPrefetchQueryKind.d.ts +0 -20
- package/dist/query/domain/internal/InternalQNodeType.d.ts +0 -6
- package/dist/query/domain/internal/InternalRelationKind.d.ts +0 -6
- package/dist/query/internal/isQNodeLike.d.ts +0 -3
- package/dist/query/planning/QueryPlanner.d.ts +0 -16
- package/dist/query/planning/domain/QueryHydrationPlan.d.ts +0 -20
- package/dist/query/planning/index.d.ts +0 -2
- package/dist/query-DUZnBFhf.js.map +0 -1
- package/dist/registerModelObjects-Djpt45KK.js.map +0 -1
- package/dist/runtime/TangoRuntime.d.ts +0 -56
- package/dist/runtime/defaultRuntime.d.ts +0 -13
- package/dist/runtime/internal/DBClientProvider.d.ts +0 -12
- package/dist/runtime/internal/PostgresDBClientProvider.d.ts +0 -12
- package/dist/runtime/internal/SqliteDBClientProvider.d.ts +0 -19
- package/dist/runtime/internal/createDBClientProvider.d.ts +0 -5
- package/dist/runtime-1H88J3nN.js +0 -18
- package/dist/runtime-1H88J3nN.js.map +0 -1
- package/dist/transaction/AtomicTransaction.d.ts +0 -32
- package/dist/transaction/UnitOfWork.d.ts +0 -52
- package/dist/transaction/atomic.d.ts +0 -2
- package/dist/transaction/internal/context/AsyncLocalTransactionEngine.d.ts +0 -21
- package/dist/transaction/internal/context/CallbackRecord.d.ts +0 -5
- package/dist/transaction/internal/context/FrameBoundTransaction.d.ts +0 -20
- package/dist/transaction/internal/context/FrameTransactionHandle.d.ts +0 -4
- package/dist/transaction/internal/context/TransactionEngine.d.ts +0 -16
- package/dist/transaction/internal/context/TransactionFrame.d.ts +0 -7
- package/dist/transaction/internal/context/TransactionState.d.ts +0 -10
- package/dist/transaction/internal/context/index.d.ts +0 -1
- package/dist/transaction-ZhfDf-f8.js.map +0 -1
- package/dist/validation/OrmSqlSafetyAdapter.d.ts +0 -22
- package/dist/validation/SQLValidationEngine.d.ts +0 -68
- package/dist/validation/SqlValidationPlan.d.ts +0 -43
- package/dist/validation/index.d.ts +0 -3
- package/dist/validation/internal/InternalSqlValidationPlanKind.d.ts +0 -25
- package/dist/validation/internal/InternalValidatedFilterDescriptorKind.d.ts +0 -4
|
@@ -1,13 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { RuntimeBoundClient, TransactionEngine, getTangoRuntime } from "./defaultRuntime-
|
|
1
|
+
import { a as isQNodeLike, c as InternalRelationKind, f as OrmSqlSafetyAdapter, i as QBuilder, l as QueryResult, m as InternalQNodeType, n as ModelQuerySet, p as InternalSqlValidationPlanKind, r as QuerySet, s as TableMetaFactory } from "./query-CP1UMIX6.js";
|
|
2
|
+
import { a as RuntimeBoundClient, o as TransactionEngine, t as getTangoRuntime } from "./defaultRuntime-CdTX8cXm.js";
|
|
3
3
|
import { NotFoundError } from "@danceroutine/tango-core";
|
|
4
4
|
import { ModelRegistry, registerModelAugmentor } from "@danceroutine/tango-schema";
|
|
5
|
-
|
|
6
5
|
//#region src/manager/relations/ManyToManyRelatedQuerySet.ts
|
|
7
6
|
function applyShape(rows, shape) {
|
|
8
7
|
return typeof shape === "function" ? rows.map(shape) : rows.map((row) => shape.parse(row));
|
|
9
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* {@link QuerySet} returned by `post.tags.all()` on a many-to-many related
|
|
11
|
+
* manager.
|
|
12
|
+
*
|
|
13
|
+
* Behaves like a normal `QuerySet` over the target model from an application
|
|
14
|
+
* developer's perspective: you can chain `filter`, `exclude`, `orderBy`,
|
|
15
|
+
* `limit`, `offset`, and terminate with `fetch`, `fetchOne`, or `count`.
|
|
16
|
+
* Each chainable call returns another `ManyToManyRelatedQuerySet` so the
|
|
17
|
+
* chain keeps the membership scoping of the owning record.
|
|
18
|
+
*
|
|
19
|
+
* Two behaviors differ from a plain `QuerySet` and matter to application
|
|
20
|
+
* developers:
|
|
21
|
+
*
|
|
22
|
+
* - When the relation was loaded by `prefetchRelated(...)` and no chainable
|
|
23
|
+
* state has been added (no `filter`, `orderBy`, etc.), `fetch()` and
|
|
24
|
+
* `count()` resolve from the prefetch cache without issuing SQL.
|
|
25
|
+
* - Mutating the membership via `post.tags.add(tag)` or
|
|
26
|
+
* `post.tags.remove(tag)` invalidates that cache so follow-up reads go
|
|
27
|
+
* back to the database.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const post = await PostModel.objects.getOrThrow(postId);
|
|
32
|
+
* await post.tags.add(tag);
|
|
33
|
+
* const tags = await post.tags.all().filter({ color: 'red' }).orderBy('name').fetch();
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @template TTarget - The persisted target record shape (e.g. `Tag`).
|
|
37
|
+
*/
|
|
10
38
|
var ManyToManyRelatedQuerySet = class ManyToManyRelatedQuerySet extends QuerySet {
|
|
39
|
+
bridge;
|
|
11
40
|
constructor(executor, bridge, state = {}) {
|
|
12
41
|
super(executor, state);
|
|
13
42
|
this.bridge = bridge;
|
|
@@ -15,10 +44,7 @@ var ManyToManyRelatedQuerySet = class ManyToManyRelatedQuerySet extends QuerySet
|
|
|
15
44
|
async fetch(shape) {
|
|
16
45
|
if (this.isStateTrivial()) {
|
|
17
46
|
const cache = this.bridge.getCache();
|
|
18
|
-
if (cache !== null)
|
|
19
|
-
const results = shape ? applyShape(cache, shape) : [...cache];
|
|
20
|
-
return new QueryResult(results);
|
|
21
|
-
}
|
|
47
|
+
if (cache !== null) return new QueryResult(shape ? applyShape(cache, shape) : [...cache]);
|
|
22
48
|
}
|
|
23
49
|
const ids = await this.bridge.fetchTargetIds();
|
|
24
50
|
if (ids.length === 0) return new QueryResult([]);
|
|
@@ -26,8 +52,7 @@ var ManyToManyRelatedQuerySet = class ManyToManyRelatedQuerySet extends QuerySet
|
|
|
26
52
|
return shape ? scopedQs.fetch(shape) : scopedQs.fetch();
|
|
27
53
|
}
|
|
28
54
|
async fetchOne(shape) {
|
|
29
|
-
|
|
30
|
-
return result.items[0] ?? null;
|
|
55
|
+
return (shape ? await this.fetch(shape) : await this.fetch()).items[0] ?? null;
|
|
31
56
|
}
|
|
32
57
|
async count() {
|
|
33
58
|
if (this.isStateTrivial()) {
|
|
@@ -37,8 +62,7 @@ var ManyToManyRelatedQuerySet = class ManyToManyRelatedQuerySet extends QuerySet
|
|
|
37
62
|
const ids = await this.bridge.fetchTargetIds();
|
|
38
63
|
if (ids.length === 0) return 0;
|
|
39
64
|
if (this.isStateTrivial()) return ids.length;
|
|
40
|
-
|
|
41
|
-
return scopedQs.count();
|
|
65
|
+
return new ModelQuerySet(this.executor, this.scopedState(ids)).count();
|
|
42
66
|
}
|
|
43
67
|
spawn(state) {
|
|
44
68
|
return new ManyToManyRelatedQuerySet(this.executor, this.bridge, state);
|
|
@@ -59,13 +83,15 @@ var ManyToManyRelatedQuerySet = class ManyToManyRelatedQuerySet extends QuerySet
|
|
|
59
83
|
};
|
|
60
84
|
}
|
|
61
85
|
};
|
|
62
|
-
|
|
63
86
|
//#endregion
|
|
64
87
|
//#region src/manager/internal/MutationCompiler.ts
|
|
65
88
|
const InternalDuplicateInsertPolicy = {
|
|
66
89
|
ERROR: "error",
|
|
67
90
|
IGNORE: "ignore"
|
|
68
91
|
};
|
|
92
|
+
/**
|
|
93
|
+
* Internal compiler for manager-owned INSERT/UPDATE/DELETE statements.
|
|
94
|
+
*/
|
|
69
95
|
var MutationCompiler = class {
|
|
70
96
|
adapter;
|
|
71
97
|
placeholders;
|
|
@@ -144,16 +170,26 @@ var MutationCompiler = class {
|
|
|
144
170
|
};
|
|
145
171
|
}
|
|
146
172
|
};
|
|
147
|
-
|
|
148
173
|
//#endregion
|
|
149
174
|
//#region src/manager/relations/internal/ThroughTableManager.ts
|
|
175
|
+
/**
|
|
176
|
+
* Internal helper that issues the INSERT, DELETE, and SELECT statements for
|
|
177
|
+
* a single many-to-many join table. Centralizes SQL safety validation and
|
|
178
|
+
* compilation so {@link ManyToManyRelatedManager} implementations only deal
|
|
179
|
+
* in primary-key values.
|
|
180
|
+
*/
|
|
150
181
|
var ThroughTableManager = class ThroughTableManager {
|
|
151
|
-
|
|
182
|
+
client;
|
|
183
|
+
mutationCompiler;
|
|
184
|
+
descriptor;
|
|
185
|
+
adapter;
|
|
186
|
+
sqlSafetyAdapter;
|
|
187
|
+
constructor(client, mutationCompiler, descriptor, adapter, sqlSafetyAdapter = new OrmSqlSafetyAdapter()) {
|
|
152
188
|
this.client = client;
|
|
153
189
|
this.mutationCompiler = mutationCompiler;
|
|
154
190
|
this.descriptor = descriptor;
|
|
155
191
|
this.adapter = adapter;
|
|
156
|
-
this.sqlSafetyAdapter = sqlSafetyAdapter
|
|
192
|
+
this.sqlSafetyAdapter = sqlSafetyAdapter;
|
|
157
193
|
}
|
|
158
194
|
/**
|
|
159
195
|
* Derive a {@link ThroughTableLinkDescriptor} from the through-model
|
|
@@ -198,8 +234,7 @@ var ThroughTableManager = class ThroughTableManager {
|
|
|
198
234
|
const targetColumn = validated.filterKeys[this.descriptor.targetColumn].field;
|
|
199
235
|
const placeholder = this.adapter.placeholders.at(1);
|
|
200
236
|
const sql = `SELECT ${targetColumn} AS target_id FROM ${validated.meta.table} WHERE ${sourceColumn} = ${placeholder}`;
|
|
201
|
-
|
|
202
|
-
return result.rows.map((row) => row.target_id).filter((value) => typeof value === "string" || typeof value === "number");
|
|
237
|
+
return (await this.client.query(sql, [ownerPrimaryKey])).rows.map((row) => row.target_id).filter((value) => typeof value === "string" || typeof value === "number");
|
|
203
238
|
}
|
|
204
239
|
async insertLink(ownerPrimaryKey, targetPrimaryKey, options = {}) {
|
|
205
240
|
await this.insertLinks(ownerPrimaryKey, [targetPrimaryKey], options);
|
|
@@ -258,10 +293,32 @@ var ThroughTableManager = class ThroughTableManager {
|
|
|
258
293
|
await this.client.query(sql, [ownerPrimaryKey]);
|
|
259
294
|
}
|
|
260
295
|
};
|
|
261
|
-
|
|
262
296
|
//#endregion
|
|
263
297
|
//#region src/manager/relations/ManyToManyRelatedManager.ts
|
|
298
|
+
/**
|
|
299
|
+
* Django-style related manager exposed on materialized model records for each
|
|
300
|
+
* many-to-many relation.
|
|
301
|
+
*
|
|
302
|
+
* Use the manager to add or remove join-table membership and to query the
|
|
303
|
+
* related target rows. The owning record's primary key and the relation name
|
|
304
|
+
* are bound when the manager is attached, so application code does not need
|
|
305
|
+
* to pass them on every call.
|
|
306
|
+
*
|
|
307
|
+
* Prefetched memberships seed an internal cache that the queryset returned
|
|
308
|
+
* from `all()` short-circuits to without re-querying. Mutations through
|
|
309
|
+
* `add`, `remove`, `set`, `clear`, and `create` invalidate the cache so
|
|
310
|
+
* subsequent reads observe the updated membership. `set(...)` applies
|
|
311
|
+
* Django-shaped replacement semantics:
|
|
312
|
+
* it diffs the current relation membership against the supplied targets,
|
|
313
|
+
* removes any missing links, and inserts any new links inside one atomic
|
|
314
|
+
* write boundary. `clear()` removes every join row for the owner, and
|
|
315
|
+
* `create(...)` persists a new target row plus its join-row link inside one
|
|
316
|
+
* atomic boundary.
|
|
317
|
+
*
|
|
318
|
+
* @template TTarget - The persisted target record shape returned by `all()`.
|
|
319
|
+
*/
|
|
264
320
|
var ManyToManyRelatedManager = class ManyToManyRelatedManager {
|
|
321
|
+
inputs;
|
|
265
322
|
static BRAND = "tango.orm.m2m_related_manager";
|
|
266
323
|
__tangoBrand = ManyToManyRelatedManager.BRAND;
|
|
267
324
|
prefetchCache = null;
|
|
@@ -319,7 +376,7 @@ var ManyToManyRelatedManager = class ManyToManyRelatedManager {
|
|
|
319
376
|
const targetPrimaryKeys = this.resolveTargetPrimaryKeys(targets);
|
|
320
377
|
if (targetPrimaryKeys.length === 0) return;
|
|
321
378
|
if (targetPrimaryKeys.length === 1) await this.insertTargetPrimaryKeys(targetPrimaryKeys);
|
|
322
|
-
else await this.inputs.runAtomic(() => this.insertTargetPrimaryKeys(targetPrimaryKeys));
|
|
379
|
+
else await this.inputs.runAtomic(() => this.insertTargetPrimaryKeys(targetPrimaryKeys));
|
|
323
380
|
this.invalidateCache();
|
|
324
381
|
}
|
|
325
382
|
/**
|
|
@@ -331,7 +388,7 @@ else await this.inputs.runAtomic(() => this.insertTargetPrimaryKeys(targetPrimar
|
|
|
331
388
|
const targetPrimaryKeys = this.resolveTargetPrimaryKeys(targets);
|
|
332
389
|
if (targetPrimaryKeys.length === 0) return;
|
|
333
390
|
if (targetPrimaryKeys.length === 1) await this.deleteTargetPrimaryKeys(targetPrimaryKeys);
|
|
334
|
-
else await this.inputs.runAtomic(() => this.deleteTargetPrimaryKeys(targetPrimaryKeys));
|
|
391
|
+
else await this.inputs.runAtomic(() => this.deleteTargetPrimaryKeys(targetPrimaryKeys));
|
|
335
392
|
this.invalidateCache();
|
|
336
393
|
}
|
|
337
394
|
/**
|
|
@@ -438,7 +495,7 @@ else await this.inputs.runAtomic(() => this.deleteTargetPrimaryKeys(targetPrimar
|
|
|
438
495
|
}
|
|
439
496
|
resolveTargetPrimaryKeys(targets) {
|
|
440
497
|
const resolved = [];
|
|
441
|
-
const seen = new Set();
|
|
498
|
+
const seen = /* @__PURE__ */ new Set();
|
|
442
499
|
for (const target of targets) {
|
|
443
500
|
const primaryKey = this.resolveTargetPrimaryKey(target);
|
|
444
501
|
const canonical = this.canonicalizePrimaryKey(primaryKey);
|
|
@@ -452,7 +509,7 @@ else await this.inputs.runAtomic(() => this.deleteTargetPrimaryKeys(targetPrimar
|
|
|
452
509
|
if (typeof target === "string" || typeof target === "number") return target;
|
|
453
510
|
if (typeof target === "object" && target !== null) {
|
|
454
511
|
const targetPrimaryKey = target[this.inputs.targetPrimaryKeyField];
|
|
455
|
-
if (targetPrimaryKey ===
|
|
512
|
+
if (targetPrimaryKey === void 0 || targetPrimaryKey === null) throw new Error(`Cannot resolve target primary key '${this.inputs.targetPrimaryKeyField}' for relation '${this.inputs.relationName}' on '${this.inputs.ownerModelLabel}'.`);
|
|
456
513
|
return targetPrimaryKey;
|
|
457
514
|
}
|
|
458
515
|
throw new Error(`Unsupported target reference for relation '${this.inputs.relationName}' on '${this.inputs.ownerModelLabel}'. Expected a record, a primary-key carrier, or a primary-key value.`);
|
|
@@ -467,10 +524,12 @@ else await this.inputs.runAtomic(() => this.deleteTargetPrimaryKeys(targetPrimar
|
|
|
467
524
|
}
|
|
468
525
|
}
|
|
469
526
|
};
|
|
470
|
-
|
|
471
527
|
//#endregion
|
|
472
528
|
//#region src/manager/ModelManager.ts
|
|
473
529
|
const sqlSafetyAdapter = new OrmSqlSafetyAdapter();
|
|
530
|
+
/**
|
|
531
|
+
* Model-backed data access API exposed as `Model.objects`.
|
|
532
|
+
*/
|
|
474
533
|
var ModelManager = class ModelManager {
|
|
475
534
|
static BRAND = "tango.orm.model_manager";
|
|
476
535
|
__tangoBrand = ModelManager.BRAND;
|
|
@@ -493,8 +552,7 @@ var ModelManager = class ModelManager {
|
|
|
493
552
|
client: this.client,
|
|
494
553
|
adapter: this.adapter,
|
|
495
554
|
run: async (compiled) => {
|
|
496
|
-
|
|
497
|
-
return result.rows;
|
|
555
|
+
return (await this.client.query(compiled.sql, compiled.params)).rows;
|
|
498
556
|
},
|
|
499
557
|
attachPersistedRecordAccessors: (record, modelKey) => {
|
|
500
558
|
this.attachManyToManyRelatedManagers(record, modelKey ?? this.model.metadata.key);
|
|
@@ -521,42 +579,34 @@ var ModelManager = class ModelManager {
|
|
|
521
579
|
return validatedMeta;
|
|
522
580
|
}
|
|
523
581
|
static mergeCreatePayloadFromWhere(modelName, pkColumn, where, defaults) {
|
|
524
|
-
const hasDefaultsArg = defaults !==
|
|
525
|
-
const providedDefaults = defaults !==
|
|
582
|
+
const hasDefaultsArg = defaults !== void 0;
|
|
583
|
+
const providedDefaults = defaults !== void 0 ? { ...defaults } : void 0;
|
|
526
584
|
if (isQNodeLike(where)) {
|
|
527
585
|
if (!hasDefaultsArg || !providedDefaults || Object.keys(providedDefaults).length === 0) throw new Error(`Cannot create ${modelName} from Q filters without defaults.`);
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
...fromQ,
|
|
586
|
+
const merged = {
|
|
587
|
+
...ModelManager.collectPlainFieldsFromQNode(modelName, where),
|
|
531
588
|
...providedDefaults
|
|
532
589
|
};
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
if (nonPkKeys$1.length === 0) throw new Error(`Cannot create ${modelName} without any values.`);
|
|
536
|
-
return merged$1;
|
|
590
|
+
if (Object.keys(merged).filter((key) => merged[key] !== void 0).filter((key) => key !== pkColumn).length === 0) throw new Error(`Cannot create ${modelName} without any values.`);
|
|
591
|
+
return merged;
|
|
537
592
|
}
|
|
538
|
-
const
|
|
539
|
-
const entries = Object.entries(atom);
|
|
593
|
+
const entries = Object.entries(where);
|
|
540
594
|
const plainEntries = entries.filter(([key]) => !String(key).includes("__"));
|
|
541
595
|
const lookupOnly = entries.length > 0 && plainEntries.length === 0;
|
|
542
|
-
const fromAtom = plainEntries.length > 0 ? Object.fromEntries(plainEntries) : undefined;
|
|
543
596
|
const mergeBase = {
|
|
544
|
-
...
|
|
597
|
+
...plainEntries.length > 0 ? Object.fromEntries(plainEntries) : void 0,
|
|
545
598
|
...providedDefaults
|
|
546
599
|
};
|
|
547
600
|
if (lookupOnly && ModelManager.countDefinedValues(mergeBase, pkColumn) === 0) throw new Error(`Cannot create ${modelName} from lookup-only filters without defaults.`);
|
|
548
|
-
const cleanedAtom = plainEntries.length > 0 ? Object.fromEntries(plainEntries) : {};
|
|
549
601
|
const merged = {
|
|
550
|
-
...
|
|
602
|
+
...plainEntries.length > 0 ? Object.fromEntries(plainEntries) : {},
|
|
551
603
|
...mergeBase
|
|
552
604
|
};
|
|
553
|
-
|
|
554
|
-
const nonPkKeys = keys.filter((key) => key !== pkColumn);
|
|
555
|
-
if (nonPkKeys.length === 0) throw new Error(`Cannot create ${modelName} without any values.`);
|
|
605
|
+
if (Object.keys(merged).filter((key) => merged[key] !== void 0).filter((key) => key !== pkColumn).length === 0) throw new Error(`Cannot create ${modelName} without any values.`);
|
|
556
606
|
return merged;
|
|
557
607
|
}
|
|
558
608
|
static countDefinedValues(payload, pkColumn) {
|
|
559
|
-
return Object.entries(payload).filter(([key, value]) => key !== pkColumn && value !==
|
|
609
|
+
return Object.entries(payload).filter(([key, value]) => key !== pkColumn && value !== void 0).length;
|
|
560
610
|
}
|
|
561
611
|
static collectPlainFieldsFromQNode(modelName, node) {
|
|
562
612
|
switch (node.kind) {
|
|
@@ -566,8 +616,7 @@ var ModelManager = class ModelManager {
|
|
|
566
616
|
return ModelManager.mergeCompatiblePartials(partials);
|
|
567
617
|
}
|
|
568
618
|
case InternalQNodeType.OR: {
|
|
569
|
-
const
|
|
570
|
-
const nonEmpty = partials.filter((partial) => Object.keys(partial).length > 0);
|
|
619
|
+
const nonEmpty = (node.nodes ?? []).map((child) => ModelManager.collectPlainFieldsFromQNode(modelName, child)).filter((partial) => Object.keys(partial).length > 0);
|
|
571
620
|
if (nonEmpty.length > 1) throw new Error(`Cannot derive a create payload from ${modelName} OR filters with multiple predicates. Supply defaults that fully describe the insert.`);
|
|
572
621
|
return nonEmpty.length === 1 ? nonEmpty[0] : {};
|
|
573
622
|
}
|
|
@@ -582,7 +631,7 @@ var ModelManager = class ModelManager {
|
|
|
582
631
|
const merged = {};
|
|
583
632
|
for (const partial of partials) for (const [key, value] of Object.entries(partial)) {
|
|
584
633
|
const existing = merged[key];
|
|
585
|
-
if (existing !==
|
|
634
|
+
if (existing !== void 0 && existing !== value) throw new Error(`Conflicting values for '${key}' while deriving create payload from Q filters.`);
|
|
586
635
|
merged[key] = value;
|
|
587
636
|
}
|
|
588
637
|
return merged;
|
|
@@ -604,18 +653,16 @@ var ModelManager = class ModelManager {
|
|
|
604
653
|
}
|
|
605
654
|
async getOrCreate(args) {
|
|
606
655
|
try {
|
|
607
|
-
const record$1 = await this.query().get(args.where);
|
|
608
656
|
return {
|
|
609
|
-
record:
|
|
657
|
+
record: await this.query().get(args.where),
|
|
610
658
|
created: false
|
|
611
659
|
};
|
|
612
660
|
} catch (error) {
|
|
613
661
|
if (!NotFoundError.isNotFoundError(error)) throw error;
|
|
614
662
|
}
|
|
615
663
|
const merged = ModelManager.mergeCreatePayloadFromWhere(this.model.metadata.name, this.meta.pk, args.where, args.defaults);
|
|
616
|
-
const record = await this.create(merged);
|
|
617
664
|
return {
|
|
618
|
-
record,
|
|
665
|
+
record: await this.create(merged),
|
|
619
666
|
created: true
|
|
620
667
|
};
|
|
621
668
|
}
|
|
@@ -628,9 +675,8 @@ var ModelManager = class ModelManager {
|
|
|
628
675
|
}
|
|
629
676
|
if (!existing) {
|
|
630
677
|
const merged = ModelManager.mergeCreatePayloadFromWhere(this.model.metadata.name, this.meta.pk, args.where, args.defaults);
|
|
631
|
-
const record$1 = await this.create(merged);
|
|
632
678
|
return {
|
|
633
|
-
record:
|
|
679
|
+
record: await this.create(merged),
|
|
634
680
|
created: true,
|
|
635
681
|
updated: false
|
|
636
682
|
};
|
|
@@ -642,9 +688,8 @@ var ModelManager = class ModelManager {
|
|
|
642
688
|
updated: false
|
|
643
689
|
};
|
|
644
690
|
const id = existing[this.meta.pk];
|
|
645
|
-
const record = await this.update(id, patch);
|
|
646
691
|
return {
|
|
647
|
-
record,
|
|
692
|
+
record: await this.update(id, patch),
|
|
648
693
|
created: false,
|
|
649
694
|
updated: true
|
|
650
695
|
};
|
|
@@ -659,8 +704,7 @@ var ModelManager = class ModelManager {
|
|
|
659
704
|
writeKeys: preparedKeys
|
|
660
705
|
});
|
|
661
706
|
const compiled = this.mutationCompiler.compileInsert(validatedPlan, preparedKeys.map((key) => prepared[key]));
|
|
662
|
-
const
|
|
663
|
-
const created = result.rows[0];
|
|
707
|
+
const created = (await this.queryExecutor.client.query(compiled.sql, compiled.params)).rows[0];
|
|
664
708
|
this.attachOwnRelatedManagers(created);
|
|
665
709
|
await this.model.hooks?.afterCreate?.({
|
|
666
710
|
record: created,
|
|
@@ -681,8 +725,7 @@ var ModelManager = class ModelManager {
|
|
|
681
725
|
writeKeys: preparedKeys
|
|
682
726
|
});
|
|
683
727
|
const compiled = this.mutationCompiler.compileUpdate(validatedPlan, preparedKeys.map((key) => prepared[key]), id);
|
|
684
|
-
const
|
|
685
|
-
const updated = result.rows[0];
|
|
728
|
+
const updated = (await this.queryExecutor.client.query(compiled.sql, compiled.params)).rows[0];
|
|
686
729
|
this.attachOwnRelatedManagers(updated);
|
|
687
730
|
await this.model.hooks?.afterUpdate?.({
|
|
688
731
|
id,
|
|
@@ -727,8 +770,7 @@ var ModelManager = class ModelManager {
|
|
|
727
770
|
*/
|
|
728
771
|
createManyToManyRelatedManager(relationName, ownerPrimaryKey) {
|
|
729
772
|
const relation = this.requireManyToManyEdge(relationName);
|
|
730
|
-
const
|
|
731
|
-
const throughModel = registry.getByKey(relation.throughModelKey);
|
|
773
|
+
const throughModel = ModelRegistry.getOwner(this.model).getByKey(relation.throughModelKey);
|
|
732
774
|
return ManyToManyRelatedManager.create({
|
|
733
775
|
ownerPrimaryKey,
|
|
734
776
|
relationName,
|
|
@@ -748,6 +790,14 @@ var ModelManager = class ModelManager {
|
|
|
748
790
|
runAtomic: (work) => TransactionEngine.forRuntime(this.runtime).atomic(() => work())
|
|
749
791
|
});
|
|
750
792
|
}
|
|
793
|
+
/**
|
|
794
|
+
* Insert multiple rows in a single multi-row INSERT statement.
|
|
795
|
+
*
|
|
796
|
+
* All rows must share the same field set after hook processing. Rows with
|
|
797
|
+
* extra or missing fields relative to the first row will cause an error.
|
|
798
|
+
* If you need to insert rows with different field sets, use individual
|
|
799
|
+
* {@link create} calls instead.
|
|
800
|
+
*/
|
|
751
801
|
async bulkCreate(inputs) {
|
|
752
802
|
if (inputs.length === 0) return [];
|
|
753
803
|
const perRowPrepared = await Promise.all(inputs.map((input) => this.runBeforeCreate(input)));
|
|
@@ -759,6 +809,7 @@ var ModelManager = class ModelManager {
|
|
|
759
809
|
}) ?? perRowPrepared;
|
|
760
810
|
const preparedKeys = Object.keys(batchPrepared[0] ?? {});
|
|
761
811
|
if (preparedKeys.length === 0) throw new Error(`Cannot create ${this.model.metadata.name} without any values.`);
|
|
812
|
+
this.assertUniformRowShape(batchPrepared, new Set(preparedKeys));
|
|
762
813
|
const validatedPlan = sqlSafetyAdapter.validate({
|
|
763
814
|
kind: InternalSqlValidationPlanKind.INSERT,
|
|
764
815
|
meta: this.meta,
|
|
@@ -800,7 +851,7 @@ var ModelManager = class ModelManager {
|
|
|
800
851
|
const relations = meta.relations;
|
|
801
852
|
if (!relations) return;
|
|
802
853
|
const ownerPrimaryKey = record[meta.pk];
|
|
803
|
-
if (ownerPrimaryKey ===
|
|
854
|
+
if (ownerPrimaryKey === void 0 || ownerPrimaryKey === null) return;
|
|
804
855
|
for (const [relationName, relation] of Object.entries(relations)) {
|
|
805
856
|
if (relation.kind !== InternalRelationKind.MANY_TO_MANY) continue;
|
|
806
857
|
if (Object.prototype.hasOwnProperty.call(record, relationName)) continue;
|
|
@@ -809,14 +860,19 @@ var ModelManager = class ModelManager {
|
|
|
809
860
|
value: relatedManager,
|
|
810
861
|
writable: true,
|
|
811
862
|
configurable: true,
|
|
863
|
+
/**
|
|
864
|
+
* Non-enumerable so `Object.keys(record)`, `JSON.stringify(record)`,
|
|
865
|
+
* `{ ...record }`, and similar enumeration paths continue to
|
|
866
|
+
* see only the persisted columns. Application code reaches the
|
|
867
|
+
* manager through `record.tags`, never through enumeration.
|
|
868
|
+
*/
|
|
812
869
|
enumerable: false
|
|
813
870
|
});
|
|
814
871
|
}
|
|
815
872
|
}
|
|
816
873
|
resolveManagerForModelKey(modelKey) {
|
|
817
874
|
if (modelKey === this.model.metadata.key) return this;
|
|
818
|
-
const
|
|
819
|
-
const otherModel = registry.getByKey(modelKey);
|
|
875
|
+
const otherModel = ModelRegistry.getOwner(this.model).getByKey(modelKey);
|
|
820
876
|
if (!otherModel) return null;
|
|
821
877
|
const candidate = otherModel.objects;
|
|
822
878
|
return ModelManager.isModelManager(candidate) ? candidate : null;
|
|
@@ -857,11 +913,32 @@ var ModelManager = class ModelManager {
|
|
|
857
913
|
getHookTransaction() {
|
|
858
914
|
return TransactionEngine.forRuntime(this.runtime).getActiveTransaction();
|
|
859
915
|
}
|
|
916
|
+
assertUniformRowShape(batch, referenceKeys) {
|
|
917
|
+
const divergentRows = batch.slice(1).map((row, i) => {
|
|
918
|
+
const rowKeys = new Set(Object.keys(row));
|
|
919
|
+
const missing = [...referenceKeys].filter((k) => !rowKeys.has(k)).sort();
|
|
920
|
+
const extra = [...rowKeys].filter((k) => !referenceKeys.has(k)).sort();
|
|
921
|
+
return {
|
|
922
|
+
index: i + 1,
|
|
923
|
+
missing,
|
|
924
|
+
extra
|
|
925
|
+
};
|
|
926
|
+
}).filter((r) => r.missing.length > 0 || r.extra.length > 0);
|
|
927
|
+
if (divergentRows.length === 0) return;
|
|
928
|
+
const sortedReferenceKeys = [...referenceKeys].sort();
|
|
929
|
+
const indices = divergentRows.map((r) => r.index);
|
|
930
|
+
const details = divergentRows.map((r) => {
|
|
931
|
+
const parts = [];
|
|
932
|
+
if (r.missing.length > 0) parts.push(`missing [${r.missing.join(", ")}]`);
|
|
933
|
+
if (r.extra.length > 0) parts.push(`extra [${r.extra.join(", ")}]`);
|
|
934
|
+
return `Row at index ${r.index}: ${parts.join(", ")}.`;
|
|
935
|
+
}).join("\n");
|
|
936
|
+
throw new Error(`bulkCreate failed after hook processing: rows at indices [${indices.join(", ")}] have mismatched fields.\n${details}\nExpected fields (from row at index 0): [${sortedReferenceKeys.join(", ")}].`);
|
|
937
|
+
}
|
|
860
938
|
};
|
|
861
|
-
|
|
862
939
|
//#endregion
|
|
863
940
|
//#region src/manager/registerModelObjects.ts
|
|
864
|
-
const managerCache = new WeakMap();
|
|
941
|
+
const managerCache = /* @__PURE__ */ new WeakMap();
|
|
865
942
|
let hasRegisteredModelObjects = false;
|
|
866
943
|
function defineObjectsProperty(model) {
|
|
867
944
|
Object.defineProperty(model, "objects", {
|
|
@@ -880,12 +957,16 @@ function defineObjectsProperty(model) {
|
|
|
880
957
|
}
|
|
881
958
|
});
|
|
882
959
|
}
|
|
960
|
+
/**
|
|
961
|
+
* Install the schema model augmentor that exposes `Model.objects`.
|
|
962
|
+
* This registration is idempotent so multiple Tango entrypoints can safely call it.
|
|
963
|
+
*/
|
|
883
964
|
function registerModelObjects() {
|
|
884
965
|
if (hasRegisteredModelObjects) return;
|
|
885
966
|
registerModelAugmentor(defineObjectsProperty);
|
|
886
967
|
hasRegisteredModelObjects = true;
|
|
887
968
|
}
|
|
888
|
-
|
|
889
969
|
//#endregion
|
|
890
|
-
export {
|
|
891
|
-
|
|
970
|
+
export { ManyToManyRelatedQuerySet as i, ModelManager as n, ManyToManyRelatedManager as r, registerModelObjects as t };
|
|
971
|
+
|
|
972
|
+
//# sourceMappingURL=registerModelObjects-DZfZ20fa.js.map
|