@holo-js/db 0.2.4 → 0.2.6
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/index.d.ts +292 -6
- package/dist/index.mjs +2753 -188
- package/package.json +7 -7
package/dist/index.mjs
CHANGED
|
@@ -122,6 +122,11 @@ function redactSql(sql, policy) {
|
|
|
122
122
|
// src/cache.ts
|
|
123
123
|
import { createHash } from "crypto";
|
|
124
124
|
import { AsyncLocalStorage } from "async_hooks";
|
|
125
|
+
var DATABASE_DEPENDENCY_PREFIX = "db:";
|
|
126
|
+
var DATABASE_DEPENDENCY_METADATA_KEY = "__holoDatabaseDependencyMetadata__";
|
|
127
|
+
var MUTATION_DEPENDENCY_SUFFIX = "mutation";
|
|
128
|
+
var WHERE_DEPENDENCY_PREFIX = "where:";
|
|
129
|
+
var WHERE_EXACT_DEPENDENCY_PREFIX = "where-exact:";
|
|
125
130
|
var databaseDependencyCollector = new AsyncLocalStorage();
|
|
126
131
|
function getQueryCacheBridgeState() {
|
|
127
132
|
const runtime = globalThis;
|
|
@@ -140,34 +145,268 @@ function resetDatabaseQueryCacheBridge() {
|
|
|
140
145
|
function onDatabaseDependencyInvalidated(listener) {
|
|
141
146
|
const state = getQueryCacheBridgeState();
|
|
142
147
|
state.dependencyInvalidationListeners ??= /* @__PURE__ */ new Set();
|
|
143
|
-
|
|
148
|
+
const internalListener = listener;
|
|
149
|
+
state.dependencyInvalidationListeners.add(internalListener);
|
|
144
150
|
return () => {
|
|
145
|
-
state.dependencyInvalidationListeners?.delete(
|
|
151
|
+
state.dependencyInvalidationListeners?.delete(internalListener);
|
|
146
152
|
};
|
|
147
153
|
}
|
|
148
154
|
function resetDatabaseDependencyInvalidationListeners() {
|
|
149
155
|
getQueryCacheBridgeState().dependencyInvalidationListeners = void 0;
|
|
150
156
|
}
|
|
151
157
|
async function collectDatabaseQueryDependencies(callback) {
|
|
152
|
-
const
|
|
153
|
-
|
|
158
|
+
const result = await collectDatabaseQueryDependenciesInternal(callback);
|
|
159
|
+
return Object.freeze({
|
|
160
|
+
value: result.value,
|
|
161
|
+
dependencies: result.dependencies
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async function collectDatabaseQueryDependenciesInternal(callback) {
|
|
165
|
+
const state = {
|
|
166
|
+
dependencies: /* @__PURE__ */ new Set(),
|
|
167
|
+
queries: []
|
|
168
|
+
};
|
|
169
|
+
const value = await databaseDependencyCollector.run(state, callback);
|
|
154
170
|
return Object.freeze({
|
|
155
171
|
value,
|
|
156
|
-
dependencies: Object.freeze([...dependencies])
|
|
172
|
+
dependencies: Object.freeze([...state.dependencies]),
|
|
173
|
+
queries: Object.freeze([...state.queries])
|
|
157
174
|
});
|
|
158
175
|
}
|
|
176
|
+
function hasActiveDatabaseDependencyCollector() {
|
|
177
|
+
return typeof databaseDependencyCollector.getStore() !== "undefined";
|
|
178
|
+
}
|
|
159
179
|
function recordDatabaseQueryDependencies(dependencies) {
|
|
160
180
|
if (!dependencies || dependencies.length === 0) {
|
|
161
181
|
return;
|
|
162
182
|
}
|
|
163
|
-
const
|
|
164
|
-
if (!
|
|
183
|
+
const state = databaseDependencyCollector.getStore();
|
|
184
|
+
if (!state) {
|
|
165
185
|
return;
|
|
166
186
|
}
|
|
167
187
|
for (const dependency of dependencies) {
|
|
168
|
-
|
|
188
|
+
state.dependencies.add(dependency);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function recordDatabaseQueryObservation(observation) {
|
|
192
|
+
if (!observation) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const state = databaseDependencyCollector.getStore();
|
|
196
|
+
if (!state) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
state.queries.push(observation);
|
|
200
|
+
}
|
|
201
|
+
function readDatabaseQueryObservationCount() {
|
|
202
|
+
return databaseDependencyCollector.getStore()?.queries.length ?? 0;
|
|
203
|
+
}
|
|
204
|
+
function truncateDatabaseQueryObservations(count) {
|
|
205
|
+
const state = databaseDependencyCollector.getStore();
|
|
206
|
+
if (!state || count >= state.queries.length) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
state.queries.length = Math.max(0, count);
|
|
210
|
+
}
|
|
211
|
+
function rebindDatabaseQueryObservationResult(source, result) {
|
|
212
|
+
rebindDatabaseQueryObservation(source, result);
|
|
213
|
+
}
|
|
214
|
+
function rebindDatabaseQueryObservationHydratedResult(source, result, belongsToHydrations, relatedHydrations) {
|
|
215
|
+
rebindDatabaseQueryObservation(source, result, void 0, void 0, void 0, void 0, belongsToHydrations, relatedHydrations);
|
|
216
|
+
}
|
|
217
|
+
function rebindDatabaseQueryObservationPagination(source, data, meta, pagination, offset, belongsToHydrations, relatedHydrations) {
|
|
218
|
+
const state = databaseDependencyCollector.getStore();
|
|
219
|
+
if (!state) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
for (let index = state.queries.length - 1; index >= 0; index -= 1) {
|
|
223
|
+
const query = state.queries[index];
|
|
224
|
+
if (!query || query.result !== source) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
state.queries[index] = Object.freeze({
|
|
228
|
+
aggregate: void 0,
|
|
229
|
+
belongsToHydrations: belongsToHydrations ?? query.belongsToHydrations,
|
|
230
|
+
connectionName: query.connectionName,
|
|
231
|
+
tableName: query.tableName,
|
|
232
|
+
dependencies: query.dependencies,
|
|
233
|
+
limit: pagination.perPage,
|
|
234
|
+
offset,
|
|
235
|
+
orderBy: query.orderBy,
|
|
236
|
+
patchable: query.patchable,
|
|
237
|
+
pagination: void 0,
|
|
238
|
+
predicates: query.predicates,
|
|
239
|
+
relation: query.relation,
|
|
240
|
+
result: data,
|
|
241
|
+
resultPath: query.resultPath,
|
|
242
|
+
relatedHydrations: relatedHydrations ?? query.relatedHydrations,
|
|
243
|
+
scalarColumn: void 0,
|
|
244
|
+
scalarListColumn: void 0,
|
|
245
|
+
scalarListRows: void 0,
|
|
246
|
+
selections: query.selections
|
|
247
|
+
});
|
|
248
|
+
state.queries.push(Object.freeze({
|
|
249
|
+
aggregate: void 0,
|
|
250
|
+
belongsToHydrations: void 0,
|
|
251
|
+
connectionName: query.connectionName,
|
|
252
|
+
tableName: query.tableName,
|
|
253
|
+
dependencies: query.dependencies,
|
|
254
|
+
limit: void 0,
|
|
255
|
+
offset: void 0,
|
|
256
|
+
orderBy: query.orderBy,
|
|
257
|
+
patchable: query.patchable,
|
|
258
|
+
pagination,
|
|
259
|
+
predicates: query.predicates,
|
|
260
|
+
relation: query.relation,
|
|
261
|
+
result: meta,
|
|
262
|
+
resultPath: void 0,
|
|
263
|
+
relatedHydrations: void 0,
|
|
264
|
+
scalarColumn: void 0,
|
|
265
|
+
scalarListColumn: void 0,
|
|
266
|
+
scalarListRows: void 0,
|
|
267
|
+
selections: query.selections
|
|
268
|
+
}));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function rebindDatabaseQueryObservationCursorPagination(source, data, meta, pagination, belongsToHydrations, relatedHydrations) {
|
|
273
|
+
const state = databaseDependencyCollector.getStore();
|
|
274
|
+
if (!state) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
for (let index = state.queries.length - 1; index >= 0; index -= 1) {
|
|
278
|
+
const query = state.queries[index];
|
|
279
|
+
if (!query || query.result !== source) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
state.queries[index] = Object.freeze({
|
|
283
|
+
aggregate: void 0,
|
|
284
|
+
belongsToHydrations: belongsToHydrations ?? query.belongsToHydrations,
|
|
285
|
+
connectionName: query.connectionName,
|
|
286
|
+
tableName: query.tableName,
|
|
287
|
+
cursorRowCount: pagination.rowCount,
|
|
288
|
+
cursorRows: pagination.rows,
|
|
289
|
+
dependencies: query.dependencies,
|
|
290
|
+
limit: pagination.perPage,
|
|
291
|
+
offset: void 0,
|
|
292
|
+
orderBy: query.orderBy,
|
|
293
|
+
patchable: query.patchable,
|
|
294
|
+
pagination: void 0,
|
|
295
|
+
predicates: query.predicates,
|
|
296
|
+
relation: query.relation,
|
|
297
|
+
result: data,
|
|
298
|
+
resultPath: query.resultPath,
|
|
299
|
+
relatedHydrations: relatedHydrations ?? query.relatedHydrations,
|
|
300
|
+
scalarColumn: void 0,
|
|
301
|
+
scalarListColumn: void 0,
|
|
302
|
+
scalarListRows: void 0,
|
|
303
|
+
selections: query.selections
|
|
304
|
+
});
|
|
305
|
+
state.queries.push(Object.freeze({
|
|
306
|
+
aggregate: void 0,
|
|
307
|
+
belongsToHydrations: void 0,
|
|
308
|
+
connectionName: query.connectionName,
|
|
309
|
+
tableName: query.tableName,
|
|
310
|
+
dependencies: query.dependencies,
|
|
311
|
+
limit: void 0,
|
|
312
|
+
offset: void 0,
|
|
313
|
+
orderBy: query.orderBy,
|
|
314
|
+
patchable: query.patchable,
|
|
315
|
+
pagination,
|
|
316
|
+
predicates: query.predicates,
|
|
317
|
+
relation: query.relation,
|
|
318
|
+
result: meta.nextCursor,
|
|
319
|
+
resultPath: Object.freeze(["nextCursor"]),
|
|
320
|
+
relatedHydrations: void 0,
|
|
321
|
+
scalarColumn: void 0,
|
|
322
|
+
scalarListColumn: void 0,
|
|
323
|
+
scalarListRows: void 0,
|
|
324
|
+
selections: query.selections
|
|
325
|
+
}));
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function disableDatabaseQueryObservationPatching(source) {
|
|
330
|
+
const state = databaseDependencyCollector.getStore();
|
|
331
|
+
if (!state) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
for (let index = state.queries.length - 1; index >= 0; index -= 1) {
|
|
335
|
+
const query = state.queries[index];
|
|
336
|
+
if (!query || query.result !== source) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
state.queries[index] = Object.freeze({
|
|
340
|
+
aggregate: query.aggregate,
|
|
341
|
+
belongsToHydrations: query.belongsToHydrations,
|
|
342
|
+
connectionName: query.connectionName,
|
|
343
|
+
tableName: query.tableName,
|
|
344
|
+
dependencies: query.dependencies,
|
|
345
|
+
limit: query.limit,
|
|
346
|
+
offset: query.offset,
|
|
347
|
+
orderBy: query.orderBy,
|
|
348
|
+
patchable: false,
|
|
349
|
+
pagination: query.pagination,
|
|
350
|
+
predicates: query.predicates,
|
|
351
|
+
relation: query.relation,
|
|
352
|
+
result: query.result,
|
|
353
|
+
resultPath: query.resultPath,
|
|
354
|
+
relatedHydrations: query.relatedHydrations,
|
|
355
|
+
scalarColumn: query.scalarColumn,
|
|
356
|
+
scalarListColumn: query.scalarListColumn,
|
|
357
|
+
scalarListRows: query.scalarListRows,
|
|
358
|
+
selections: query.selections
|
|
359
|
+
});
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function rebindDatabaseQueryObservationAggregate(source, result, aggregate) {
|
|
364
|
+
rebindDatabaseQueryObservation(source, result, aggregate);
|
|
365
|
+
}
|
|
366
|
+
function rebindDatabaseQueryObservationScalar(source, result, column2) {
|
|
367
|
+
rebindDatabaseQueryObservation(source, result, void 0, column2);
|
|
368
|
+
}
|
|
369
|
+
function rebindDatabaseQueryObservationScalarList(rows, result, column2) {
|
|
370
|
+
rebindDatabaseQueryObservation(rows, result, void 0, void 0, column2, rows);
|
|
371
|
+
}
|
|
372
|
+
function rebindDatabaseQueryObservation(source, result, aggregate, scalarColumn, scalarListColumn, scalarListRows, belongsToHydrations, relatedHydrations) {
|
|
373
|
+
const state = databaseDependencyCollector.getStore();
|
|
374
|
+
if (!state) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
for (let index = state.queries.length - 1; index >= 0; index -= 1) {
|
|
378
|
+
const query = state.queries[index];
|
|
379
|
+
if (!query || query.result !== source) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
state.queries[index] = Object.freeze({
|
|
383
|
+
aggregate,
|
|
384
|
+
belongsToHydrations,
|
|
385
|
+
connectionName: query.connectionName,
|
|
386
|
+
tableName: query.tableName,
|
|
387
|
+
dependencies: query.dependencies,
|
|
388
|
+
limit: query.limit,
|
|
389
|
+
offset: query.offset,
|
|
390
|
+
orderBy: query.orderBy,
|
|
391
|
+
patchable: query.patchable,
|
|
392
|
+
pagination: query.pagination,
|
|
393
|
+
predicates: query.predicates,
|
|
394
|
+
relation: query.relation,
|
|
395
|
+
result,
|
|
396
|
+
resultPath: query.resultPath,
|
|
397
|
+
relatedHydrations,
|
|
398
|
+
scalarColumn,
|
|
399
|
+
scalarListColumn,
|
|
400
|
+
scalarListRows,
|
|
401
|
+
selections: query.selections
|
|
402
|
+
});
|
|
403
|
+
return;
|
|
169
404
|
}
|
|
170
405
|
}
|
|
406
|
+
function hasDatabaseDependencyInvalidationListeners() {
|
|
407
|
+
const listeners = getQueryCacheBridgeState().dependencyInvalidationListeners;
|
|
408
|
+
return typeof listeners !== "undefined" && listeners.size > 0;
|
|
409
|
+
}
|
|
171
410
|
async function notifyDatabaseDependencyInvalidationListeners(event) {
|
|
172
411
|
const listeners = getQueryCacheBridgeState().dependencyInvalidationListeners;
|
|
173
412
|
if (!listeners || listeners.size === 0) {
|
|
@@ -232,6 +471,173 @@ function resolveQueryCacheKey(statement, connectionName, config) {
|
|
|
232
471
|
function createTableCacheDependency(connectionName, tableName) {
|
|
233
472
|
return `db:${connectionName}:${tableName}`;
|
|
234
473
|
}
|
|
474
|
+
function encodeDependencyValue(value) {
|
|
475
|
+
return encodeURIComponent(JSON.stringify(value));
|
|
476
|
+
}
|
|
477
|
+
function createPredicateMetadata(connectionName, tableName, columnName, value) {
|
|
478
|
+
if (typeof value === "undefined") {
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
481
|
+
return Object.freeze({
|
|
482
|
+
tableKey: createTableCacheDependency(connectionName, tableName),
|
|
483
|
+
columnName: getColumnName(columnName),
|
|
484
|
+
encodedValue: encodeDependencyValue(value)
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
function createPredicateDependencyFromMetadata(metadata, exact) {
|
|
488
|
+
return `${metadata.tableKey}:${exact ? WHERE_EXACT_DEPENDENCY_PREFIX : WHERE_DEPENDENCY_PREFIX}${metadata.columnName}:${metadata.encodedValue}`;
|
|
489
|
+
}
|
|
490
|
+
function createPredicateDependencyEntry(connectionName, tableName, columnName, value, exact = false) {
|
|
491
|
+
const metadata = createPredicateMetadata(connectionName, tableName, columnName, value);
|
|
492
|
+
if (!metadata) {
|
|
493
|
+
return void 0;
|
|
494
|
+
}
|
|
495
|
+
return {
|
|
496
|
+
dependency: createPredicateDependencyFromMetadata(metadata, exact),
|
|
497
|
+
metadata
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
function readExactPredicateValues(predicate) {
|
|
501
|
+
if (predicate.kind !== "comparison") {
|
|
502
|
+
return Object.freeze([]);
|
|
503
|
+
}
|
|
504
|
+
if (predicate.operator === "=") {
|
|
505
|
+
return Object.freeze([predicate.value]);
|
|
506
|
+
}
|
|
507
|
+
if (predicate.operator === "in" && Array.isArray(predicate.value)) {
|
|
508
|
+
return Object.freeze([...predicate.value]);
|
|
509
|
+
}
|
|
510
|
+
return Object.freeze([]);
|
|
511
|
+
}
|
|
512
|
+
function createTableRowCacheDependency(connectionName, tableName, columnName, value) {
|
|
513
|
+
if (typeof value === "undefined") {
|
|
514
|
+
return void 0;
|
|
515
|
+
}
|
|
516
|
+
return `db:${connectionName}:${tableName}:row:${columnName}:${encodeDependencyValue(value)}`;
|
|
517
|
+
}
|
|
518
|
+
function createTableRowWildcardCacheDependency(connectionName, tableName) {
|
|
519
|
+
return `db:${connectionName}:${tableName}:row:*`;
|
|
520
|
+
}
|
|
521
|
+
function createTablePredicateCacheDependency(connectionName, tableName, columnName, value) {
|
|
522
|
+
return createPredicateDependencyEntry(connectionName, tableName, columnName, value)?.dependency;
|
|
523
|
+
}
|
|
524
|
+
function createTableMutationCacheDependency(connectionName, tableName) {
|
|
525
|
+
return `db:${connectionName}:${tableName}:mutation`;
|
|
526
|
+
}
|
|
527
|
+
function createTableExactPredicateCacheDependency(connectionName, tableName, columnName, value) {
|
|
528
|
+
return createPredicateDependencyEntry(connectionName, tableName, columnName, value, true)?.dependency;
|
|
529
|
+
}
|
|
530
|
+
function parseDatabaseDependency(dependency) {
|
|
531
|
+
if (!dependency.startsWith(DATABASE_DEPENDENCY_PREFIX)) {
|
|
532
|
+
return void 0;
|
|
533
|
+
}
|
|
534
|
+
const connectionEnd = dependency.indexOf(":", DATABASE_DEPENDENCY_PREFIX.length);
|
|
535
|
+
if (connectionEnd <= DATABASE_DEPENDENCY_PREFIX.length) {
|
|
536
|
+
return void 0;
|
|
537
|
+
}
|
|
538
|
+
const tableStart = connectionEnd + 1;
|
|
539
|
+
const tableEnd = dependency.indexOf(":", tableStart);
|
|
540
|
+
if (tableEnd < 0) {
|
|
541
|
+
return tableStart === dependency.length ? void 0 : { tableKey: dependency };
|
|
542
|
+
}
|
|
543
|
+
if (tableEnd === tableStart) {
|
|
544
|
+
return void 0;
|
|
545
|
+
}
|
|
546
|
+
const suffixStart = tableEnd + 1;
|
|
547
|
+
return {
|
|
548
|
+
suffix: suffixStart === dependency.length ? "" : dependency.slice(suffixStart),
|
|
549
|
+
tableKey: dependency.slice(0, tableEnd)
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function parsePredicateDependencySuffix(tableKey, suffix, prefix) {
|
|
553
|
+
if (!suffix.startsWith(prefix)) {
|
|
554
|
+
return void 0;
|
|
555
|
+
}
|
|
556
|
+
const columnStart = prefix.length;
|
|
557
|
+
const valueSeparator = suffix.indexOf(":", columnStart);
|
|
558
|
+
if (valueSeparator <= columnStart || valueSeparator === suffix.length - 1) {
|
|
559
|
+
return void 0;
|
|
560
|
+
}
|
|
561
|
+
return Object.freeze({
|
|
562
|
+
tableKey,
|
|
563
|
+
columnName: suffix.slice(columnStart, valueSeparator),
|
|
564
|
+
encodedValue: suffix.slice(valueSeparator + 1)
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
function createDatabaseDependencyInvalidationMetadata(dependencies, mutations) {
|
|
568
|
+
const directDependencies = [];
|
|
569
|
+
const exactPredicates = [];
|
|
570
|
+
const predicates = [];
|
|
571
|
+
const tableDependencyCandidates = [];
|
|
572
|
+
let hasMutationDependency = mutations.some((mutation) => mutation.kind === "upsert");
|
|
573
|
+
for (const dependency of dependencies) {
|
|
574
|
+
const parsed = parseDatabaseDependency(dependency);
|
|
575
|
+
if (!parsed) {
|
|
576
|
+
directDependencies.push(dependency);
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
if (parsed.suffix === void 0) {
|
|
580
|
+
tableDependencyCandidates.push(parsed.tableKey);
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
if (parsed.suffix === MUTATION_DEPENDENCY_SUFFIX) {
|
|
584
|
+
hasMutationDependency = true;
|
|
585
|
+
directDependencies.push(dependency);
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
const exactPredicate = parsePredicateDependencySuffix(
|
|
589
|
+
parsed.tableKey,
|
|
590
|
+
parsed.suffix,
|
|
591
|
+
WHERE_EXACT_DEPENDENCY_PREFIX
|
|
592
|
+
);
|
|
593
|
+
if (exactPredicate) {
|
|
594
|
+
exactPredicates.push(exactPredicate);
|
|
595
|
+
directDependencies.push(dependency);
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
const predicate = parsePredicateDependencySuffix(
|
|
599
|
+
parsed.tableKey,
|
|
600
|
+
parsed.suffix,
|
|
601
|
+
WHERE_DEPENDENCY_PREFIX
|
|
602
|
+
);
|
|
603
|
+
if (predicate) {
|
|
604
|
+
predicates.push(predicate);
|
|
605
|
+
directDependencies.push(dependency);
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
directDependencies.push(dependency);
|
|
609
|
+
}
|
|
610
|
+
const exactPredicateTables = new Set(exactPredicates.map((predicate) => predicate.tableKey));
|
|
611
|
+
const tableDependencies = [];
|
|
612
|
+
for (const tableKey of tableDependencyCandidates) {
|
|
613
|
+
if (exactPredicateTables.has(tableKey)) {
|
|
614
|
+
tableDependencies.push(tableKey);
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
directDependencies.push(tableKey);
|
|
618
|
+
}
|
|
619
|
+
return Object.freeze({
|
|
620
|
+
directDependencies: Object.freeze(directDependencies),
|
|
621
|
+
exactPredicates: Object.freeze(exactPredicates),
|
|
622
|
+
hasMutationDependency,
|
|
623
|
+
predicates: Object.freeze(predicates),
|
|
624
|
+
tableDependencies: Object.freeze(tableDependencies)
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
function createDatabaseDependencyInvalidationEvent(connectionName, dependencies, mutations, metadata) {
|
|
628
|
+
const event = {
|
|
629
|
+
connectionName,
|
|
630
|
+
dependencies,
|
|
631
|
+
mutations
|
|
632
|
+
};
|
|
633
|
+
Object.defineProperty(event, DATABASE_DEPENDENCY_METADATA_KEY, {
|
|
634
|
+
configurable: false,
|
|
635
|
+
enumerable: false,
|
|
636
|
+
value: metadata ?? createDatabaseDependencyInvalidationMetadata(dependencies, mutations),
|
|
637
|
+
writable: false
|
|
638
|
+
});
|
|
639
|
+
return Object.freeze(event);
|
|
640
|
+
}
|
|
235
641
|
function normalizeQueryCacheDependencies(connectionName, dependencies) {
|
|
236
642
|
return Object.freeze(dependencies.map((dependency) => {
|
|
237
643
|
return dependency.startsWith("db:") ? dependency : createTableCacheDependency(connectionName, dependency);
|
|
@@ -257,8 +663,403 @@ function supportsAutomaticPredicateInvalidation(predicate) {
|
|
|
257
663
|
return false;
|
|
258
664
|
}
|
|
259
665
|
}
|
|
666
|
+
function getColumnName(column2) {
|
|
667
|
+
const segments = column2.split(".");
|
|
668
|
+
return segments[segments.length - 1] ?? column2;
|
|
669
|
+
}
|
|
670
|
+
function getPrimaryKeyColumn(plan) {
|
|
671
|
+
const columns = plan.source.table?.columns;
|
|
672
|
+
if (!columns) {
|
|
673
|
+
return "id";
|
|
674
|
+
}
|
|
675
|
+
return Object.values(columns).find((column2) => column2.primaryKey)?.name ?? "id";
|
|
676
|
+
}
|
|
677
|
+
function hasDisjunctivePredicate(predicates) {
|
|
678
|
+
return predicates.some((predicate) => {
|
|
679
|
+
if (predicate.boolean === "or") {
|
|
680
|
+
return true;
|
|
681
|
+
}
|
|
682
|
+
if (predicate.kind !== "group") {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
return predicate.negated === true || hasDisjunctivePredicate(predicate.predicates);
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
function findExactPrimaryKeyValue(predicates, primaryKeyColumn) {
|
|
689
|
+
for (const predicate of predicates) {
|
|
690
|
+
if (predicate.kind === "comparison" && predicate.operator === "=" && getColumnName(predicate.column) === primaryKeyColumn) {
|
|
691
|
+
return predicate.value;
|
|
692
|
+
}
|
|
693
|
+
if (predicate.kind === "group" && !predicate.negated && predicate.boolean !== "or") {
|
|
694
|
+
const value = findExactPrimaryKeyValue(predicate.predicates, primaryKeyColumn);
|
|
695
|
+
if (typeof value !== "undefined") {
|
|
696
|
+
return value;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return void 0;
|
|
701
|
+
}
|
|
702
|
+
function collectExactPredicateDependencies(predicates, connectionName, tableName, exact = false) {
|
|
703
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
704
|
+
for (const predicate of predicates) {
|
|
705
|
+
const values = readExactPredicateValues(predicate);
|
|
706
|
+
if (values.length > 0 && predicate.kind === "comparison") {
|
|
707
|
+
for (const value of values) {
|
|
708
|
+
const dependency = exact ? createTableExactPredicateCacheDependency(
|
|
709
|
+
connectionName,
|
|
710
|
+
tableName,
|
|
711
|
+
getColumnName(predicate.column),
|
|
712
|
+
value
|
|
713
|
+
) : createTablePredicateCacheDependency(
|
|
714
|
+
connectionName,
|
|
715
|
+
tableName,
|
|
716
|
+
getColumnName(predicate.column),
|
|
717
|
+
value
|
|
718
|
+
);
|
|
719
|
+
if (dependency) {
|
|
720
|
+
dependencies.add(dependency);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
if (predicate.kind === "group" && !predicate.negated && predicate.boolean !== "or") {
|
|
726
|
+
for (const dependency of collectExactPredicateDependencies(predicate.predicates, connectionName, tableName, exact)) {
|
|
727
|
+
dependencies.add(dependency);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return Object.freeze([...dependencies]);
|
|
732
|
+
}
|
|
733
|
+
function appendExactPredicateDependencyEntries(target, predicates, connectionName, tableName, exact = false) {
|
|
734
|
+
for (const predicate of predicates) {
|
|
735
|
+
const values = readExactPredicateValues(predicate);
|
|
736
|
+
if (values.length > 0 && predicate.kind === "comparison") {
|
|
737
|
+
for (const value of values) {
|
|
738
|
+
const entry = createPredicateDependencyEntry(
|
|
739
|
+
connectionName,
|
|
740
|
+
tableName,
|
|
741
|
+
getColumnName(predicate.column),
|
|
742
|
+
value,
|
|
743
|
+
exact
|
|
744
|
+
);
|
|
745
|
+
if (entry) {
|
|
746
|
+
target.set(entry.dependency, entry);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
if (predicate.kind === "group" && !predicate.negated && predicate.boolean !== "or") {
|
|
752
|
+
appendExactPredicateDependencyEntries(target, predicate.predicates, connectionName, tableName, exact);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
function collectRecordPredicateDependencies(connectionName, tableName, record, exact = false) {
|
|
757
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
758
|
+
for (const [columnName, value] of Object.entries(record)) {
|
|
759
|
+
const dependency = exact ? createTableExactPredicateCacheDependency(connectionName, tableName, getColumnName(columnName), value) : createTablePredicateCacheDependency(connectionName, tableName, getColumnName(columnName), value);
|
|
760
|
+
if (dependency) {
|
|
761
|
+
dependencies.add(dependency);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return Object.freeze([...dependencies]);
|
|
765
|
+
}
|
|
766
|
+
function appendRecordPredicateDependencyEntries(target, connectionName, tableName, record, exact = false) {
|
|
767
|
+
for (const [columnName, value] of Object.entries(record)) {
|
|
768
|
+
const entry = createPredicateDependencyEntry(connectionName, tableName, getColumnName(columnName), value, exact);
|
|
769
|
+
if (entry) {
|
|
770
|
+
target.set(entry.dependency, entry);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
function createInvalidationMetadataFromParts(directDependencies, exactPredicates, predicates, tableDependencyCandidates, hasMutationDependency) {
|
|
775
|
+
const exactPredicateTables = new Set(exactPredicates.map((predicate) => predicate.tableKey));
|
|
776
|
+
const nextDirectDependencies = [...directDependencies];
|
|
777
|
+
const tableDependencies = [];
|
|
778
|
+
for (const tableKey of tableDependencyCandidates) {
|
|
779
|
+
if (exactPredicateTables.has(tableKey)) {
|
|
780
|
+
tableDependencies.push(tableKey);
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
nextDirectDependencies.push(tableKey);
|
|
784
|
+
}
|
|
785
|
+
return Object.freeze({
|
|
786
|
+
directDependencies: Object.freeze(nextDirectDependencies),
|
|
787
|
+
exactPredicates: Object.freeze([...exactPredicates]),
|
|
788
|
+
hasMutationDependency,
|
|
789
|
+
predicates: Object.freeze([...predicates]),
|
|
790
|
+
tableDependencies: Object.freeze(tableDependencies)
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
function collectQueryPredicateObservations(predicates) {
|
|
794
|
+
const observations = [];
|
|
795
|
+
for (const predicate of predicates) {
|
|
796
|
+
if (predicate.kind === "comparison") {
|
|
797
|
+
observations.push(Object.freeze({
|
|
798
|
+
column: getColumnName(predicate.column),
|
|
799
|
+
operator: predicate.operator,
|
|
800
|
+
value: predicate.value
|
|
801
|
+
}));
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
if (predicate.kind === "group" && !predicate.negated && predicate.boolean !== "or") {
|
|
805
|
+
observations.push(...collectQueryPredicateObservations(predicate.predicates));
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
return Object.freeze(observations);
|
|
809
|
+
}
|
|
810
|
+
function collectQueryOrderObservations(plan) {
|
|
811
|
+
return Object.freeze(plan.orderBy.flatMap((order) => {
|
|
812
|
+
if (order.kind !== "column") {
|
|
813
|
+
return [];
|
|
814
|
+
}
|
|
815
|
+
return [Object.freeze({
|
|
816
|
+
column: getColumnName(order.column),
|
|
817
|
+
direction: order.direction
|
|
818
|
+
})];
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
function collectQuerySelectionObservations(plan) {
|
|
822
|
+
return Object.freeze(plan.selections.flatMap((selection) => {
|
|
823
|
+
if (selection.kind !== "column") {
|
|
824
|
+
return [];
|
|
825
|
+
}
|
|
826
|
+
const column2 = getColumnName(selection.column);
|
|
827
|
+
return [Object.freeze({
|
|
828
|
+
column: column2,
|
|
829
|
+
resultKey: selection.alias ?? column2
|
|
830
|
+
})];
|
|
831
|
+
}));
|
|
832
|
+
}
|
|
833
|
+
function isPatchablePredicateObservation(predicate) {
|
|
834
|
+
if (predicate.kind === "comparison" && predicate.boolean !== "or") {
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
if (predicate.kind !== "group" || predicate.negated || predicate.boolean === "or") {
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
return predicate.predicates.every((child) => isPatchablePredicateObservation(child));
|
|
841
|
+
}
|
|
842
|
+
function isColumnSelection(selection) {
|
|
843
|
+
return selection.kind === "column";
|
|
844
|
+
}
|
|
845
|
+
function hasRequiredProjectionSelection(selections, column2) {
|
|
846
|
+
return selections.some((selection) => selection.column === column2 && selection.resultKey === column2);
|
|
847
|
+
}
|
|
848
|
+
function isExactPrimaryKeySingleResultProjection(plan) {
|
|
849
|
+
return plan.limit === 1 && typeof findExactPrimaryKeyValue(plan.predicates, getPrimaryKeyColumn(plan)) !== "undefined";
|
|
850
|
+
}
|
|
851
|
+
function isPatchableProjectionObservation(plan, selections, predicates, orderBy) {
|
|
852
|
+
if (plan.selections.length === 0) {
|
|
853
|
+
return true;
|
|
854
|
+
}
|
|
855
|
+
if (plan.selections.every((selection) => selection.kind === "aggregate")) {
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
if (!plan.selections.every((selection) => isColumnSelection(selection))) {
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
const needsProjectedPrimaryKey = !isExactPrimaryKeySingleResultProjection(plan);
|
|
862
|
+
const requiredColumns = /* @__PURE__ */ new Set([
|
|
863
|
+
...orderBy.map((order) => order.column)
|
|
864
|
+
]);
|
|
865
|
+
if (needsProjectedPrimaryKey) {
|
|
866
|
+
requiredColumns.add(getPrimaryKeyColumn(plan));
|
|
867
|
+
}
|
|
868
|
+
for (const column2 of requiredColumns) {
|
|
869
|
+
if (!hasRequiredProjectionSelection(selections, column2)) {
|
|
870
|
+
return false;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return true;
|
|
874
|
+
}
|
|
875
|
+
function isPatchableOffsetObservation(plan, orderBy) {
|
|
876
|
+
return typeof plan.offset === "undefined" || typeof plan.limit === "number" && plan.offset > 0 && orderBy.length > 0;
|
|
877
|
+
}
|
|
878
|
+
function findGroupedAggregateObservation(plan, averageStates, aggregateStates) {
|
|
879
|
+
if (plan.groupBy.length !== 1 || plan.selections.length !== 2) {
|
|
880
|
+
return void 0;
|
|
881
|
+
}
|
|
882
|
+
const groupColumn = getColumnName(plan.groupBy[0]);
|
|
883
|
+
const groupSelection = plan.selections.find((selection) => {
|
|
884
|
+
return selection.kind === "column" && getColumnName(selection.column) === groupColumn;
|
|
885
|
+
});
|
|
886
|
+
const aggregateSelection = plan.selections.find((selection) => {
|
|
887
|
+
return selection.kind === "aggregate" && (selection.aggregate === "count" && selection.column === "*" || selection.aggregate === "avg" && selection.column !== "*" || selection.aggregate === "sum" && selection.column !== "*" || selection.aggregate === "min" && selection.column !== "*" || selection.aggregate === "max" && selection.column !== "*");
|
|
888
|
+
});
|
|
889
|
+
if (!groupSelection || !aggregateSelection) {
|
|
890
|
+
return void 0;
|
|
891
|
+
}
|
|
892
|
+
const orderBy = collectQueryOrderObservations(plan);
|
|
893
|
+
if (orderBy.some((order) => order.column !== groupColumn)) {
|
|
894
|
+
return void 0;
|
|
895
|
+
}
|
|
896
|
+
const aggregateKind = aggregateSelection.aggregate === "count" ? "count" : aggregateSelection.aggregate;
|
|
897
|
+
const having = readGroupedCountHavingObservation(plan);
|
|
898
|
+
if (plan.having.length > 0 && !isSupportedGroupedCountHaving(plan)) {
|
|
899
|
+
return void 0;
|
|
900
|
+
}
|
|
901
|
+
const groupedAggregate = {
|
|
902
|
+
aggregateColumn: aggregateKind === "count" ? void 0 : getColumnName(aggregateSelection.column),
|
|
903
|
+
aggregateResultKey: aggregateSelection.alias,
|
|
904
|
+
...(aggregateKind === "count" || aggregateKind === "sum" || aggregateKind === "min" || aggregateKind === "max") && aggregateStates ? { aggregateStates: Object.freeze([...aggregateStates]) } : {},
|
|
905
|
+
...aggregateKind === "avg" && averageStates ? { averageStates: Object.freeze([...averageStates]) } : {},
|
|
906
|
+
groupColumn,
|
|
907
|
+
groupResultKey: groupSelection.alias ?? groupColumn,
|
|
908
|
+
having,
|
|
909
|
+
kind: aggregateKind
|
|
910
|
+
};
|
|
911
|
+
return Object.freeze(groupedAggregate);
|
|
912
|
+
}
|
|
913
|
+
function isSupportedGroupedCountHaving(plan) {
|
|
914
|
+
if (plan.having.length === 0) {
|
|
915
|
+
return true;
|
|
916
|
+
}
|
|
917
|
+
if (plan.groupBy.length === 0 || plan.having.length !== 1) {
|
|
918
|
+
return false;
|
|
919
|
+
}
|
|
920
|
+
const clause = plan.having[0];
|
|
921
|
+
return typeof clause !== "undefined" && clause.expression.replace(/\s+/g, "").toLowerCase() === "count(*)" && typeof clause.value === "number" && Number.isFinite(clause.value) && isGroupedCountHavingOperator(clause.operator);
|
|
922
|
+
}
|
|
923
|
+
function readGroupedCountHavingObservation(plan) {
|
|
924
|
+
if (!isSupportedGroupedCountHaving(plan) || hasOnlyRedundantGroupedCountHaving(plan)) {
|
|
925
|
+
return void 0;
|
|
926
|
+
}
|
|
927
|
+
const clause = plan.having[0];
|
|
928
|
+
if (!clause || !isGroupedCountHavingOperator(clause.operator) || typeof clause.value !== "number" || !Number.isFinite(clause.value)) {
|
|
929
|
+
return void 0;
|
|
930
|
+
}
|
|
931
|
+
return Object.freeze({
|
|
932
|
+
operator: clause.operator,
|
|
933
|
+
value: clause.value
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
function isGroupedCountHavingOperator(operator) {
|
|
937
|
+
return operator === "<" || operator === "<=" || operator === "=" || operator === ">" || operator === ">=";
|
|
938
|
+
}
|
|
939
|
+
function hasOnlyRedundantGroupedCountHaving(plan) {
|
|
940
|
+
if (plan.having.length === 0) {
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
if (plan.groupBy.length === 0 || plan.having.length !== 1) {
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
const clause = plan.having[0];
|
|
947
|
+
return typeof clause !== "undefined" && clause.expression.replace(/\s+/g, "").toLowerCase() === "count(*)" && clause.operator === ">=" && clause.value === 1;
|
|
948
|
+
}
|
|
949
|
+
function isPatchableGroupedAggregateObservation(plan) {
|
|
950
|
+
return supportsAutomaticQueryCacheInvalidation(plan) && Boolean(findGroupedAggregateObservation(plan)) && !plan.distinct && !plan.lockMode && !plan.source.alias && plan.joins.length === 0 && typeof plan.limit === "undefined" && typeof plan.offset === "undefined" && plan.unions.length === 0 && plan.orderBy.every((order) => order.kind === "column") && plan.predicates.every((predicate) => isPatchablePredicateObservation(predicate));
|
|
951
|
+
}
|
|
952
|
+
function isPatchableQueryObservation(plan) {
|
|
953
|
+
const predicates = collectQueryPredicateObservations(plan.predicates);
|
|
954
|
+
const orderBy = collectQueryOrderObservations(plan);
|
|
955
|
+
const selections = collectQuerySelectionObservations(plan);
|
|
956
|
+
return isPatchableGroupedAggregateObservation(plan) || supportsAutomaticQueryCacheInvalidation(plan) && !plan.distinct && !plan.lockMode && !plan.source.alias && plan.groupBy.length === 0 && plan.having.length === 0 && plan.joins.length === 0 && isPatchableOffsetObservation(plan, orderBy) && isPatchableProjectionObservation(plan, selections, predicates, orderBy) && plan.unions.length === 0 && plan.orderBy.every((order) => order.kind === "column") && plan.predicates.every((predicate) => isPatchablePredicateObservation(predicate));
|
|
957
|
+
}
|
|
958
|
+
function appendObservableQueryDependencies(plan, connectionName, dependencies, seen) {
|
|
959
|
+
if (seen.has(plan)) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
seen.add(plan);
|
|
963
|
+
dependencies.add(createTableCacheDependency(connectionName, plan.source.tableName));
|
|
964
|
+
for (const join of plan.joins) {
|
|
965
|
+
if (join.table) {
|
|
966
|
+
dependencies.add(createTableCacheDependency(connectionName, join.table));
|
|
967
|
+
}
|
|
968
|
+
if (join.subquery) {
|
|
969
|
+
appendObservableQueryDependencies(join.subquery, connectionName, dependencies, seen);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
for (const union of plan.unions) {
|
|
973
|
+
appendObservableQueryDependencies(union.query, connectionName, dependencies, seen);
|
|
974
|
+
}
|
|
975
|
+
for (const selection of plan.selections) {
|
|
976
|
+
if (selection.kind === "subquery") {
|
|
977
|
+
appendObservableQueryDependencies(selection.query, connectionName, dependencies, seen);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
for (const predicate of plan.predicates) {
|
|
981
|
+
appendObservablePredicateDependencies(predicate, connectionName, dependencies, seen);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function appendObservablePredicateDependencies(predicate, connectionName, dependencies, seen) {
|
|
985
|
+
if (predicate.kind === "group") {
|
|
986
|
+
for (const child of predicate.predicates) {
|
|
987
|
+
appendObservablePredicateDependencies(child, connectionName, dependencies, seen);
|
|
988
|
+
}
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
if (predicate.kind === "exists" || predicate.kind === "subquery") {
|
|
992
|
+
appendObservableQueryDependencies(predicate.subquery, connectionName, dependencies, seen);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
function hasObservationDependencyFallbackPredicate(predicate) {
|
|
996
|
+
if (predicate.kind === "group") {
|
|
997
|
+
return predicate.predicates.some((child) => hasObservationDependencyFallbackPredicate(child));
|
|
998
|
+
}
|
|
999
|
+
return predicate.kind === "exists" || predicate.kind === "subquery" || predicate.kind === "raw" || predicate.kind === "vector" || predicate.kind === "fulltext";
|
|
1000
|
+
}
|
|
1001
|
+
function hasObservationDependencyFallbackShape(plan) {
|
|
1002
|
+
return plan.joins.length > 0 || plan.unions.length > 0 || !isSupportedGroupedCountHaving(plan) || plan.selections.some((selection) => selection.kind === "raw" || selection.kind === "subquery") || plan.orderBy.some((order) => order.kind === "raw") || plan.predicates.some((predicate) => hasObservationDependencyFallbackPredicate(predicate));
|
|
1003
|
+
}
|
|
1004
|
+
function inferDatabaseQueryObservationDependencies(plan, connectionName) {
|
|
1005
|
+
if (!hasObservationDependencyFallbackShape(plan)) {
|
|
1006
|
+
return void 0;
|
|
1007
|
+
}
|
|
1008
|
+
const dependencies = /* @__PURE__ */ new Set();
|
|
1009
|
+
appendObservableQueryDependencies(plan, connectionName, dependencies, /* @__PURE__ */ new Set());
|
|
1010
|
+
return Object.freeze([...dependencies]);
|
|
1011
|
+
}
|
|
1012
|
+
function createDatabaseQueryObservationFromPlan(plan, connectionName, dependencies, result, patchable = isPatchableQueryObservation(plan), groupedAverageStates, groupedAggregateStates) {
|
|
1013
|
+
return Object.freeze({
|
|
1014
|
+
connectionName,
|
|
1015
|
+
belongsToHydrations: void 0,
|
|
1016
|
+
relatedHydrations: void 0,
|
|
1017
|
+
tableName: plan.source.tableName,
|
|
1018
|
+
dependencies: Object.freeze([...dependencies]),
|
|
1019
|
+
groupedAggregate: findGroupedAggregateObservation(plan, groupedAverageStates, groupedAggregateStates),
|
|
1020
|
+
limit: plan.limit,
|
|
1021
|
+
offset: plan.offset,
|
|
1022
|
+
orderBy: collectQueryOrderObservations(plan),
|
|
1023
|
+
patchable,
|
|
1024
|
+
pagination: void 0,
|
|
1025
|
+
predicates: collectQueryPredicateObservations(plan.predicates),
|
|
1026
|
+
result,
|
|
1027
|
+
selections: collectQuerySelectionObservations(plan)
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
function createDatabaseQueryObservation(plan, connectionName, dependencies, result, groupedAverageStates, groupedAggregateStates) {
|
|
1031
|
+
if (!supportsAutomaticQueryCacheInvalidation(plan)) {
|
|
1032
|
+
return void 0;
|
|
1033
|
+
}
|
|
1034
|
+
return createDatabaseQueryObservationFromPlan(
|
|
1035
|
+
plan,
|
|
1036
|
+
connectionName,
|
|
1037
|
+
dependencies,
|
|
1038
|
+
result,
|
|
1039
|
+
void 0,
|
|
1040
|
+
groupedAverageStates,
|
|
1041
|
+
groupedAggregateStates
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1044
|
+
function createDatabaseQueryFallbackObservation(plan, connectionName, dependencies, result) {
|
|
1045
|
+
if (dependencies.length === 0) {
|
|
1046
|
+
return void 0;
|
|
1047
|
+
}
|
|
1048
|
+
return createDatabaseQueryObservationFromPlan(plan, connectionName, dependencies, result, false);
|
|
1049
|
+
}
|
|
1050
|
+
function createDatabaseMutationEvent(kind, connectionName, tableName, predicates = [], values, rows, previousRows) {
|
|
1051
|
+
return Object.freeze({
|
|
1052
|
+
connectionName,
|
|
1053
|
+
tableName,
|
|
1054
|
+
kind,
|
|
1055
|
+
predicates: collectQueryPredicateObservations(predicates),
|
|
1056
|
+
previousRows: previousRows ? Object.freeze([...previousRows]) : void 0,
|
|
1057
|
+
rows: rows ? Object.freeze([...rows]) : void 0,
|
|
1058
|
+
values
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
260
1061
|
function supportsAutomaticQueryCacheInvalidation(plan) {
|
|
261
|
-
if (plan.joins.length > 0 || plan.unions.length > 0 || plan
|
|
1062
|
+
if (plan.joins.length > 0 || plan.unions.length > 0 || !isSupportedGroupedCountHaving(plan)) {
|
|
262
1063
|
return false;
|
|
263
1064
|
}
|
|
264
1065
|
if (plan.selections.some((selection) => selection.kind === "raw" || selection.kind === "subquery")) {
|
|
@@ -273,27 +1074,203 @@ function inferAutomaticQueryCacheDependencies(plan, connectionName) {
|
|
|
273
1074
|
if (!supportsAutomaticQueryCacheInvalidation(plan)) {
|
|
274
1075
|
return void 0;
|
|
275
1076
|
}
|
|
1077
|
+
if (!hasDisjunctivePredicate(plan.predicates)) {
|
|
1078
|
+
const primaryKeyColumn = getPrimaryKeyColumn(plan);
|
|
1079
|
+
const primaryKeyValue = findExactPrimaryKeyValue(plan.predicates, primaryKeyColumn);
|
|
1080
|
+
const primaryKeyDependency = createTableRowCacheDependency(
|
|
1081
|
+
connectionName,
|
|
1082
|
+
plan.source.tableName,
|
|
1083
|
+
primaryKeyColumn,
|
|
1084
|
+
primaryKeyValue
|
|
1085
|
+
);
|
|
1086
|
+
if (primaryKeyDependency) {
|
|
1087
|
+
return Object.freeze([
|
|
1088
|
+
primaryKeyDependency,
|
|
1089
|
+
createTableRowWildcardCacheDependency(connectionName, plan.source.tableName)
|
|
1090
|
+
]);
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
if (!hasDisjunctivePredicate(plan.predicates)) {
|
|
1094
|
+
const predicateDependencies = collectExactPredicateDependencies(
|
|
1095
|
+
plan.predicates,
|
|
1096
|
+
connectionName,
|
|
1097
|
+
plan.source.tableName
|
|
1098
|
+
);
|
|
1099
|
+
if (predicateDependencies.length > 0) {
|
|
1100
|
+
return Object.freeze([
|
|
1101
|
+
createTableCacheDependency(connectionName, plan.source.tableName),
|
|
1102
|
+
...predicateDependencies
|
|
1103
|
+
]);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
276
1106
|
return Object.freeze([
|
|
277
1107
|
createTableCacheDependency(connectionName, plan.source.tableName)
|
|
278
1108
|
]);
|
|
279
1109
|
}
|
|
1110
|
+
function inferAutomaticQueryCacheInvalidationDependencies(plan, connectionName, values = {}) {
|
|
1111
|
+
return inferAutomaticQueryCacheInvalidationPlan(plan, connectionName, values).dependencies;
|
|
1112
|
+
}
|
|
1113
|
+
function inferAutomaticQueryCacheInvalidationPlan(plan, connectionName, values = {}, includeMetadata = false) {
|
|
1114
|
+
const tableKey = createTableCacheDependency(connectionName, plan.source.tableName);
|
|
1115
|
+
const dependencies = [tableKey];
|
|
1116
|
+
if (hasDisjunctivePredicate(plan.predicates)) {
|
|
1117
|
+
dependencies.push(createTableRowWildcardCacheDependency(connectionName, plan.source.tableName));
|
|
1118
|
+
return Object.freeze({
|
|
1119
|
+
dependencies: Object.freeze(dependencies),
|
|
1120
|
+
metadata: includeMetadata ? createInvalidationMetadataFromParts(
|
|
1121
|
+
dependencies,
|
|
1122
|
+
Object.freeze([]),
|
|
1123
|
+
Object.freeze([]),
|
|
1124
|
+
Object.freeze([]),
|
|
1125
|
+
false
|
|
1126
|
+
) : void 0
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
const directDependencies = [];
|
|
1130
|
+
const exactPredicates = [];
|
|
1131
|
+
const predicates = [];
|
|
1132
|
+
const mutationDependency = createTableMutationCacheDependency(connectionName, plan.source.tableName);
|
|
1133
|
+
dependencies.push(mutationDependency);
|
|
1134
|
+
directDependencies.push(mutationDependency);
|
|
1135
|
+
const primaryKeyColumn = getPrimaryKeyColumn(plan);
|
|
1136
|
+
const primaryKeyValue = findExactPrimaryKeyValue(plan.predicates, primaryKeyColumn);
|
|
1137
|
+
const primaryKeyDependency = createTableRowCacheDependency(
|
|
1138
|
+
connectionName,
|
|
1139
|
+
plan.source.tableName,
|
|
1140
|
+
primaryKeyColumn,
|
|
1141
|
+
primaryKeyValue
|
|
1142
|
+
);
|
|
1143
|
+
const rowDependency = primaryKeyDependency ?? createTableRowWildcardCacheDependency(connectionName, plan.source.tableName);
|
|
1144
|
+
dependencies.push(rowDependency);
|
|
1145
|
+
directDependencies.push(rowDependency);
|
|
1146
|
+
if (includeMetadata) {
|
|
1147
|
+
const predicateEntries = /* @__PURE__ */ new Map();
|
|
1148
|
+
appendExactPredicateDependencyEntries(predicateEntries, plan.predicates, connectionName, plan.source.tableName);
|
|
1149
|
+
for (const entry of predicateEntries.values()) {
|
|
1150
|
+
dependencies.push(entry.dependency);
|
|
1151
|
+
directDependencies.push(entry.dependency);
|
|
1152
|
+
predicates.push(entry.metadata);
|
|
1153
|
+
}
|
|
1154
|
+
const exactPredicateEntries = /* @__PURE__ */ new Map();
|
|
1155
|
+
appendExactPredicateDependencyEntries(exactPredicateEntries, plan.predicates, connectionName, plan.source.tableName, true);
|
|
1156
|
+
for (const entry of exactPredicateEntries.values()) {
|
|
1157
|
+
dependencies.push(entry.dependency);
|
|
1158
|
+
directDependencies.push(entry.dependency);
|
|
1159
|
+
exactPredicates.push(entry.metadata);
|
|
1160
|
+
}
|
|
1161
|
+
const recordPredicateEntries = /* @__PURE__ */ new Map();
|
|
1162
|
+
appendRecordPredicateDependencyEntries(recordPredicateEntries, connectionName, plan.source.tableName, values);
|
|
1163
|
+
for (const entry of recordPredicateEntries.values()) {
|
|
1164
|
+
dependencies.push(entry.dependency);
|
|
1165
|
+
directDependencies.push(entry.dependency);
|
|
1166
|
+
predicates.push(entry.metadata);
|
|
1167
|
+
}
|
|
1168
|
+
const exactRecordPredicateEntries = /* @__PURE__ */ new Map();
|
|
1169
|
+
appendRecordPredicateDependencyEntries(exactRecordPredicateEntries, connectionName, plan.source.tableName, values, true);
|
|
1170
|
+
for (const entry of exactRecordPredicateEntries.values()) {
|
|
1171
|
+
dependencies.push(entry.dependency);
|
|
1172
|
+
directDependencies.push(entry.dependency);
|
|
1173
|
+
exactPredicates.push(entry.metadata);
|
|
1174
|
+
}
|
|
1175
|
+
return Object.freeze({
|
|
1176
|
+
dependencies: Object.freeze(dependencies),
|
|
1177
|
+
metadata: createInvalidationMetadataFromParts(
|
|
1178
|
+
directDependencies,
|
|
1179
|
+
exactPredicates,
|
|
1180
|
+
predicates,
|
|
1181
|
+
Object.freeze([tableKey]),
|
|
1182
|
+
true
|
|
1183
|
+
)
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
dependencies.push(...collectExactPredicateDependencies(plan.predicates, connectionName, plan.source.tableName));
|
|
1187
|
+
dependencies.push(...collectExactPredicateDependencies(plan.predicates, connectionName, plan.source.tableName, true));
|
|
1188
|
+
dependencies.push(...collectRecordPredicateDependencies(connectionName, plan.source.tableName, values));
|
|
1189
|
+
dependencies.push(...collectRecordPredicateDependencies(connectionName, plan.source.tableName, values, true));
|
|
1190
|
+
return Object.freeze({
|
|
1191
|
+
dependencies: Object.freeze(dependencies)
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
function inferAutomaticInsertCacheInvalidationDependencies(connectionName, tableName, rows, lastInsertId) {
|
|
1195
|
+
return inferAutomaticInsertCacheInvalidationPlan(connectionName, tableName, rows, lastInsertId).dependencies;
|
|
1196
|
+
}
|
|
1197
|
+
function inferAutomaticInsertCacheInvalidationPlan(connectionName, tableName, rows, lastInsertId, includeMetadata = false) {
|
|
1198
|
+
const tableKey = createTableCacheDependency(connectionName, tableName);
|
|
1199
|
+
const dependencies = /* @__PURE__ */ new Set([
|
|
1200
|
+
tableKey
|
|
1201
|
+
]);
|
|
1202
|
+
const directDependencies = /* @__PURE__ */ new Set();
|
|
1203
|
+
const exactPredicates = /* @__PURE__ */ new Map();
|
|
1204
|
+
const predicates = /* @__PURE__ */ new Map();
|
|
1205
|
+
for (const row of rows) {
|
|
1206
|
+
const dependency = createTableRowCacheDependency(connectionName, tableName, "id", row.id);
|
|
1207
|
+
if (dependency) {
|
|
1208
|
+
dependencies.add(dependency);
|
|
1209
|
+
directDependencies.add(dependency);
|
|
1210
|
+
}
|
|
1211
|
+
if (includeMetadata) {
|
|
1212
|
+
const rowPredicateEntries = /* @__PURE__ */ new Map();
|
|
1213
|
+
appendRecordPredicateDependencyEntries(rowPredicateEntries, connectionName, tableName, row);
|
|
1214
|
+
for (const entry of rowPredicateEntries.values()) {
|
|
1215
|
+
dependencies.add(entry.dependency);
|
|
1216
|
+
directDependencies.add(entry.dependency);
|
|
1217
|
+
predicates.set(entry.dependency, entry);
|
|
1218
|
+
}
|
|
1219
|
+
const rowExactPredicateEntries = /* @__PURE__ */ new Map();
|
|
1220
|
+
appendRecordPredicateDependencyEntries(rowExactPredicateEntries, connectionName, tableName, row, true);
|
|
1221
|
+
for (const entry of rowExactPredicateEntries.values()) {
|
|
1222
|
+
dependencies.add(entry.dependency);
|
|
1223
|
+
directDependencies.add(entry.dependency);
|
|
1224
|
+
exactPredicates.set(entry.dependency, entry);
|
|
1225
|
+
}
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
for (const dependency2 of collectRecordPredicateDependencies(connectionName, tableName, row)) {
|
|
1229
|
+
dependencies.add(dependency2);
|
|
1230
|
+
}
|
|
1231
|
+
for (const dependency2 of collectRecordPredicateDependencies(connectionName, tableName, row, true)) {
|
|
1232
|
+
dependencies.add(dependency2);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
const lastInsertDependency = createTableRowCacheDependency(connectionName, tableName, "id", lastInsertId);
|
|
1236
|
+
if (lastInsertDependency) {
|
|
1237
|
+
dependencies.add(lastInsertDependency);
|
|
1238
|
+
directDependencies.add(lastInsertDependency);
|
|
1239
|
+
}
|
|
1240
|
+
if (dependencies.size === 1) {
|
|
1241
|
+
const rowWildcardDependency = createTableRowWildcardCacheDependency(connectionName, tableName);
|
|
1242
|
+
dependencies.add(rowWildcardDependency);
|
|
1243
|
+
directDependencies.add(rowWildcardDependency);
|
|
1244
|
+
}
|
|
1245
|
+
return Object.freeze({
|
|
1246
|
+
dependencies: Object.freeze([...dependencies]),
|
|
1247
|
+
metadata: includeMetadata ? createInvalidationMetadataFromParts(
|
|
1248
|
+
[...directDependencies],
|
|
1249
|
+
[...exactPredicates.values()].map((entry) => entry.metadata),
|
|
1250
|
+
[...predicates.values()].map((entry) => entry.metadata),
|
|
1251
|
+
Object.freeze([tableKey]),
|
|
1252
|
+
false
|
|
1253
|
+
) : void 0
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
280
1256
|
function resolveQueryCacheDependencies(plan, connectionName, explicit) {
|
|
281
1257
|
if (explicit && explicit.length > 0) {
|
|
282
1258
|
return normalizeQueryCacheDependencies(connectionName, explicit);
|
|
283
1259
|
}
|
|
284
1260
|
return inferAutomaticQueryCacheDependencies(plan, connectionName);
|
|
285
1261
|
}
|
|
286
|
-
async function invalidateQueryCacheDependencies(connection, dependencies) {
|
|
1262
|
+
async function invalidateQueryCacheDependencies(connection, dependencies, mutations = [], plan) {
|
|
287
1263
|
if (dependencies.length === 0) {
|
|
288
1264
|
return;
|
|
289
1265
|
}
|
|
290
1266
|
const invalidate = async () => {
|
|
291
1267
|
const bridge = getDatabaseQueryCacheBridge();
|
|
292
1268
|
await bridge?.invalidateDependencies(dependencies);
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
1269
|
+
if (hasDatabaseDependencyInvalidationListeners()) {
|
|
1270
|
+
await notifyDatabaseDependencyInvalidationListeners(
|
|
1271
|
+
createDatabaseDependencyInvalidationEvent(connection.getConnectionName(), dependencies, mutations, plan?.metadata)
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
297
1274
|
};
|
|
298
1275
|
if (connection.getScope().kind === "root") {
|
|
299
1276
|
await invalidate();
|
|
@@ -302,17 +1279,33 @@ async function invalidateQueryCacheDependencies(connection, dependencies) {
|
|
|
302
1279
|
connection.afterCommit(invalidate);
|
|
303
1280
|
}
|
|
304
1281
|
var queryCacheInternals = {
|
|
305
|
-
collectDatabaseQueryDependencies,
|
|
1282
|
+
collectDatabaseQueryDependencies: collectDatabaseQueryDependenciesInternal,
|
|
306
1283
|
configureDatabaseQueryCacheBridge,
|
|
1284
|
+
createDatabaseMutationEvent,
|
|
1285
|
+
createDatabaseQueryObservation,
|
|
307
1286
|
createDeterministicQueryCacheKey,
|
|
1287
|
+
createTablePredicateCacheDependency,
|
|
308
1288
|
createTableCacheDependency,
|
|
1289
|
+
createTableRowCacheDependency,
|
|
1290
|
+
createTableRowWildcardCacheDependency,
|
|
309
1291
|
getQueryCacheBridgeState,
|
|
1292
|
+
hasActiveDatabaseDependencyCollector,
|
|
1293
|
+
hasDatabaseDependencyInvalidationListeners,
|
|
1294
|
+
inferAutomaticInsertCacheInvalidationDependencies,
|
|
1295
|
+
inferAutomaticInsertCacheInvalidationPlan,
|
|
310
1296
|
inferAutomaticQueryCacheDependencies,
|
|
1297
|
+
inferAutomaticQueryCacheInvalidationDependencies,
|
|
1298
|
+
inferAutomaticQueryCacheInvalidationPlan,
|
|
311
1299
|
normalizeQueryCacheConfig,
|
|
312
1300
|
normalizeQueryCacheDependencies,
|
|
313
1301
|
notifyDatabaseDependencyInvalidationListeners,
|
|
1302
|
+
disableDatabaseQueryObservationPatching,
|
|
1303
|
+
rebindDatabaseQueryObservationResult,
|
|
1304
|
+
rebindDatabaseQueryObservationScalar,
|
|
1305
|
+
rebindDatabaseQueryObservationScalarList,
|
|
314
1306
|
onDatabaseDependencyInvalidated,
|
|
315
1307
|
recordDatabaseQueryDependencies,
|
|
1308
|
+
recordDatabaseQueryObservation,
|
|
316
1309
|
resolveQueryCacheDependencies,
|
|
317
1310
|
resolveQueryCacheKey,
|
|
318
1311
|
resetDatabaseDependencyInvalidationListeners,
|
|
@@ -688,34 +1681,47 @@ function createInsertQueryPlan(source, values, options = {}) {
|
|
|
688
1681
|
kind: "insert",
|
|
689
1682
|
source,
|
|
690
1683
|
ignoreConflicts: options.ignoreConflicts ?? false,
|
|
1684
|
+
returning: options.returning === true,
|
|
691
1685
|
values: Object.freeze(values.map((value) => Object.freeze({ ...value })))
|
|
692
1686
|
});
|
|
693
1687
|
}
|
|
694
|
-
function createUpsertQueryPlan(source, values, uniqueBy, updateColumns) {
|
|
1688
|
+
function createUpsertQueryPlan(source, values, uniqueBy, updateColumns, options = {}) {
|
|
695
1689
|
return Object.freeze({
|
|
696
1690
|
kind: "upsert",
|
|
697
1691
|
source,
|
|
1692
|
+
returning: options.returning === true,
|
|
698
1693
|
values: Object.freeze(values.map((value) => Object.freeze({ ...value }))),
|
|
699
1694
|
uniqueBy: Object.freeze([...uniqueBy]),
|
|
700
1695
|
updateColumns: Object.freeze([...updateColumns])
|
|
701
1696
|
});
|
|
702
1697
|
}
|
|
703
|
-
function createUpdateQueryPlan(source, predicates, values) {
|
|
1698
|
+
function createUpdateQueryPlan(source, predicates, values, options = {}) {
|
|
704
1699
|
return Object.freeze({
|
|
705
1700
|
kind: "update",
|
|
706
1701
|
source,
|
|
707
1702
|
predicates: Object.freeze([...predicates]),
|
|
1703
|
+
returning: options.returning === true,
|
|
708
1704
|
values: Object.freeze({ ...values })
|
|
709
1705
|
});
|
|
710
1706
|
}
|
|
711
|
-
function createDeleteQueryPlan(source, predicates) {
|
|
1707
|
+
function createDeleteQueryPlan(source, predicates, options = {}) {
|
|
712
1708
|
return Object.freeze({
|
|
713
1709
|
kind: "delete",
|
|
714
1710
|
source,
|
|
715
|
-
predicates: Object.freeze([...predicates])
|
|
1711
|
+
predicates: Object.freeze([...predicates]),
|
|
1712
|
+
returning: options.returning === true
|
|
716
1713
|
});
|
|
717
1714
|
}
|
|
718
1715
|
|
|
1716
|
+
// src/query/aggregateValueCounts.ts
|
|
1717
|
+
function createAggregateValueCounts(values) {
|
|
1718
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1719
|
+
for (const value of values) {
|
|
1720
|
+
counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
1721
|
+
}
|
|
1722
|
+
return Object.freeze([...counts.entries()].sort(([left], [right]) => left - right).map(([value, count]) => Object.freeze({ count, value })));
|
|
1723
|
+
}
|
|
1724
|
+
|
|
719
1725
|
// src/query/validator.ts
|
|
720
1726
|
var IDENTIFIER_PATTERN = /^[A-Z_]\w*$/i;
|
|
721
1727
|
var OPERATORS = /* @__PURE__ */ new Set([
|
|
@@ -1352,8 +2358,9 @@ var SQLQueryCompiler = class {
|
|
|
1352
2358
|
return `${this.quoteIdentifier(column2)} = ${this.compileUpdateValue(column2, plan.values[column2], bindings)}`;
|
|
1353
2359
|
}).join(", ");
|
|
1354
2360
|
const whereClause = this.compilePredicates(plan.predicates, bindings);
|
|
2361
|
+
const returningClause = this.compileReturningClause(plan.returning === true);
|
|
1355
2362
|
return this.withMetadata({
|
|
1356
|
-
sql: `UPDATE ${this.quoteIdentifier(plan.source.tableName)} SET ${assignments}${whereClause}`,
|
|
2363
|
+
sql: `UPDATE ${this.quoteIdentifier(plan.source.tableName)} SET ${assignments}${whereClause}${returningClause}`,
|
|
1357
2364
|
bindings,
|
|
1358
2365
|
source: `query:update:${plan.source.tableName}`
|
|
1359
2366
|
}, this.createWriteMetadata("update", plan.source.tableName, this.calculatePlanComplexity(plan)));
|
|
@@ -1361,8 +2368,9 @@ var SQLQueryCompiler = class {
|
|
|
1361
2368
|
compileDelete(plan) {
|
|
1362
2369
|
const bindings = [];
|
|
1363
2370
|
const whereClause = this.compilePredicates(plan.predicates, bindings);
|
|
2371
|
+
const returningClause = this.compileReturningClause(plan.returning === true);
|
|
1364
2372
|
return this.withMetadata({
|
|
1365
|
-
sql: `DELETE FROM ${this.quoteIdentifier(plan.source.tableName)}${whereClause}`,
|
|
2373
|
+
sql: `DELETE FROM ${this.quoteIdentifier(plan.source.tableName)}${whereClause}${returningClause}`,
|
|
1366
2374
|
bindings,
|
|
1367
2375
|
source: `query:delete:${plan.source.tableName}`
|
|
1368
2376
|
}, this.createWriteMetadata("delete", plan.source.tableName, this.calculatePlanComplexity(plan)));
|
|
@@ -1639,15 +2647,19 @@ var SQLQueryCompiler = class {
|
|
|
1639
2647
|
return "INSERT INTO";
|
|
1640
2648
|
}
|
|
1641
2649
|
compileInsertSuffix(_plan) {
|
|
1642
|
-
return "";
|
|
2650
|
+
return _plan.returning === true ? " RETURNING *" : "";
|
|
1643
2651
|
}
|
|
1644
2652
|
compileUpsertSuffix(plan, _insertColumns) {
|
|
1645
2653
|
const conflictColumns = plan.uniqueBy.map((column2) => this.quoteIdentifier(column2)).join(", ");
|
|
2654
|
+
const returning = plan.returning === true ? " RETURNING *" : "";
|
|
1646
2655
|
if (plan.updateColumns.length === 0) {
|
|
1647
|
-
return ` ON CONFLICT (${conflictColumns}) DO NOTHING`;
|
|
2656
|
+
return ` ON CONFLICT (${conflictColumns}) DO NOTHING${returning}`;
|
|
1648
2657
|
}
|
|
1649
2658
|
const updates = plan.updateColumns.map((column2) => `${this.quoteIdentifier(column2)} = EXCLUDED.${this.quoteIdentifier(column2)}`).join(", ");
|
|
1650
|
-
return ` ON CONFLICT (${conflictColumns}) DO UPDATE SET ${updates}`;
|
|
2659
|
+
return ` ON CONFLICT (${conflictColumns}) DO UPDATE SET ${updates}${returning}`;
|
|
2660
|
+
}
|
|
2661
|
+
compileReturningClause(returning) {
|
|
2662
|
+
return returning ? " RETURNING *" : "";
|
|
1651
2663
|
}
|
|
1652
2664
|
compileHavingExpression(expression) {
|
|
1653
2665
|
const aggregateMatch = expression.match(/^(count|sum|avg|min|max)\((\*|[A-Z_]\w*)\)$/i);
|
|
@@ -1829,12 +2841,18 @@ var PostgresQueryCompiler = class extends SQLQueryCompiler {
|
|
|
1829
2841
|
return lockMode === "update" ? "FOR UPDATE" : "FOR SHARE";
|
|
1830
2842
|
}
|
|
1831
2843
|
compileInsertSuffix(plan) {
|
|
2844
|
+
if (plan.returning === true) {
|
|
2845
|
+
return `${plan.ignoreConflicts ? " ON CONFLICT DO NOTHING" : ""} RETURNING *`;
|
|
2846
|
+
}
|
|
1832
2847
|
const primaryKey = Object.values(plan.source.table?.columns ?? {}).find((column2) => column2.primaryKey)?.name;
|
|
1833
2848
|
const returning = primaryKey ? ` RETURNING ${this.quoteIdentifier(primaryKey)}` : "";
|
|
1834
2849
|
return `${plan.ignoreConflicts ? " ON CONFLICT DO NOTHING" : ""}${returning}`;
|
|
1835
2850
|
}
|
|
1836
2851
|
compileUpsertSuffix(plan, insertColumns) {
|
|
1837
2852
|
const suffix = super.compileUpsertSuffix(plan, insertColumns);
|
|
2853
|
+
if (plan.returning === true) {
|
|
2854
|
+
return suffix;
|
|
2855
|
+
}
|
|
1838
2856
|
const primaryKey = Object.values(plan.source.table?.columns ?? {}).find((column2) => column2.primaryKey)?.name;
|
|
1839
2857
|
return primaryKey ? `${suffix} RETURNING ${this.quoteIdentifier(primaryKey)}` : suffix;
|
|
1840
2858
|
}
|
|
@@ -2112,6 +3130,15 @@ function normalizeDialectWriteValue(dialect, column2, value) {
|
|
|
2112
3130
|
}
|
|
2113
3131
|
|
|
2114
3132
|
// src/query/TableQueryBuilder.ts
|
|
3133
|
+
var GROUPED_AVERAGE_COUNT_KEY = "__holo_grouped_average_count";
|
|
3134
|
+
var GROUPED_AVERAGE_ROW_COUNT_KEY = "__holo_grouped_average_row_count";
|
|
3135
|
+
var GROUPED_AVERAGE_SUM_KEY = "__holo_grouped_average_sum";
|
|
3136
|
+
var GROUPED_AVERAGE_GROUP_KEY = "__holo_grouped_average_group";
|
|
3137
|
+
var GROUPED_AGGREGATE_VALUE_KEY = "__holo_grouped_aggregate_state_value";
|
|
3138
|
+
var GROUPED_AGGREGATE_ROW_COUNT_KEY = "__holo_grouped_aggregate_state_row_count";
|
|
3139
|
+
var GROUPED_AGGREGATE_GROUP_KEY = "__holo_grouped_aggregate_state_group";
|
|
3140
|
+
var GROUPED_AGGREGATE_VALUE_COUNT_VALUE_KEY = "__holo_grouped_aggregate_state_count_value";
|
|
3141
|
+
var GROUPED_AGGREGATE_VALUE_COUNT_KEY = "__holo_grouped_aggregate_state_value_count";
|
|
2115
3142
|
function normalizeAtomicQueryCacheTtl(ttl) {
|
|
2116
3143
|
if (ttl instanceof Date) {
|
|
2117
3144
|
const expiresAt = ttl.getTime();
|
|
@@ -2809,14 +3836,23 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2809
3836
|
async get() {
|
|
2810
3837
|
const statement = this.toSQL();
|
|
2811
3838
|
const cacheConfig = this.queryCacheConfig;
|
|
2812
|
-
const
|
|
3839
|
+
const activeDependencyCollector = hasActiveDatabaseDependencyCollector();
|
|
3840
|
+
const dependencies = this.plan.lockMode || !cacheConfig && !activeDependencyCollector ? void 0 : resolveQueryCacheDependencies(
|
|
2813
3841
|
this.plan,
|
|
2814
3842
|
this.connection.getConnectionName(),
|
|
2815
3843
|
cacheConfig?.invalidate
|
|
2816
3844
|
);
|
|
2817
|
-
|
|
3845
|
+
const observationDependencies = activeDependencyCollector && !this.plan.lockMode ? dependencies ?? inferDatabaseQueryObservationDependencies(this.plan, this.connection.getConnectionName()) : dependencies;
|
|
3846
|
+
const createObservation = dependencies ? createDatabaseQueryObservation : createDatabaseQueryFallbackObservation;
|
|
3847
|
+
recordDatabaseQueryDependencies(observationDependencies);
|
|
2818
3848
|
if (!cacheConfig || this.plan.lockMode) {
|
|
2819
3849
|
const result = await this.connection.queryCompiled(statement);
|
|
3850
|
+
await this.recordCollectedQueryObservation(
|
|
3851
|
+
activeDependencyCollector,
|
|
3852
|
+
observationDependencies,
|
|
3853
|
+
createObservation,
|
|
3854
|
+
result.rows
|
|
3855
|
+
);
|
|
2820
3856
|
return result.rows;
|
|
2821
3857
|
}
|
|
2822
3858
|
const bridge = getDatabaseQueryCacheBridge();
|
|
@@ -2825,7 +3861,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2825
3861
|
}
|
|
2826
3862
|
const cacheKey = resolveQueryCacheKey(statement, this.connection.getConnectionName(), cacheConfig);
|
|
2827
3863
|
if (cacheConfig.flexible) {
|
|
2828
|
-
|
|
3864
|
+
const rows2 = await bridge.flexible(
|
|
2829
3865
|
cacheKey,
|
|
2830
3866
|
cacheConfig.flexible,
|
|
2831
3867
|
async () => {
|
|
@@ -2837,11 +3873,18 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2837
3873
|
dependencies
|
|
2838
3874
|
}
|
|
2839
3875
|
);
|
|
3876
|
+
await this.recordCollectedQueryObservation(
|
|
3877
|
+
activeDependencyCollector,
|
|
3878
|
+
observationDependencies,
|
|
3879
|
+
createObservation,
|
|
3880
|
+
rows2
|
|
3881
|
+
);
|
|
3882
|
+
return rows2;
|
|
2840
3883
|
}
|
|
2841
3884
|
if (typeof cacheConfig.ttl === "undefined") {
|
|
2842
3885
|
throw new ConfigurationError('[@holo-js/db] Query cache config requires "ttl" or "flexible".');
|
|
2843
3886
|
}
|
|
2844
|
-
|
|
3887
|
+
const rows = await bridge.flexible(
|
|
2845
3888
|
cacheKey,
|
|
2846
3889
|
normalizeAtomicQueryCacheTtl(cacheConfig.ttl),
|
|
2847
3890
|
async () => {
|
|
@@ -2853,17 +3896,227 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2853
3896
|
dependencies
|
|
2854
3897
|
}
|
|
2855
3898
|
);
|
|
3899
|
+
await this.recordCollectedQueryObservation(
|
|
3900
|
+
activeDependencyCollector,
|
|
3901
|
+
observationDependencies,
|
|
3902
|
+
createObservation,
|
|
3903
|
+
rows
|
|
3904
|
+
);
|
|
3905
|
+
return rows;
|
|
3906
|
+
}
|
|
3907
|
+
async recordCollectedQueryObservation(activeDependencyCollector, observationDependencies, createObservation, rows) {
|
|
3908
|
+
if (!activeDependencyCollector || !observationDependencies) {
|
|
3909
|
+
return;
|
|
3910
|
+
}
|
|
3911
|
+
const observation = createObservation(
|
|
3912
|
+
this.plan,
|
|
3913
|
+
this.connection.getConnectionName(),
|
|
3914
|
+
observationDependencies,
|
|
3915
|
+
rows
|
|
3916
|
+
);
|
|
3917
|
+
const groupedAggregate = observation?.groupedAggregate;
|
|
3918
|
+
if (!observation?.patchable || !groupedAggregate) {
|
|
3919
|
+
recordDatabaseQueryObservation(observation);
|
|
3920
|
+
return;
|
|
3921
|
+
}
|
|
3922
|
+
const averageStates = groupedAggregate.kind === "avg" && groupedAggregate.aggregateColumn ? await this.readGroupedAverageStates(groupedAggregate) : void 0;
|
|
3923
|
+
const aggregateStates = (groupedAggregate.kind === "count" || groupedAggregate.kind === "sum" || groupedAggregate.kind === "min" || groupedAggregate.kind === "max") && groupedAggregate.having ? await this.readGroupedAggregateStates(groupedAggregate) : void 0;
|
|
3924
|
+
recordDatabaseQueryObservation(averageStates || aggregateStates ? createObservation(
|
|
3925
|
+
this.plan,
|
|
3926
|
+
this.connection.getConnectionName(),
|
|
3927
|
+
observationDependencies,
|
|
3928
|
+
rows,
|
|
3929
|
+
averageStates,
|
|
3930
|
+
aggregateStates
|
|
3931
|
+
) : observation);
|
|
3932
|
+
}
|
|
3933
|
+
async readGroupedAverageStates(groupedAggregate) {
|
|
3934
|
+
const aggregateColumn = groupedAggregate.aggregateColumn;
|
|
3935
|
+
if (!aggregateColumn) {
|
|
3936
|
+
return void 0;
|
|
3937
|
+
}
|
|
3938
|
+
const selections = [
|
|
3939
|
+
Object.freeze({
|
|
3940
|
+
alias: GROUPED_AVERAGE_GROUP_KEY,
|
|
3941
|
+
column: groupedAggregate.groupColumn,
|
|
3942
|
+
kind: "column"
|
|
3943
|
+
}),
|
|
3944
|
+
this.createAggregateSelection("count", GROUPED_AVERAGE_COUNT_KEY, aggregateColumn),
|
|
3945
|
+
this.createAggregateSelection("count", GROUPED_AVERAGE_ROW_COUNT_KEY, "*"),
|
|
3946
|
+
this.createAggregateSelection("sum", GROUPED_AVERAGE_SUM_KEY, aggregateColumn)
|
|
3947
|
+
];
|
|
3948
|
+
const metadataPlan = Object.freeze({
|
|
3949
|
+
...this.plan,
|
|
3950
|
+
having: Object.freeze([]),
|
|
3951
|
+
selections: Object.freeze(selections)
|
|
3952
|
+
});
|
|
3953
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(metadataPlan));
|
|
3954
|
+
const states = [];
|
|
3955
|
+
for (const row of result.rows) {
|
|
3956
|
+
const count = this.normalizeAggregateMetadataNumber(row[GROUPED_AVERAGE_COUNT_KEY]);
|
|
3957
|
+
const rowCount = this.normalizeAggregateMetadataNumber(row[GROUPED_AVERAGE_ROW_COUNT_KEY]);
|
|
3958
|
+
const sum = this.normalizeAggregateMetadataNumber(row[GROUPED_AVERAGE_SUM_KEY] ?? 0);
|
|
3959
|
+
if (typeof count === "undefined" || typeof rowCount === "undefined" || typeof sum === "undefined" || count < 0 || rowCount < 0) {
|
|
3960
|
+
return void 0;
|
|
3961
|
+
}
|
|
3962
|
+
states.push(Object.freeze({
|
|
3963
|
+
count,
|
|
3964
|
+
groupValue: row[GROUPED_AVERAGE_GROUP_KEY],
|
|
3965
|
+
rowCount,
|
|
3966
|
+
sum
|
|
3967
|
+
}));
|
|
3968
|
+
}
|
|
3969
|
+
return Object.freeze(states);
|
|
3970
|
+
}
|
|
3971
|
+
async readGroupedAggregateStates(groupedAggregate) {
|
|
3972
|
+
const aggregateSelection = this.createGroupedAggregateStateValueSelection(groupedAggregate);
|
|
3973
|
+
if (!aggregateSelection) {
|
|
3974
|
+
return void 0;
|
|
3975
|
+
}
|
|
3976
|
+
const valueCounts = await this.readGroupedAggregateValueCounts(groupedAggregate);
|
|
3977
|
+
const selections = [
|
|
3978
|
+
Object.freeze({
|
|
3979
|
+
alias: GROUPED_AGGREGATE_GROUP_KEY,
|
|
3980
|
+
column: groupedAggregate.groupColumn,
|
|
3981
|
+
kind: "column"
|
|
3982
|
+
}),
|
|
3983
|
+
aggregateSelection,
|
|
3984
|
+
this.createAggregateSelection("count", GROUPED_AGGREGATE_ROW_COUNT_KEY, "*")
|
|
3985
|
+
];
|
|
3986
|
+
const metadataPlan = Object.freeze({
|
|
3987
|
+
...this.plan,
|
|
3988
|
+
having: Object.freeze([]),
|
|
3989
|
+
selections: Object.freeze(selections)
|
|
3990
|
+
});
|
|
3991
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(metadataPlan));
|
|
3992
|
+
const states = [];
|
|
3993
|
+
for (const row of result.rows) {
|
|
3994
|
+
const aggregateValue = this.normalizeGroupedAggregateStateValue(
|
|
3995
|
+
groupedAggregate,
|
|
3996
|
+
row[GROUPED_AGGREGATE_VALUE_KEY]
|
|
3997
|
+
);
|
|
3998
|
+
const rowCount = this.normalizeAggregateMetadataNumber(row[GROUPED_AGGREGATE_ROW_COUNT_KEY]);
|
|
3999
|
+
if (typeof aggregateValue === "undefined" || typeof rowCount === "undefined" || rowCount < 0) {
|
|
4000
|
+
return void 0;
|
|
4001
|
+
}
|
|
4002
|
+
states.push(Object.freeze({
|
|
4003
|
+
aggregateValue,
|
|
4004
|
+
groupValue: row[GROUPED_AGGREGATE_GROUP_KEY],
|
|
4005
|
+
rowCount,
|
|
4006
|
+
...valueCounts ? { valueCounts: this.readGroupedAggregateValueCountsForGroup(valueCounts, row[GROUPED_AGGREGATE_GROUP_KEY]) } : {}
|
|
4007
|
+
}));
|
|
4008
|
+
}
|
|
4009
|
+
return Object.freeze(states);
|
|
4010
|
+
}
|
|
4011
|
+
async readGroupedAggregateValueCounts(groupedAggregate) {
|
|
4012
|
+
if (groupedAggregate.kind !== "min" && groupedAggregate.kind !== "max") {
|
|
4013
|
+
return void 0;
|
|
4014
|
+
}
|
|
4015
|
+
const aggregateColumn = groupedAggregate.aggregateColumn;
|
|
4016
|
+
if (!aggregateColumn) {
|
|
4017
|
+
return void 0;
|
|
4018
|
+
}
|
|
4019
|
+
const metadataPlan = Object.freeze({
|
|
4020
|
+
...this.plan,
|
|
4021
|
+
groupBy: Object.freeze([groupedAggregate.groupColumn, aggregateColumn]),
|
|
4022
|
+
having: Object.freeze([]),
|
|
4023
|
+
selections: Object.freeze([
|
|
4024
|
+
Object.freeze({
|
|
4025
|
+
alias: GROUPED_AGGREGATE_GROUP_KEY,
|
|
4026
|
+
column: groupedAggregate.groupColumn,
|
|
4027
|
+
kind: "column"
|
|
4028
|
+
}),
|
|
4029
|
+
Object.freeze({
|
|
4030
|
+
alias: GROUPED_AGGREGATE_VALUE_COUNT_VALUE_KEY,
|
|
4031
|
+
column: aggregateColumn,
|
|
4032
|
+
kind: "column"
|
|
4033
|
+
}),
|
|
4034
|
+
this.createAggregateSelection("count", GROUPED_AGGREGATE_VALUE_COUNT_KEY, "*")
|
|
4035
|
+
])
|
|
4036
|
+
});
|
|
4037
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(metadataPlan));
|
|
4038
|
+
const groups = [];
|
|
4039
|
+
for (const row of result.rows) {
|
|
4040
|
+
const groupValue = row[GROUPED_AGGREGATE_GROUP_KEY];
|
|
4041
|
+
const value = this.normalizeGroupedAggregateStateValue(
|
|
4042
|
+
groupedAggregate,
|
|
4043
|
+
row[GROUPED_AGGREGATE_VALUE_COUNT_VALUE_KEY]
|
|
4044
|
+
);
|
|
4045
|
+
const count = this.normalizeAggregateMetadataNumber(row[GROUPED_AGGREGATE_VALUE_COUNT_KEY]);
|
|
4046
|
+
if (typeof value === "undefined" || typeof count === "undefined" || count <= 0) {
|
|
4047
|
+
return void 0;
|
|
4048
|
+
}
|
|
4049
|
+
this.pushGroupedAggregateValueCount(groups, groupValue, Object.freeze({ count, value }));
|
|
4050
|
+
}
|
|
4051
|
+
return Object.freeze(groups.map((group) => Object.freeze({
|
|
4052
|
+
groupValue: group.groupValue,
|
|
4053
|
+
valueCounts: [...group.valueCounts].sort((left, right) => left.value - right.value)
|
|
4054
|
+
})));
|
|
4055
|
+
}
|
|
4056
|
+
pushGroupedAggregateValueCount(groups, groupValue, valueCount) {
|
|
4057
|
+
const group = groups.find((candidate) => Object.is(candidate.groupValue, groupValue));
|
|
4058
|
+
if (group) {
|
|
4059
|
+
group.valueCounts.push(valueCount);
|
|
4060
|
+
return;
|
|
4061
|
+
}
|
|
4062
|
+
groups.push({
|
|
4063
|
+
groupValue,
|
|
4064
|
+
valueCounts: [valueCount]
|
|
4065
|
+
});
|
|
4066
|
+
}
|
|
4067
|
+
readGroupedAggregateValueCountsForGroup(groups, groupValue) {
|
|
4068
|
+
return groups.find((group) => Object.is(group.groupValue, groupValue))?.valueCounts ?? Object.freeze([]);
|
|
4069
|
+
}
|
|
4070
|
+
createGroupedAggregateStateValueSelection(groupedAggregate) {
|
|
4071
|
+
if (groupedAggregate.kind === "count") {
|
|
4072
|
+
return this.createAggregateSelection("count", GROUPED_AGGREGATE_VALUE_KEY, "*");
|
|
4073
|
+
}
|
|
4074
|
+
if ((groupedAggregate.kind === "sum" || groupedAggregate.kind === "min" || groupedAggregate.kind === "max") && groupedAggregate.aggregateColumn) {
|
|
4075
|
+
return this.createAggregateSelection(
|
|
4076
|
+
groupedAggregate.kind,
|
|
4077
|
+
GROUPED_AGGREGATE_VALUE_KEY,
|
|
4078
|
+
groupedAggregate.aggregateColumn
|
|
4079
|
+
);
|
|
4080
|
+
}
|
|
4081
|
+
return void 0;
|
|
4082
|
+
}
|
|
4083
|
+
normalizeGroupedAggregateStateValue(groupedAggregate, value) {
|
|
4084
|
+
if ((groupedAggregate.kind === "min" || groupedAggregate.kind === "max") && value === null) {
|
|
4085
|
+
return void 0;
|
|
4086
|
+
}
|
|
4087
|
+
return this.normalizeAggregateMetadataNumber(value);
|
|
4088
|
+
}
|
|
4089
|
+
normalizeAggregateMetadataNumber(value) {
|
|
4090
|
+
if (value === null) {
|
|
4091
|
+
return 0;
|
|
4092
|
+
}
|
|
4093
|
+
if (typeof value === "number") {
|
|
4094
|
+
return Number.isFinite(value) ? value : void 0;
|
|
4095
|
+
}
|
|
4096
|
+
if (typeof value === "bigint") {
|
|
4097
|
+
const numericValue = Number(value);
|
|
4098
|
+
return Number.isSafeInteger(numericValue) ? numericValue : void 0;
|
|
4099
|
+
}
|
|
4100
|
+
if (typeof value === "string" && value.trim()) {
|
|
4101
|
+
const numericValue = Number(value);
|
|
4102
|
+
return Number.isFinite(numericValue) ? numericValue : void 0;
|
|
4103
|
+
}
|
|
4104
|
+
return void 0;
|
|
2856
4105
|
}
|
|
2857
4106
|
async first() {
|
|
2858
4107
|
const rows = await this.limit(1).get();
|
|
2859
|
-
|
|
4108
|
+
const row = rows[0];
|
|
4109
|
+
rebindDatabaseQueryObservationResult(rows, row);
|
|
4110
|
+
return row;
|
|
2860
4111
|
}
|
|
2861
4112
|
async sole() {
|
|
2862
4113
|
const rows = await this.limit(2).get();
|
|
2863
4114
|
if (rows.length !== 1) {
|
|
2864
4115
|
throw new CompilerError(`Query expected exactly one row but found ${rows.length}.`);
|
|
2865
4116
|
}
|
|
2866
|
-
|
|
4117
|
+
const row = rows[0];
|
|
4118
|
+
rebindDatabaseQueryObservationResult(rows, row);
|
|
4119
|
+
return row;
|
|
2867
4120
|
}
|
|
2868
4121
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
2869
4122
|
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
@@ -2875,7 +4128,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2875
4128
|
const data = rows.slice(offset, offset + perPage);
|
|
2876
4129
|
const from = data.length === 0 ? null : offset + 1;
|
|
2877
4130
|
const to = data.length === 0 ? null : offset + data.length;
|
|
2878
|
-
|
|
4131
|
+
const result = createPaginator(data, {
|
|
2879
4132
|
total,
|
|
2880
4133
|
perPage,
|
|
2881
4134
|
pageName,
|
|
@@ -2885,6 +4138,14 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2885
4138
|
to,
|
|
2886
4139
|
hasMorePages: offset + data.length < total
|
|
2887
4140
|
});
|
|
4141
|
+
rebindDatabaseQueryObservationPagination(rows, result.data, result.meta, Object.freeze({
|
|
4142
|
+
currentPage: page,
|
|
4143
|
+
kind: "standard",
|
|
4144
|
+
pageName,
|
|
4145
|
+
perPage,
|
|
4146
|
+
total
|
|
4147
|
+
}), offset);
|
|
4148
|
+
return result;
|
|
2888
4149
|
}
|
|
2889
4150
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
2890
4151
|
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
@@ -2897,7 +4158,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2897
4158
|
const data = hasMorePages ? pageRows.slice(0, perPage) : pageRows;
|
|
2898
4159
|
const from = data.length === 0 ? null : offset + 1;
|
|
2899
4160
|
const to = data.length === 0 ? null : offset + data.length;
|
|
2900
|
-
|
|
4161
|
+
const result = createSimplePaginator(data, {
|
|
2901
4162
|
perPage,
|
|
2902
4163
|
pageName,
|
|
2903
4164
|
currentPage: page,
|
|
@@ -2905,6 +4166,15 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2905
4166
|
to,
|
|
2906
4167
|
hasMorePages
|
|
2907
4168
|
});
|
|
4169
|
+
rebindDatabaseQueryObservationPagination(rows, result.data, result.meta, Object.freeze({
|
|
4170
|
+
currentPage: page,
|
|
4171
|
+
hasMorePages,
|
|
4172
|
+
kind: "simple",
|
|
4173
|
+
pageName,
|
|
4174
|
+
perPage,
|
|
4175
|
+
rowCount: rows.length
|
|
4176
|
+
}), offset);
|
|
4177
|
+
return result;
|
|
2908
4178
|
}
|
|
2909
4179
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
2910
4180
|
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
@@ -2922,12 +4192,32 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2922
4192
|
const hasMorePages = pageRows.length > perPage;
|
|
2923
4193
|
const data = hasMorePages ? pageRows.slice(0, perPage) : pageRows;
|
|
2924
4194
|
const lastRow = data.at(-1);
|
|
2925
|
-
|
|
4195
|
+
const result = createCursorPaginator(data, {
|
|
2926
4196
|
perPage,
|
|
2927
4197
|
cursorName,
|
|
2928
4198
|
nextCursor: hasMorePages && lastRow ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastRow, order.column))) : null,
|
|
2929
4199
|
prevCursor: cursor
|
|
2930
4200
|
});
|
|
4201
|
+
if (cursor === null) {
|
|
4202
|
+
rebindDatabaseQueryObservationCursorPagination(rows, result.data, {
|
|
4203
|
+
cursorName: result.cursorName,
|
|
4204
|
+
nextCursor: result.nextCursor,
|
|
4205
|
+
perPage: result.perPage,
|
|
4206
|
+
prevCursor: result.prevCursor
|
|
4207
|
+
}, Object.freeze({
|
|
4208
|
+
cursorName: result.cursorName,
|
|
4209
|
+
hasMorePages,
|
|
4210
|
+
kind: "cursor",
|
|
4211
|
+
nextCursor: result.nextCursor,
|
|
4212
|
+
perPage: result.perPage,
|
|
4213
|
+
prevCursor: result.prevCursor,
|
|
4214
|
+
rows: pageRows,
|
|
4215
|
+
rowCount: rows.length
|
|
4216
|
+
}));
|
|
4217
|
+
} else {
|
|
4218
|
+
rebindDatabaseQueryObservationResult(rows, data);
|
|
4219
|
+
}
|
|
4220
|
+
return result;
|
|
2931
4221
|
}
|
|
2932
4222
|
async chunk(size, callback) {
|
|
2933
4223
|
assertPositiveInteger(size, "Chunk size", (message) => new SecurityError(message));
|
|
@@ -2991,35 +4281,66 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2991
4281
|
}
|
|
2992
4282
|
}
|
|
2993
4283
|
async count() {
|
|
2994
|
-
|
|
4284
|
+
const rows = await this.get();
|
|
4285
|
+
const result = rows.length;
|
|
4286
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4287
|
+
rebindDatabaseQueryObservationAggregate(rows, result, Object.freeze({ kind: "count" }));
|
|
4288
|
+
}
|
|
4289
|
+
return result;
|
|
2995
4290
|
}
|
|
2996
4291
|
async exists() {
|
|
2997
|
-
|
|
4292
|
+
const count = await this.count();
|
|
4293
|
+
const result = count > 0;
|
|
4294
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4295
|
+
rebindDatabaseQueryObservationAggregate(count, result, Object.freeze({
|
|
4296
|
+
count,
|
|
4297
|
+
kind: "count",
|
|
4298
|
+
output: "boolean"
|
|
4299
|
+
}));
|
|
4300
|
+
}
|
|
4301
|
+
return result;
|
|
2998
4302
|
}
|
|
2999
4303
|
async doesntExist() {
|
|
3000
|
-
|
|
4304
|
+
const count = await this.count();
|
|
4305
|
+
const result = count === 0;
|
|
4306
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4307
|
+
rebindDatabaseQueryObservationAggregate(count, result, Object.freeze({
|
|
4308
|
+
count,
|
|
4309
|
+
kind: "count",
|
|
4310
|
+
output: "inverseBoolean"
|
|
4311
|
+
}));
|
|
4312
|
+
}
|
|
4313
|
+
return result;
|
|
3001
4314
|
}
|
|
3002
4315
|
async pluck(column2) {
|
|
3003
4316
|
const rows = await this.get();
|
|
3004
|
-
|
|
4317
|
+
const result = rows.map((row) => row[column2]);
|
|
4318
|
+
rebindDatabaseQueryObservationScalarList(rows, result, column2);
|
|
4319
|
+
return result;
|
|
3005
4320
|
}
|
|
3006
4321
|
async value(column2) {
|
|
3007
4322
|
const row = await this.first();
|
|
3008
|
-
|
|
4323
|
+
const result = row?.[column2];
|
|
4324
|
+
rebindDatabaseQueryObservationScalar(row, result, column2);
|
|
4325
|
+
return result;
|
|
3009
4326
|
}
|
|
3010
4327
|
async valueOrFail(column2) {
|
|
3011
4328
|
const row = await this.first();
|
|
3012
4329
|
if (!row || typeof row[column2] === "undefined") {
|
|
3013
4330
|
throw new CompilerError(`Query returned no value for column "${column2}".`);
|
|
3014
4331
|
}
|
|
3015
|
-
|
|
4332
|
+
const result = row[column2];
|
|
4333
|
+
rebindDatabaseQueryObservationScalar(row, result, column2);
|
|
4334
|
+
return result;
|
|
3016
4335
|
}
|
|
3017
4336
|
async soleValue(column2) {
|
|
3018
4337
|
const row = await this.sole();
|
|
3019
4338
|
if (typeof row[column2] === "undefined") {
|
|
3020
4339
|
throw new CompilerError(`Query returned no value for column "${column2}".`);
|
|
3021
4340
|
}
|
|
3022
|
-
|
|
4341
|
+
const result = row[column2];
|
|
4342
|
+
rebindDatabaseQueryObservationScalar(row, result, column2);
|
|
4343
|
+
return result;
|
|
3023
4344
|
}
|
|
3024
4345
|
async sum(column2) {
|
|
3025
4346
|
return this.aggregateNumeric(column2, "sum");
|
|
@@ -3027,45 +4348,95 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3027
4348
|
async avg(column2) {
|
|
3028
4349
|
const rows = await this.get();
|
|
3029
4350
|
if (rows.length === 0) {
|
|
4351
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4352
|
+
rebindDatabaseQueryObservationAggregate(rows, null, Object.freeze({ column: column2, count: 0, kind: "avg", sum: 0 }));
|
|
4353
|
+
}
|
|
3030
4354
|
return null;
|
|
3031
4355
|
}
|
|
3032
4356
|
const values = this.extractNumericValues(rows, column2, "avg");
|
|
3033
|
-
|
|
4357
|
+
const sum = values.reduce((total, value) => total + value, 0);
|
|
4358
|
+
const result = sum / values.length;
|
|
4359
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4360
|
+
rebindDatabaseQueryObservationAggregate(rows, result, Object.freeze({ column: column2, count: values.length, kind: "avg", sum }));
|
|
4361
|
+
}
|
|
4362
|
+
return result;
|
|
3034
4363
|
}
|
|
3035
4364
|
async min(column2) {
|
|
3036
4365
|
const rows = await this.get();
|
|
3037
4366
|
if (rows.length === 0) {
|
|
4367
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4368
|
+
rebindDatabaseQueryObservationAggregate(rows, null, Object.freeze({ column: column2, kind: "min" }));
|
|
4369
|
+
}
|
|
3038
4370
|
return null;
|
|
3039
4371
|
}
|
|
3040
4372
|
const values = this.extractNumericValues(rows, column2, "min");
|
|
3041
|
-
|
|
4373
|
+
const result = Math.min(...values);
|
|
4374
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4375
|
+
rebindDatabaseQueryObservationAggregate(rows, result, Object.freeze({
|
|
4376
|
+
column: column2,
|
|
4377
|
+
currentValueCount: values.filter((value) => value === result).length,
|
|
4378
|
+
kind: "min",
|
|
4379
|
+
valueCounts: createAggregateValueCounts(values)
|
|
4380
|
+
}));
|
|
4381
|
+
}
|
|
4382
|
+
return result;
|
|
3042
4383
|
}
|
|
3043
4384
|
async max(column2) {
|
|
3044
4385
|
const rows = await this.get();
|
|
3045
4386
|
if (rows.length === 0) {
|
|
4387
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4388
|
+
rebindDatabaseQueryObservationAggregate(rows, null, Object.freeze({ column: column2, kind: "max" }));
|
|
4389
|
+
}
|
|
3046
4390
|
return null;
|
|
3047
4391
|
}
|
|
3048
4392
|
const values = this.extractNumericValues(rows, column2, "max");
|
|
3049
|
-
|
|
4393
|
+
const result = Math.max(...values);
|
|
4394
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4395
|
+
rebindDatabaseQueryObservationAggregate(rows, result, Object.freeze({
|
|
4396
|
+
column: column2,
|
|
4397
|
+
currentValueCount: values.filter((value) => value === result).length,
|
|
4398
|
+
kind: "max",
|
|
4399
|
+
valueCounts: createAggregateValueCounts(values)
|
|
4400
|
+
}));
|
|
4401
|
+
}
|
|
4402
|
+
return result;
|
|
3050
4403
|
}
|
|
3051
4404
|
async find(value, column2 = "id") {
|
|
3052
4405
|
return this.where(column2, value).limit(1).first();
|
|
3053
4406
|
}
|
|
3054
4407
|
async insert(values) {
|
|
3055
4408
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
3056
|
-
const
|
|
4409
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4410
|
+
const useReturningRows = this.shouldUseReturningMutationRows(hasInvalidationListeners);
|
|
4411
|
+
const result = useReturningRows ? await this.queryReturningMutationRows(
|
|
4412
|
+
createInsertQueryPlan(this.source, rows, { returning: true }),
|
|
4413
|
+
true
|
|
4414
|
+
) : await this.connection.executeCompiled(this.getCompiler().compile(
|
|
3057
4415
|
createInsertQueryPlan(this.source, rows)
|
|
3058
4416
|
));
|
|
3059
|
-
await this.
|
|
3060
|
-
return
|
|
4417
|
+
await this.invalidateInsertQueries("insert", result.rows?.rows ?? rows, result.lastInsertId);
|
|
4418
|
+
return {
|
|
4419
|
+
affectedRows: result.affectedRows,
|
|
4420
|
+
lastInsertId: result.lastInsertId
|
|
4421
|
+
};
|
|
3061
4422
|
}
|
|
3062
4423
|
async insertOrIgnore(values) {
|
|
3063
4424
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
3064
|
-
const
|
|
4425
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4426
|
+
const useReturningRows = this.shouldUseReturningMutationRows(hasInvalidationListeners);
|
|
4427
|
+
const result = useReturningRows ? await this.queryReturningMutationRows(
|
|
4428
|
+
createInsertQueryPlan(this.source, rows, { ignoreConflicts: true, returning: true }),
|
|
4429
|
+
true
|
|
4430
|
+
) : await this.connection.executeCompiled(this.getCompiler().compile(
|
|
3065
4431
|
createInsertQueryPlan(this.source, rows, { ignoreConflicts: true })
|
|
3066
4432
|
));
|
|
3067
|
-
|
|
3068
|
-
|
|
4433
|
+
if (!useReturningRows || result.affectedRows !== 0) {
|
|
4434
|
+
await this.invalidateInsertQueries("insert", result.rows?.rows ?? rows, result.lastInsertId);
|
|
4435
|
+
}
|
|
4436
|
+
return {
|
|
4437
|
+
affectedRows: result.affectedRows,
|
|
4438
|
+
lastInsertId: result.lastInsertId
|
|
4439
|
+
};
|
|
3069
4440
|
}
|
|
3070
4441
|
async insertGetId(values) {
|
|
3071
4442
|
const result = await this.insert(values);
|
|
@@ -3073,61 +4444,273 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3073
4444
|
}
|
|
3074
4445
|
async upsert(values, uniqueBy, updateColumns = []) {
|
|
3075
4446
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
3076
|
-
const
|
|
4447
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4448
|
+
const previousRows = hasInvalidationListeners ? await this.captureUpsertPreviousRows(rows, uniqueBy) : void 0;
|
|
4449
|
+
const useReturningRows = this.shouldUseReturningMutationRows(hasInvalidationListeners);
|
|
4450
|
+
const result = useReturningRows ? await this.queryReturningMutationRows(
|
|
4451
|
+
createUpsertQueryPlan(this.source, rows, uniqueBy, updateColumns, { returning: true }),
|
|
4452
|
+
true
|
|
4453
|
+
) : await this.connection.executeCompiled(this.getCompiler().compile(
|
|
3077
4454
|
createUpsertQueryPlan(this.source, rows, uniqueBy, updateColumns)
|
|
3078
4455
|
));
|
|
3079
|
-
|
|
3080
|
-
|
|
4456
|
+
if (!useReturningRows || result.affectedRows !== 0) {
|
|
4457
|
+
await this.invalidateInsertQueries("upsert", result.rows?.rows ?? rows, result.lastInsertId, previousRows);
|
|
4458
|
+
}
|
|
4459
|
+
return {
|
|
4460
|
+
affectedRows: result.affectedRows,
|
|
4461
|
+
lastInsertId: result.lastInsertId
|
|
4462
|
+
};
|
|
3081
4463
|
}
|
|
3082
4464
|
async increment(column2, amount = 1, extraValues = {}) {
|
|
3083
4465
|
return this.adjustNumericColumn(column2, amount, extraValues);
|
|
3084
4466
|
}
|
|
3085
|
-
async decrement(column2, amount = 1, extraValues = {}) {
|
|
3086
|
-
return this.adjustNumericColumn(column2, -amount, extraValues);
|
|
4467
|
+
async decrement(column2, amount = 1, extraValues = {}) {
|
|
4468
|
+
return this.adjustNumericColumn(column2, -amount, extraValues);
|
|
4469
|
+
}
|
|
4470
|
+
async update(values) {
|
|
4471
|
+
const normalizedValues = this.normalizeUpdateValues(values);
|
|
4472
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4473
|
+
const useReturningRows = this.shouldUseReturningMutationRows(hasInvalidationListeners);
|
|
4474
|
+
const mutationRows = hasInvalidationListeners && !useReturningRows ? await this.captureUpdatedMutationRows(normalizedValues) : void 0;
|
|
4475
|
+
const result = useReturningRows ? await this.queryReturningMutationRows(
|
|
4476
|
+
createUpdateQueryPlan(this.source, this.plan.predicates, normalizedValues, { returning: true })
|
|
4477
|
+
) : await this.connection.executeCompiled(this.getCompiler().compile(
|
|
4478
|
+
createUpdateQueryPlan(this.source, this.plan.predicates, normalizedValues)
|
|
4479
|
+
));
|
|
4480
|
+
const capturedRows = result.rows ?? mutationRows;
|
|
4481
|
+
if (result.affectedRows !== 0) {
|
|
4482
|
+
await this.invalidateMutationQueries(normalizedValues, capturedRows);
|
|
4483
|
+
}
|
|
4484
|
+
return {
|
|
4485
|
+
affectedRows: result.affectedRows,
|
|
4486
|
+
lastInsertId: result.lastInsertId
|
|
4487
|
+
};
|
|
4488
|
+
}
|
|
4489
|
+
async updateJson(columnPath, value) {
|
|
4490
|
+
return this.update({ [columnPath]: value });
|
|
4491
|
+
}
|
|
4492
|
+
async delete() {
|
|
4493
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4494
|
+
const useReturningRows = this.shouldUseReturningMutationRows(hasInvalidationListeners);
|
|
4495
|
+
const mutationRows = hasInvalidationListeners && !useReturningRows ? await this.captureDeletedMutationRows() : void 0;
|
|
4496
|
+
const result = useReturningRows ? await this.queryReturningMutationRows(
|
|
4497
|
+
createDeleteQueryPlan(this.source, this.plan.predicates, { returning: true })
|
|
4498
|
+
) : await this.connection.executeCompiled(this.getCompiler().compile(
|
|
4499
|
+
createDeleteQueryPlan(this.source, this.plan.predicates)
|
|
4500
|
+
));
|
|
4501
|
+
const capturedRows = result.rows ?? mutationRows;
|
|
4502
|
+
if (result.affectedRows !== 0) {
|
|
4503
|
+
await this.invalidateMutationQueries({}, capturedRows);
|
|
4504
|
+
}
|
|
4505
|
+
return {
|
|
4506
|
+
affectedRows: result.affectedRows,
|
|
4507
|
+
lastInsertId: result.lastInsertId
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4510
|
+
async unsafeQuery(statement) {
|
|
4511
|
+
return this.connection.unsafeQuery({
|
|
4512
|
+
...statement,
|
|
4513
|
+
unsafe: true,
|
|
4514
|
+
source: `table:${this.source.tableName}`
|
|
4515
|
+
});
|
|
4516
|
+
}
|
|
4517
|
+
async unsafeExecute(statement) {
|
|
4518
|
+
return this.connection.unsafeExecute({
|
|
4519
|
+
...statement,
|
|
4520
|
+
unsafe: true,
|
|
4521
|
+
source: `table:${this.source.tableName}`
|
|
4522
|
+
});
|
|
4523
|
+
}
|
|
4524
|
+
clone(plan) {
|
|
4525
|
+
const table = this.source.table ?? this.source.tableName;
|
|
4526
|
+
return new _TableQueryBuilder(table, this.connection, plan, this.queryCacheConfig);
|
|
4527
|
+
}
|
|
4528
|
+
async captureUpdatedMutationRows(values) {
|
|
4529
|
+
const plan = Object.freeze({
|
|
4530
|
+
...createSelectQueryPlan(this.source),
|
|
4531
|
+
predicates: this.plan.predicates
|
|
4532
|
+
});
|
|
4533
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(plan));
|
|
4534
|
+
if (result.rows.length === 0) {
|
|
4535
|
+
return void 0;
|
|
4536
|
+
}
|
|
4537
|
+
const previousRows = Object.freeze(result.rows.map((row) => Object.freeze({ ...row })));
|
|
4538
|
+
const rows = Object.freeze(previousRows.map((row) => Object.freeze(
|
|
4539
|
+
this.applyCapturedUpdateValues(row, values)
|
|
4540
|
+
)));
|
|
4541
|
+
return Object.freeze({
|
|
4542
|
+
previousRows,
|
|
4543
|
+
rows
|
|
4544
|
+
});
|
|
4545
|
+
}
|
|
4546
|
+
async captureDeletedMutationRows() {
|
|
4547
|
+
const plan = Object.freeze({
|
|
4548
|
+
...createSelectQueryPlan(this.source),
|
|
4549
|
+
predicates: this.plan.predicates
|
|
4550
|
+
});
|
|
4551
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(plan));
|
|
4552
|
+
if (result.rows.length === 0) {
|
|
4553
|
+
return void 0;
|
|
4554
|
+
}
|
|
4555
|
+
return Object.freeze({
|
|
4556
|
+
rows: Object.freeze(result.rows.map((row) => Object.freeze({ ...row })))
|
|
4557
|
+
});
|
|
4558
|
+
}
|
|
4559
|
+
applyCapturedUpdateValues(row, values) {
|
|
4560
|
+
const nextRow = { ...row };
|
|
4561
|
+
for (const [column2, value] of Object.entries(values)) {
|
|
4562
|
+
nextRow[column2] = this.applyCapturedUpdateValue(row[column2], value);
|
|
4563
|
+
}
|
|
4564
|
+
return nextRow;
|
|
4565
|
+
}
|
|
4566
|
+
applyCapturedUpdateValue(currentValue, value) {
|
|
4567
|
+
if (!Array.isArray(value) || !value.every((item) => this.isCapturedJsonUpdateOperation(item))) {
|
|
4568
|
+
return value;
|
|
4569
|
+
}
|
|
4570
|
+
let nextValue = currentValue;
|
|
4571
|
+
for (const operation of value) {
|
|
4572
|
+
nextValue = this.applyCapturedJsonUpdateOperation(nextValue, operation);
|
|
4573
|
+
}
|
|
4574
|
+
return nextValue;
|
|
4575
|
+
}
|
|
4576
|
+
applyCapturedJsonUpdateOperation(currentValue, operation) {
|
|
4577
|
+
return this.applyCapturedJsonPathValue(currentValue, operation.path, operation.value);
|
|
4578
|
+
}
|
|
4579
|
+
isCapturedJsonUpdateOperation(value) {
|
|
4580
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && value.kind === "json-set" && Array.isArray(value.path);
|
|
4581
|
+
}
|
|
4582
|
+
applyCapturedJsonPathValue(currentValue, path, value) {
|
|
4583
|
+
const segment = path[0];
|
|
4584
|
+
if (typeof segment === "undefined") {
|
|
4585
|
+
return value;
|
|
4586
|
+
}
|
|
4587
|
+
const currentRecord = this.isJsonRecord(currentValue) ? currentValue : {};
|
|
4588
|
+
const childValue = this.applyCapturedJsonPathValue(currentRecord[segment], path.slice(1), value);
|
|
4589
|
+
return Object.freeze({
|
|
4590
|
+
...currentRecord,
|
|
4591
|
+
[segment]: childValue
|
|
4592
|
+
});
|
|
4593
|
+
}
|
|
4594
|
+
isJsonRecord(value) {
|
|
4595
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3087
4596
|
}
|
|
3088
|
-
async
|
|
3089
|
-
const
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
if (result.affectedRows !== 0) {
|
|
3093
|
-
await this.invalidateSourceTableQueries();
|
|
4597
|
+
async captureUpsertPreviousRows(rows, uniqueBy) {
|
|
4598
|
+
const firstUniqueColumn = uniqueBy[0];
|
|
4599
|
+
if (!firstUniqueColumn || rows.length === 0 || !rows.every((row) => this.hasUniqueByValues(row, uniqueBy))) {
|
|
4600
|
+
return void 0;
|
|
3094
4601
|
}
|
|
3095
|
-
|
|
4602
|
+
const firstColumnValues = Object.freeze([...new Set(rows.map((row) => row[firstUniqueColumn]))]);
|
|
4603
|
+
const query = new _TableQueryBuilder(this.source.tableName, this.connection).whereIn(firstUniqueColumn, firstColumnValues);
|
|
4604
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(query.getPlan()));
|
|
4605
|
+
const previousRows = [];
|
|
4606
|
+
const usedResultIndexes = /* @__PURE__ */ new Set();
|
|
4607
|
+
for (const row of rows) {
|
|
4608
|
+
const resultIndex = result.rows.findIndex((candidate, index) => {
|
|
4609
|
+
return !usedResultIndexes.has(index) && this.rowsMatchUniqueBy(candidate, row, uniqueBy);
|
|
4610
|
+
});
|
|
4611
|
+
if (resultIndex < 0) {
|
|
4612
|
+
continue;
|
|
4613
|
+
}
|
|
4614
|
+
const previousRow = result.rows[resultIndex];
|
|
4615
|
+
if (!previousRow) {
|
|
4616
|
+
continue;
|
|
4617
|
+
}
|
|
4618
|
+
usedResultIndexes.add(resultIndex);
|
|
4619
|
+
previousRows.push(Object.freeze({ ...previousRow }));
|
|
4620
|
+
}
|
|
4621
|
+
return Object.freeze(previousRows);
|
|
3096
4622
|
}
|
|
3097
|
-
|
|
3098
|
-
return
|
|
4623
|
+
hasUniqueByValues(row, uniqueBy) {
|
|
4624
|
+
return uniqueBy.every((column2) => Object.prototype.hasOwnProperty.call(row, column2));
|
|
3099
4625
|
}
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
createDeleteQueryPlan(this.source, this.plan.predicates)
|
|
3103
|
-
));
|
|
3104
|
-
if (result.affectedRows !== 0) {
|
|
3105
|
-
await this.invalidateSourceTableQueries();
|
|
3106
|
-
}
|
|
3107
|
-
return result;
|
|
4626
|
+
rowsMatchUniqueBy(left, right, uniqueBy) {
|
|
4627
|
+
return uniqueBy.every((column2) => left[column2] === right[column2]);
|
|
3108
4628
|
}
|
|
3109
|
-
|
|
3110
|
-
return this.connection.
|
|
3111
|
-
...statement,
|
|
3112
|
-
unsafe: true,
|
|
3113
|
-
source: `table:${this.source.tableName}`
|
|
3114
|
-
});
|
|
4629
|
+
shouldUseReturningMutationRows(hasInvalidationListeners) {
|
|
4630
|
+
return hasInvalidationListeners && this.connection.getCapabilities().returning;
|
|
3115
4631
|
}
|
|
3116
|
-
async
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
4632
|
+
async queryReturningMutationRows(plan, includeLastInsertId = false) {
|
|
4633
|
+
const result = await this.connection.queryCompiled(this.getCompiler().compile(plan));
|
|
4634
|
+
const rows = this.freezeMutationRows(result.rows);
|
|
4635
|
+
return {
|
|
4636
|
+
affectedRows: result.rowCount,
|
|
4637
|
+
lastInsertId: includeLastInsertId ? this.readReturnedLastInsertId(rows) : void 0,
|
|
4638
|
+
rows: rows.length === 0 ? void 0 : Object.freeze({
|
|
4639
|
+
rows
|
|
4640
|
+
})
|
|
4641
|
+
};
|
|
3122
4642
|
}
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
return new _TableQueryBuilder(table, this.connection, plan, this.queryCacheConfig);
|
|
4643
|
+
freezeMutationRows(rows) {
|
|
4644
|
+
return Object.freeze(rows.map((row) => Object.freeze({ ...row })));
|
|
3126
4645
|
}
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
4646
|
+
readReturnedLastInsertId(rows) {
|
|
4647
|
+
if (rows.length !== 1) {
|
|
4648
|
+
return void 0;
|
|
4649
|
+
}
|
|
4650
|
+
const value = rows[0]?.[this.resolvePrimaryKeyColumn()];
|
|
4651
|
+
return typeof value === "number" || typeof value === "string" ? value : void 0;
|
|
4652
|
+
}
|
|
4653
|
+
async invalidateInsertQueries(kind, rows, lastInsertId, previousRows) {
|
|
4654
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4655
|
+
if (!getDatabaseQueryCacheBridge() && !hasInvalidationListeners) {
|
|
4656
|
+
return;
|
|
4657
|
+
}
|
|
4658
|
+
const mutations = hasInvalidationListeners ? [
|
|
4659
|
+
createDatabaseMutationEvent(
|
|
4660
|
+
kind,
|
|
4661
|
+
this.connection.getConnectionName(),
|
|
4662
|
+
this.source.tableName,
|
|
4663
|
+
[],
|
|
4664
|
+
void 0,
|
|
4665
|
+
rows.length === 1 && typeof lastInsertId !== "undefined" && !Object.prototype.hasOwnProperty.call(rows[0], "id") ? Object.freeze([Object.freeze({
|
|
4666
|
+
...rows[0],
|
|
4667
|
+
id: lastInsertId
|
|
4668
|
+
})]) : rows,
|
|
4669
|
+
previousRows
|
|
4670
|
+
)
|
|
4671
|
+
] : [];
|
|
4672
|
+
const invalidation = inferAutomaticInsertCacheInvalidationPlan(
|
|
4673
|
+
this.connection.getConnectionName(),
|
|
4674
|
+
this.source.tableName,
|
|
4675
|
+
rows,
|
|
4676
|
+
lastInsertId,
|
|
4677
|
+
hasInvalidationListeners
|
|
4678
|
+
);
|
|
4679
|
+
await invalidateQueryCacheDependencies(
|
|
4680
|
+
this.connection,
|
|
4681
|
+
invalidation.dependencies,
|
|
4682
|
+
mutations,
|
|
4683
|
+
invalidation
|
|
4684
|
+
);
|
|
4685
|
+
}
|
|
4686
|
+
async invalidateMutationQueries(values = {}, capturedRows) {
|
|
4687
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4688
|
+
if (!getDatabaseQueryCacheBridge() && !hasInvalidationListeners) {
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4691
|
+
const hasValues = Object.keys(values).length > 0;
|
|
4692
|
+
const invalidation = inferAutomaticQueryCacheInvalidationPlan(
|
|
4693
|
+
this.plan,
|
|
4694
|
+
this.connection.getConnectionName(),
|
|
4695
|
+
values,
|
|
4696
|
+
hasInvalidationListeners
|
|
4697
|
+
);
|
|
4698
|
+
await invalidateQueryCacheDependencies(
|
|
4699
|
+
this.connection,
|
|
4700
|
+
invalidation.dependencies,
|
|
4701
|
+
hasInvalidationListeners ? [
|
|
4702
|
+
createDatabaseMutationEvent(
|
|
4703
|
+
hasValues ? "update" : "delete",
|
|
4704
|
+
this.connection.getConnectionName(),
|
|
4705
|
+
this.source.tableName,
|
|
4706
|
+
this.plan.predicates,
|
|
4707
|
+
hasValues ? values : void 0,
|
|
4708
|
+
capturedRows?.rows,
|
|
4709
|
+
capturedRows?.previousRows
|
|
4710
|
+
)
|
|
4711
|
+
] : [],
|
|
4712
|
+
invalidation
|
|
4713
|
+
);
|
|
3131
4714
|
}
|
|
3132
4715
|
getCompiler() {
|
|
3133
4716
|
const dialect = this.connection.getDialect();
|
|
@@ -3270,10 +4853,11 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3270
4853
|
}
|
|
3271
4854
|
async aggregateNumeric(column2, kind) {
|
|
3272
4855
|
const rows = await this.get();
|
|
3273
|
-
|
|
3274
|
-
|
|
4856
|
+
const result = rows.length === 0 ? 0 : this.extractNumericValues(rows, column2, kind).reduce((sum, value) => sum + value, 0);
|
|
4857
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4858
|
+
rebindDatabaseQueryObservationAggregate(rows, result, Object.freeze({ column: column2, kind }));
|
|
3275
4859
|
}
|
|
3276
|
-
return
|
|
4860
|
+
return result;
|
|
3277
4861
|
}
|
|
3278
4862
|
extractNumericValues(rows, column2, kind) {
|
|
3279
4863
|
return rows.map((row) => {
|
|
@@ -8089,6 +9673,13 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8089
9673
|
}
|
|
8090
9674
|
async get() {
|
|
8091
9675
|
const rows = await this.tableQuery.get();
|
|
9676
|
+
const collection = await this.hydrateRows(rows);
|
|
9677
|
+
this.recordCollectionRelationObservations(collection);
|
|
9678
|
+
this.recordCollectionRelationAggregateObservations(collection);
|
|
9679
|
+
this.rebindRowsToSerializedResult(rows, collection);
|
|
9680
|
+
return collection;
|
|
9681
|
+
}
|
|
9682
|
+
async hydrateRows(rows) {
|
|
8092
9683
|
const hasQueryCasts = Object.keys(this.queryCasts).length > 0;
|
|
8093
9684
|
let entities = await Promise.all(
|
|
8094
9685
|
rows.map((row) => hasQueryCasts ? this.repository.retrieveWithCasts(row, this.queryCasts) : this.repository.retrieve(row))
|
|
@@ -8100,39 +9691,76 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8100
9691
|
return this.repository.createCollection(entities);
|
|
8101
9692
|
}
|
|
8102
9693
|
async getJson() {
|
|
8103
|
-
|
|
9694
|
+
const rows = await this.tableQuery.get();
|
|
9695
|
+
const collection = await this.hydrateRows(rows);
|
|
9696
|
+
this.recordCollectionRelationObservations(collection);
|
|
9697
|
+
this.recordCollectionRelationAggregateObservations(collection);
|
|
9698
|
+
const data = collection.toJSON();
|
|
9699
|
+
this.rebindRowsToSerializedResult(rows, data);
|
|
9700
|
+
return data;
|
|
8104
9701
|
}
|
|
8105
9702
|
async first() {
|
|
8106
|
-
const
|
|
9703
|
+
const query = this.limit(1);
|
|
9704
|
+
const { collection, rows } = await query.getRowsAndEntities();
|
|
9705
|
+
const entity = collection[0];
|
|
9706
|
+
query.recordSingleRelationObservations(entity);
|
|
9707
|
+
query.recordSingleRelationAggregateObservations(entity);
|
|
9708
|
+
query.rebindRowsToSerializedResult(rows, entity);
|
|
8107
9709
|
return entity;
|
|
8108
9710
|
}
|
|
8109
9711
|
async firstJson() {
|
|
8110
|
-
|
|
9712
|
+
const query = this.limit(1);
|
|
9713
|
+
const { collection, rows } = await query.getRowsAndEntities();
|
|
9714
|
+
const data = collection[0]?.toJSON();
|
|
9715
|
+
query.recordSingleRelationObservations(collection[0]);
|
|
9716
|
+
query.recordSingleRelationAggregateObservations(collection[0]);
|
|
9717
|
+
query.rebindRowsToSerializedResult(rows, data);
|
|
9718
|
+
return data;
|
|
8111
9719
|
}
|
|
8112
9720
|
async sole() {
|
|
8113
|
-
const
|
|
8114
|
-
|
|
9721
|
+
const query = this.limit(2);
|
|
9722
|
+
const { collection, rows } = await query.getRowsAndEntities();
|
|
9723
|
+
if (collection.length === 0) {
|
|
8115
9724
|
throw new ModelNotFoundException(this.repository.definition.name, `${this.repository.definition.name} query expected exactly one result but found 0.`);
|
|
8116
9725
|
}
|
|
8117
|
-
if (
|
|
8118
|
-
throw new HydrationError(`${this.repository.definition.name} query expected exactly one result but found ${
|
|
9726
|
+
if (collection.length !== 1) {
|
|
9727
|
+
throw new HydrationError(`${this.repository.definition.name} query expected exactly one result but found ${collection.length}.`);
|
|
8119
9728
|
}
|
|
8120
|
-
|
|
9729
|
+
const entity = collection[0];
|
|
9730
|
+
query.recordSingleRelationObservations(entity);
|
|
9731
|
+
query.recordSingleRelationAggregateObservations(entity);
|
|
9732
|
+
query.rebindRowsToSerializedResult(rows, entity);
|
|
9733
|
+
return entity;
|
|
8121
9734
|
}
|
|
8122
9735
|
async soleJson() {
|
|
8123
|
-
|
|
9736
|
+
const query = this.limit(2);
|
|
9737
|
+
const { collection, rows } = await query.getRowsAndEntities();
|
|
9738
|
+
if (collection.length === 0) {
|
|
9739
|
+
throw new ModelNotFoundException(this.repository.definition.name, `${this.repository.definition.name} query expected exactly one result but found 0.`);
|
|
9740
|
+
}
|
|
9741
|
+
if (collection.length !== 1) {
|
|
9742
|
+
throw new HydrationError(`${this.repository.definition.name} query expected exactly one result but found ${collection.length}.`);
|
|
9743
|
+
}
|
|
9744
|
+
const data = collection[0].toJSON();
|
|
9745
|
+
query.recordSingleRelationObservations(collection[0]);
|
|
9746
|
+
query.recordSingleRelationAggregateObservations(collection[0]);
|
|
9747
|
+
query.rebindRowsToSerializedResult(rows, data);
|
|
9748
|
+
return data;
|
|
8124
9749
|
}
|
|
8125
9750
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
8126
9751
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
8127
9752
|
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
8128
9753
|
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
8129
|
-
const entities = await this.
|
|
9754
|
+
const { collection: entities, rows } = await this.getUnpaginatedRowsAndEntities();
|
|
8130
9755
|
const total = entities.length;
|
|
8131
9756
|
const offset = (page - 1) * perPage;
|
|
8132
9757
|
const data = entities.slice(offset, offset + perPage);
|
|
8133
9758
|
const from = data.length === 0 ? null : offset + 1;
|
|
8134
9759
|
const to = data.length === 0 ? null : offset + data.length;
|
|
8135
|
-
|
|
9760
|
+
const collection = this.repository.createCollection(data);
|
|
9761
|
+
this.recordPaginatedRelationObservations(collection);
|
|
9762
|
+
this.recordPaginatedRelationAggregateObservations(collection);
|
|
9763
|
+
const result = createPaginator(collection, {
|
|
8136
9764
|
total,
|
|
8137
9765
|
perPage,
|
|
8138
9766
|
pageName,
|
|
@@ -8142,22 +9770,50 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8142
9770
|
to,
|
|
8143
9771
|
hasMorePages: offset + data.length < total
|
|
8144
9772
|
});
|
|
9773
|
+
this.rebindRowsToPaginatedResult(rows, result.data, result.meta, page, pageName, perPage, total, offset);
|
|
9774
|
+
return result;
|
|
8145
9775
|
}
|
|
8146
9776
|
async paginateJson(perPage = 15, page = 1, options = {}) {
|
|
8147
|
-
|
|
9777
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
9778
|
+
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
9779
|
+
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
9780
|
+
const { collection, rows } = await this.getUnpaginatedRowsAndEntities();
|
|
9781
|
+
const total = collection.length;
|
|
9782
|
+
const offset = (page - 1) * perPage;
|
|
9783
|
+
const pageCollection = this.repository.createCollection(collection.slice(offset, offset + perPage));
|
|
9784
|
+
const data = pageCollection.toJSON();
|
|
9785
|
+
this.recordPaginatedRelationObservations(pageCollection);
|
|
9786
|
+
this.recordPaginatedRelationAggregateObservations(pageCollection);
|
|
9787
|
+
const from = data.length === 0 ? null : offset + 1;
|
|
9788
|
+
const to = data.length === 0 ? null : offset + data.length;
|
|
9789
|
+
const result = createPaginator(data, {
|
|
9790
|
+
total,
|
|
9791
|
+
perPage,
|
|
9792
|
+
pageName,
|
|
9793
|
+
currentPage: page,
|
|
9794
|
+
lastPage: Math.max(1, Math.ceil(total / perPage)),
|
|
9795
|
+
from,
|
|
9796
|
+
to,
|
|
9797
|
+
hasMorePages: offset + data.length < total
|
|
9798
|
+
}).toJSON();
|
|
9799
|
+
this.rebindRowsToPaginatedResult(rows, result.data, result.meta, page, pageName, perPage, total, offset);
|
|
9800
|
+
return result;
|
|
8148
9801
|
}
|
|
8149
9802
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
8150
9803
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
8151
9804
|
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
8152
9805
|
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
8153
|
-
const entities = await this.
|
|
9806
|
+
const { collection: entities, rows } = await this.getUnpaginatedRowsAndEntities();
|
|
8154
9807
|
const offset = (page - 1) * perPage;
|
|
8155
9808
|
const pageEntities = entities.slice(offset, offset + perPage + 1);
|
|
8156
9809
|
const hasMorePages = pageEntities.length > perPage;
|
|
8157
9810
|
const data = hasMorePages ? pageEntities.slice(0, perPage) : pageEntities;
|
|
8158
9811
|
const from = data.length === 0 ? null : offset + 1;
|
|
8159
9812
|
const to = data.length === 0 ? null : offset + data.length;
|
|
8160
|
-
|
|
9813
|
+
const collection = this.repository.createCollection(data);
|
|
9814
|
+
this.recordPaginatedRelationObservations(collection);
|
|
9815
|
+
this.recordPaginatedRelationAggregateObservations(collection);
|
|
9816
|
+
const result = createSimplePaginator(collection, {
|
|
8161
9817
|
perPage,
|
|
8162
9818
|
pageName,
|
|
8163
9819
|
currentPage: page,
|
|
@@ -8165,9 +9821,33 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8165
9821
|
to,
|
|
8166
9822
|
hasMorePages
|
|
8167
9823
|
});
|
|
9824
|
+
this.rebindRowsToSimplePaginatedResult(rows, result.data, result.meta, page, pageName, perPage, entities.length, hasMorePages, offset);
|
|
9825
|
+
return result;
|
|
8168
9826
|
}
|
|
8169
9827
|
async simplePaginateJson(perPage = 15, page = 1, options = {}) {
|
|
8170
|
-
|
|
9828
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
9829
|
+
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
9830
|
+
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
9831
|
+
const { collection, rows } = await this.getUnpaginatedRowsAndEntities();
|
|
9832
|
+
const offset = (page - 1) * perPage;
|
|
9833
|
+
const pageEntities = collection.slice(offset, offset + perPage + 1);
|
|
9834
|
+
const hasMorePages = pageEntities.length > perPage;
|
|
9835
|
+
const pageCollection = this.repository.createCollection(hasMorePages ? pageEntities.slice(0, perPage) : pageEntities);
|
|
9836
|
+
const data = pageCollection.toJSON();
|
|
9837
|
+
this.recordPaginatedRelationObservations(pageCollection);
|
|
9838
|
+
this.recordPaginatedRelationAggregateObservations(pageCollection);
|
|
9839
|
+
const from = data.length === 0 ? null : offset + 1;
|
|
9840
|
+
const to = data.length === 0 ? null : offset + data.length;
|
|
9841
|
+
const result = createSimplePaginator(data, {
|
|
9842
|
+
perPage,
|
|
9843
|
+
pageName,
|
|
9844
|
+
currentPage: page,
|
|
9845
|
+
from,
|
|
9846
|
+
to,
|
|
9847
|
+
hasMorePages
|
|
9848
|
+
}).toJSON();
|
|
9849
|
+
this.rebindRowsToSimplePaginatedResult(rows, result.data, result.meta, page, pageName, perPage, collection.length, hasMorePages, offset);
|
|
9850
|
+
return result;
|
|
8171
9851
|
}
|
|
8172
9852
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
8173
9853
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
@@ -8175,7 +9855,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8175
9855
|
const decodedCursor = decodeValueCursor(cursor, (message) => new HydrationError(message));
|
|
8176
9856
|
const orderedQuery = this.prepareCursorPaginationQuery();
|
|
8177
9857
|
const cursorOrders = orderedQuery.resolveCursorOrders();
|
|
8178
|
-
const entities = await orderedQuery.
|
|
9858
|
+
const { collection: entities, rows } = await orderedQuery.getUnpaginatedRowsAndEntities();
|
|
8179
9859
|
const filteredEntities = decodedCursor ? entities.filter((entity) => isRowAfterCursor(
|
|
8180
9860
|
cursorOrders.map((order) => orderedQuery.readCursorColumnValue(entity, order.column)),
|
|
8181
9861
|
decodedCursor.values,
|
|
@@ -8185,15 +9865,65 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8185
9865
|
const hasMorePages = pageEntities.length > perPage;
|
|
8186
9866
|
const data = hasMorePages ? pageEntities.slice(0, perPage) : pageEntities;
|
|
8187
9867
|
const lastEntity = data.at(-1);
|
|
8188
|
-
|
|
9868
|
+
const collection = orderedQuery.repository.createCollection(data);
|
|
9869
|
+
const observedPageRows = orderedQuery.repository.createCollection(pageEntities).toJSON();
|
|
9870
|
+
orderedQuery.recordPaginatedRelationObservations(collection);
|
|
9871
|
+
orderedQuery.recordPaginatedRelationAggregateObservations(collection);
|
|
9872
|
+
const result = createCursorPaginator(collection, {
|
|
8189
9873
|
perPage,
|
|
8190
9874
|
cursorName,
|
|
8191
9875
|
nextCursor: hasMorePages && lastEntity ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastEntity, order.column))) : null,
|
|
8192
9876
|
prevCursor: cursor
|
|
8193
9877
|
});
|
|
9878
|
+
if (cursor === null) {
|
|
9879
|
+
orderedQuery.rebindRowsToCursorPaginatedResult(rows, result.data, {
|
|
9880
|
+
cursorName: result.cursorName,
|
|
9881
|
+
nextCursor: result.nextCursor,
|
|
9882
|
+
perPage: result.perPage,
|
|
9883
|
+
prevCursor: result.prevCursor
|
|
9884
|
+
}, observedPageRows, entities.length, hasMorePages);
|
|
9885
|
+
} else {
|
|
9886
|
+
orderedQuery.rebindRowsToSerializedResult(rows, collection);
|
|
9887
|
+
}
|
|
9888
|
+
return result;
|
|
8194
9889
|
}
|
|
8195
9890
|
async cursorPaginateJson(perPage = 15, cursor = null, options = {}) {
|
|
8196
|
-
|
|
9891
|
+
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
9892
|
+
const cursorName = normalizePaginationParameterName(options.cursorName, "cursor", (message) => new HydrationError(message));
|
|
9893
|
+
const decodedCursor = decodeValueCursor(cursor, (message) => new HydrationError(message));
|
|
9894
|
+
const orderedQuery = this.prepareCursorPaginationQuery();
|
|
9895
|
+
const cursorOrders = orderedQuery.resolveCursorOrders();
|
|
9896
|
+
const { collection, rows } = await orderedQuery.getUnpaginatedRowsAndEntities();
|
|
9897
|
+
const filteredEntities = decodedCursor ? collection.filter((entity) => isRowAfterCursor(
|
|
9898
|
+
cursorOrders.map((order) => orderedQuery.readCursorColumnValue(entity, order.column)),
|
|
9899
|
+
decodedCursor.values,
|
|
9900
|
+
cursorOrders
|
|
9901
|
+
)) : collection;
|
|
9902
|
+
const pageEntities = filteredEntities.slice(0, perPage + 1);
|
|
9903
|
+
const hasMorePages = pageEntities.length > perPage;
|
|
9904
|
+
const pageCollection = orderedQuery.repository.createCollection(hasMorePages ? pageEntities.slice(0, perPage) : pageEntities);
|
|
9905
|
+
const data = pageCollection.toJSON();
|
|
9906
|
+
const observedPageRows = orderedQuery.repository.createCollection(pageEntities).toJSON();
|
|
9907
|
+
const lastEntity = pageCollection.at(-1);
|
|
9908
|
+
orderedQuery.recordPaginatedRelationObservations(pageCollection);
|
|
9909
|
+
orderedQuery.recordPaginatedRelationAggregateObservations(pageCollection);
|
|
9910
|
+
const result = createCursorPaginator(data, {
|
|
9911
|
+
perPage,
|
|
9912
|
+
cursorName,
|
|
9913
|
+
nextCursor: hasMorePages && lastEntity ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastEntity, order.column))) : null,
|
|
9914
|
+
prevCursor: cursor
|
|
9915
|
+
}).toJSON();
|
|
9916
|
+
if (cursor === null) {
|
|
9917
|
+
orderedQuery.rebindRowsToCursorPaginatedResult(rows, result.data, {
|
|
9918
|
+
cursorName: result.cursorName,
|
|
9919
|
+
nextCursor: result.nextCursor,
|
|
9920
|
+
perPage: result.perPage,
|
|
9921
|
+
prevCursor: result.prevCursor
|
|
9922
|
+
}, observedPageRows, collection.length, hasMorePages);
|
|
9923
|
+
} else {
|
|
9924
|
+
orderedQuery.rebindRowsToSerializedResult(rows, result.data);
|
|
9925
|
+
}
|
|
9926
|
+
return result;
|
|
8197
9927
|
}
|
|
8198
9928
|
async chunk(size, callback) {
|
|
8199
9929
|
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
@@ -8257,21 +9987,42 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8257
9987
|
}
|
|
8258
9988
|
}
|
|
8259
9989
|
async count() {
|
|
8260
|
-
|
|
9990
|
+
const collection = await this.get();
|
|
9991
|
+
const result = collection.length;
|
|
9992
|
+
rebindDatabaseQueryObservationAggregate(collection, result, Object.freeze({ kind: "count" }));
|
|
9993
|
+
return result;
|
|
8261
9994
|
}
|
|
8262
9995
|
async exists() {
|
|
8263
|
-
|
|
9996
|
+
const count = await this.count();
|
|
9997
|
+
const result = count > 0;
|
|
9998
|
+
rebindDatabaseQueryObservationAggregate(count, result, Object.freeze({
|
|
9999
|
+
count,
|
|
10000
|
+
kind: "count",
|
|
10001
|
+
output: "boolean"
|
|
10002
|
+
}));
|
|
10003
|
+
return result;
|
|
8264
10004
|
}
|
|
8265
10005
|
async doesntExist() {
|
|
8266
|
-
|
|
10006
|
+
const count = await this.count();
|
|
10007
|
+
const result = count === 0;
|
|
10008
|
+
rebindDatabaseQueryObservationAggregate(count, result, Object.freeze({
|
|
10009
|
+
count,
|
|
10010
|
+
kind: "count",
|
|
10011
|
+
output: "inverseBoolean"
|
|
10012
|
+
}));
|
|
10013
|
+
return result;
|
|
8267
10014
|
}
|
|
8268
10015
|
async pluck(column2) {
|
|
8269
|
-
const
|
|
8270
|
-
|
|
10016
|
+
const { collection, rows } = await this.getRowsAndEntities();
|
|
10017
|
+
const result = collection.map((entity) => entity.get(column2));
|
|
10018
|
+
rebindDatabaseQueryObservationScalarList(rows, result, column2);
|
|
10019
|
+
return result;
|
|
8271
10020
|
}
|
|
8272
10021
|
async value(column2) {
|
|
8273
10022
|
const entity = await this.first();
|
|
8274
|
-
|
|
10023
|
+
const value = entity?.get(column2);
|
|
10024
|
+
rebindDatabaseQueryObservationScalar(entity, value, column2);
|
|
10025
|
+
return value;
|
|
8275
10026
|
}
|
|
8276
10027
|
async valueOrFail(column2) {
|
|
8277
10028
|
const entity = await this.first();
|
|
@@ -8282,6 +10033,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8282
10033
|
if (typeof value === "undefined") {
|
|
8283
10034
|
throw new HydrationError(`${this.repository.definition.name} query returned no value for column "${column2}".`);
|
|
8284
10035
|
}
|
|
10036
|
+
rebindDatabaseQueryObservationScalar(entity, value, column2);
|
|
8285
10037
|
return value;
|
|
8286
10038
|
}
|
|
8287
10039
|
async soleValue(column2) {
|
|
@@ -8290,36 +10042,78 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8290
10042
|
if (typeof value === "undefined") {
|
|
8291
10043
|
throw new HydrationError(`${this.repository.definition.name} query returned no value for column "${column2}".`);
|
|
8292
10044
|
}
|
|
10045
|
+
rebindDatabaseQueryObservationScalar(entity, value, column2);
|
|
8293
10046
|
return value;
|
|
8294
10047
|
}
|
|
8295
10048
|
async sum(column2) {
|
|
8296
10049
|
const entities = await this.get();
|
|
8297
10050
|
if (entities.length === 0) {
|
|
10051
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10052
|
+
rebindDatabaseQueryObservationAggregate(entities, 0, Object.freeze({ column: column2, kind: "sum" }));
|
|
10053
|
+
}
|
|
8298
10054
|
return 0;
|
|
8299
10055
|
}
|
|
8300
|
-
|
|
10056
|
+
const result = this.extractNumericValues(entities, column2, "sum").reduce((sum, value) => sum + value, 0);
|
|
10057
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10058
|
+
rebindDatabaseQueryObservationAggregate(entities, result, Object.freeze({ column: column2, kind: "sum" }));
|
|
10059
|
+
}
|
|
10060
|
+
return result;
|
|
8301
10061
|
}
|
|
8302
10062
|
async avg(column2) {
|
|
8303
10063
|
const entities = await this.get();
|
|
8304
10064
|
if (entities.length === 0) {
|
|
10065
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10066
|
+
rebindDatabaseQueryObservationAggregate(entities, null, Object.freeze({ column: column2, count: 0, kind: "avg", sum: 0 }));
|
|
10067
|
+
}
|
|
8305
10068
|
return null;
|
|
8306
10069
|
}
|
|
8307
10070
|
const values = this.extractNumericValues(entities, column2, "avg");
|
|
8308
|
-
|
|
10071
|
+
const sum = values.reduce((total, value) => total + value, 0);
|
|
10072
|
+
const result = sum / values.length;
|
|
10073
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10074
|
+
rebindDatabaseQueryObservationAggregate(entities, result, Object.freeze({ column: column2, count: values.length, kind: "avg", sum }));
|
|
10075
|
+
}
|
|
10076
|
+
return result;
|
|
8309
10077
|
}
|
|
8310
10078
|
async min(column2) {
|
|
8311
10079
|
const entities = await this.get();
|
|
8312
10080
|
if (entities.length === 0) {
|
|
10081
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10082
|
+
rebindDatabaseQueryObservationAggregate(entities, null, Object.freeze({ column: column2, kind: "min" }));
|
|
10083
|
+
}
|
|
8313
10084
|
return null;
|
|
8314
10085
|
}
|
|
8315
|
-
|
|
10086
|
+
const values = this.extractNumericValues(entities, column2, "min");
|
|
10087
|
+
const result = Math.min(...values);
|
|
10088
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10089
|
+
rebindDatabaseQueryObservationAggregate(entities, result, Object.freeze({
|
|
10090
|
+
column: column2,
|
|
10091
|
+
currentValueCount: values.filter((value) => value === result).length,
|
|
10092
|
+
kind: "min",
|
|
10093
|
+
valueCounts: createAggregateValueCounts(values)
|
|
10094
|
+
}));
|
|
10095
|
+
}
|
|
10096
|
+
return result;
|
|
8316
10097
|
}
|
|
8317
10098
|
async max(column2) {
|
|
8318
10099
|
const entities = await this.get();
|
|
8319
10100
|
if (entities.length === 0) {
|
|
10101
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10102
|
+
rebindDatabaseQueryObservationAggregate(entities, null, Object.freeze({ column: column2, kind: "max" }));
|
|
10103
|
+
}
|
|
8320
10104
|
return null;
|
|
8321
10105
|
}
|
|
8322
|
-
|
|
10106
|
+
const values = this.extractNumericValues(entities, column2, "max");
|
|
10107
|
+
const result = Math.max(...values);
|
|
10108
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10109
|
+
rebindDatabaseQueryObservationAggregate(entities, result, Object.freeze({
|
|
10110
|
+
column: column2,
|
|
10111
|
+
currentValueCount: values.filter((value) => value === result).length,
|
|
10112
|
+
kind: "max",
|
|
10113
|
+
valueCounts: createAggregateValueCounts(values)
|
|
10114
|
+
}));
|
|
10115
|
+
}
|
|
10116
|
+
return result;
|
|
8323
10117
|
}
|
|
8324
10118
|
async firstOrFail() {
|
|
8325
10119
|
const entity = await this.first();
|
|
@@ -8592,68 +10386,296 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8592
10386
|
column: column2
|
|
8593
10387
|
}));
|
|
8594
10388
|
}
|
|
8595
|
-
parseAggregateRelation(spec) {
|
|
8596
|
-
const [relationPart, aliasPart] = spec.split(/\s+as\s+/i);
|
|
8597
|
-
const relation = relationPart?.trim();
|
|
8598
|
-
const alias = aliasPart?.trim();
|
|
8599
|
-
if (!relation) {
|
|
8600
|
-
throw new HydrationError("Aggregate relation names cannot be empty.");
|
|
10389
|
+
parseAggregateRelation(spec) {
|
|
10390
|
+
const [relationPart, aliasPart] = spec.split(/\s+as\s+/i);
|
|
10391
|
+
const relation = relationPart?.trim();
|
|
10392
|
+
const alias = aliasPart?.trim();
|
|
10393
|
+
if (!relation) {
|
|
10394
|
+
throw new HydrationError("Aggregate relation names cannot be empty.");
|
|
10395
|
+
}
|
|
10396
|
+
if (typeof aliasPart !== "undefined" && !alias) {
|
|
10397
|
+
throw new HydrationError("Aggregate relation aliases cannot be empty.");
|
|
10398
|
+
}
|
|
10399
|
+
return alias ? { relation, alias } : { relation };
|
|
10400
|
+
}
|
|
10401
|
+
resolveBelongsToRelation(relatedEntity, relationName) {
|
|
10402
|
+
const resolvedName = this.resolveBelongsToRelationName(relatedEntity, relationName);
|
|
10403
|
+
const relation = this.repository.getRelationDefinition(resolvedName);
|
|
10404
|
+
if (relation.kind !== "belongsTo") {
|
|
10405
|
+
throw new RelationError(`Relation "${resolvedName}" on model "${this.repository.definition.name}" is not a belongs-to relation.`);
|
|
10406
|
+
}
|
|
10407
|
+
return relation;
|
|
10408
|
+
}
|
|
10409
|
+
applyBelongsToFilter(relatedEntity, relationName, boolean) {
|
|
10410
|
+
const resolvedRelationName = this.resolveBelongsToRelationName(relatedEntity, relationName);
|
|
10411
|
+
const relation = this.resolveBelongsToRelation(relatedEntity, resolvedRelationName);
|
|
10412
|
+
const ownerValue = relatedEntity.get(relation.ownerKey);
|
|
10413
|
+
if (ownerValue === null || typeof ownerValue === "undefined") {
|
|
10414
|
+
return boolean === "and" ? this.whereDoesntHave(resolvedRelationName) : this.orWhereDoesntHave(resolvedRelationName);
|
|
10415
|
+
}
|
|
10416
|
+
return boolean === "and" ? this.whereHas(resolvedRelationName, (query) => query.where(relation.ownerKey, ownerValue)) : this.orWhereHas(resolvedRelationName, (query) => query.where(relation.ownerKey, ownerValue));
|
|
10417
|
+
}
|
|
10418
|
+
resolveBelongsToRelationName(relatedEntity, relationName) {
|
|
10419
|
+
if (relationName) {
|
|
10420
|
+
return relationName;
|
|
10421
|
+
}
|
|
10422
|
+
const relatedDefinition = relatedEntity.getRepository().definition;
|
|
10423
|
+
const candidates = Object.entries(this.repository.definition.relations).filter(([, relation]) => relation.kind === "belongsTo").map(([name, relation]) => [name, relation]).filter(([, relation]) => {
|
|
10424
|
+
const ref = relation.related();
|
|
10425
|
+
const definition = "definition" in ref ? ref.definition : ref;
|
|
10426
|
+
return definition.table.tableName === relatedDefinition.table.tableName;
|
|
10427
|
+
}).map(([name]) => name);
|
|
10428
|
+
if (candidates.length === 1) {
|
|
10429
|
+
return candidates[0];
|
|
10430
|
+
}
|
|
10431
|
+
if (candidates.length === 0) {
|
|
10432
|
+
throw new RelationError(
|
|
10433
|
+
`No belongs-to relation on model "${this.repository.definition.name}" matches related model "${relatedDefinition.name}".`
|
|
10434
|
+
);
|
|
10435
|
+
}
|
|
10436
|
+
throw new RelationError(
|
|
10437
|
+
`Multiple belongs-to relations on model "${this.repository.definition.name}" match related model "${relatedDefinition.name}". Specify the relation name explicitly.`
|
|
10438
|
+
);
|
|
10439
|
+
}
|
|
10440
|
+
extractNumericValues(entities, column2, kind) {
|
|
10441
|
+
return entities.map((entity) => {
|
|
10442
|
+
const value = entity.get(column2);
|
|
10443
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
10444
|
+
throw new HydrationError(`Model aggregate "${kind}" requires numeric values for column "${column2}".`);
|
|
10445
|
+
}
|
|
10446
|
+
return value;
|
|
10447
|
+
});
|
|
10448
|
+
}
|
|
10449
|
+
async getUnpaginatedEntities() {
|
|
10450
|
+
return this.clone(this.tableQuery.limit(void 0).offset(void 0)).get();
|
|
10451
|
+
}
|
|
10452
|
+
async getUnpaginatedRowsAndEntities() {
|
|
10453
|
+
const query = this.clone(this.tableQuery.limit(void 0).offset(void 0));
|
|
10454
|
+
return await query.getRowsAndEntities();
|
|
10455
|
+
}
|
|
10456
|
+
async getRowsAndEntities() {
|
|
10457
|
+
const rows = await this.tableQuery.get();
|
|
10458
|
+
return {
|
|
10459
|
+
collection: await this.hydrateRows(rows),
|
|
10460
|
+
rows
|
|
10461
|
+
};
|
|
10462
|
+
}
|
|
10463
|
+
recordCollectionRelationAggregateObservations(collection) {
|
|
10464
|
+
this.repository.recordRelationAggregateObservations(
|
|
10465
|
+
collection,
|
|
10466
|
+
this.aggregateLoads,
|
|
10467
|
+
(index, key) => Object.freeze([index, key])
|
|
10468
|
+
);
|
|
10469
|
+
}
|
|
10470
|
+
recordCollectionRelationObservations(collection) {
|
|
10471
|
+
this.repository.recordRelationObservations(
|
|
10472
|
+
collection,
|
|
10473
|
+
this.eagerLoads,
|
|
10474
|
+
(index, relationName) => Object.freeze([index, relationName])
|
|
10475
|
+
);
|
|
10476
|
+
}
|
|
10477
|
+
recordSingleRelationObservations(entity) {
|
|
10478
|
+
if (!entity) {
|
|
10479
|
+
return;
|
|
10480
|
+
}
|
|
10481
|
+
this.repository.recordRelationObservations(
|
|
10482
|
+
[entity],
|
|
10483
|
+
this.eagerLoads,
|
|
10484
|
+
(_index, relationName) => Object.freeze([relationName])
|
|
10485
|
+
);
|
|
10486
|
+
}
|
|
10487
|
+
recordPaginatedRelationObservations(collection) {
|
|
10488
|
+
this.repository.recordRelationObservations(
|
|
10489
|
+
collection,
|
|
10490
|
+
this.eagerLoads,
|
|
10491
|
+
(index, relationName) => Object.freeze(["data", index, relationName])
|
|
10492
|
+
);
|
|
10493
|
+
}
|
|
10494
|
+
recordSingleRelationAggregateObservations(entity) {
|
|
10495
|
+
if (!entity) {
|
|
10496
|
+
return;
|
|
10497
|
+
}
|
|
10498
|
+
this.repository.recordRelationAggregateObservations(
|
|
10499
|
+
[entity],
|
|
10500
|
+
this.aggregateLoads,
|
|
10501
|
+
(_index, key) => Object.freeze([key])
|
|
10502
|
+
);
|
|
10503
|
+
}
|
|
10504
|
+
recordPaginatedRelationAggregateObservations(collection) {
|
|
10505
|
+
this.repository.recordRelationAggregateObservations(
|
|
10506
|
+
collection,
|
|
10507
|
+
this.aggregateLoads,
|
|
10508
|
+
(index, key) => Object.freeze(["data", index, key])
|
|
10509
|
+
);
|
|
10510
|
+
}
|
|
10511
|
+
canBindRowsToSerializedResultBase() {
|
|
10512
|
+
return Object.keys(this.repository.definition.accessors).length === 0 && Object.keys(this.repository.definition.casts).length === 0 && Object.keys(this.queryCasts).length === 0 && this.repository.definition.appended.length === 0 && this.repository.definition.hidden.length === 0 && this.repository.definition.visible.length === 0 && this.relationFilters.length === 0 && this.aggregateLoads.length === 0;
|
|
10513
|
+
}
|
|
10514
|
+
canBindRowsToSerializedResult() {
|
|
10515
|
+
return this.canBindRowsToSerializedResultBase() && this.eagerLoads.length === 0;
|
|
10516
|
+
}
|
|
10517
|
+
createPatchableEagerRelationHydrations() {
|
|
10518
|
+
if (!this.canBindRowsToSerializedResultBase() || this.eagerLoads.length === 0) {
|
|
10519
|
+
return void 0;
|
|
10520
|
+
}
|
|
10521
|
+
const belongsToHydrations = [];
|
|
10522
|
+
const relatedHydrations = [];
|
|
10523
|
+
for (const load of this.eagerLoads) {
|
|
10524
|
+
if (load.relation.includes(".")) {
|
|
10525
|
+
return void 0;
|
|
10526
|
+
}
|
|
10527
|
+
const relation = this.repository.getRelationDefinition(load.relation);
|
|
10528
|
+
if (relation.kind === "belongsTo") {
|
|
10529
|
+
if (relation.constraint || load.constraint) {
|
|
10530
|
+
return void 0;
|
|
10531
|
+
}
|
|
10532
|
+
const related = relation.related();
|
|
10533
|
+
const relatedDefinition = "definition" in related ? related.definition : related;
|
|
10534
|
+
belongsToHydrations.push(Object.freeze({
|
|
10535
|
+
foreignKey: relation.foreignKey,
|
|
10536
|
+
ownerKey: relation.ownerKey,
|
|
10537
|
+
relationKey: load.relation,
|
|
10538
|
+
relatedConnectionName: relatedDefinition.connectionName ?? this.getConnectionName(),
|
|
10539
|
+
relatedTableName: relatedDefinition.table.tableName
|
|
10540
|
+
}));
|
|
10541
|
+
continue;
|
|
10542
|
+
}
|
|
10543
|
+
if (relation.kind === "hasMany" || relation.kind === "hasOne") {
|
|
10544
|
+
const hydrationQuery = this.createPatchableRelatedHydrationQuery(relation, load.constraint);
|
|
10545
|
+
if (!hydrationQuery) {
|
|
10546
|
+
return void 0;
|
|
10547
|
+
}
|
|
10548
|
+
const related = relation.related();
|
|
10549
|
+
const relatedDefinition = "definition" in related ? related.definition : related;
|
|
10550
|
+
relatedHydrations.push(Object.freeze({
|
|
10551
|
+
foreignKey: relation.foreignKey,
|
|
10552
|
+
kind: relation.kind,
|
|
10553
|
+
localKey: relation.localKey,
|
|
10554
|
+
orderBy: hydrationQuery.orderBy,
|
|
10555
|
+
predicates: hydrationQuery.predicates,
|
|
10556
|
+
relationKey: load.relation,
|
|
10557
|
+
relatedConnectionName: relatedDefinition.connectionName ?? this.getConnectionName(),
|
|
10558
|
+
relatedTableName: relatedDefinition.table.tableName
|
|
10559
|
+
}));
|
|
10560
|
+
continue;
|
|
10561
|
+
}
|
|
10562
|
+
return void 0;
|
|
10563
|
+
}
|
|
10564
|
+
return Object.freeze({
|
|
10565
|
+
belongsToHydrations: belongsToHydrations.length > 0 ? Object.freeze(belongsToHydrations) : void 0,
|
|
10566
|
+
relatedHydrations: relatedHydrations.length > 0 ? Object.freeze(relatedHydrations) : void 0
|
|
10567
|
+
});
|
|
10568
|
+
}
|
|
10569
|
+
createPatchableRelatedHydrationQuery(relation, constraint) {
|
|
10570
|
+
if (!relation.constraint && !constraint) {
|
|
10571
|
+
return Object.freeze({
|
|
10572
|
+
orderBy: Object.freeze([]),
|
|
10573
|
+
predicates: Object.freeze([])
|
|
10574
|
+
});
|
|
8601
10575
|
}
|
|
8602
|
-
|
|
8603
|
-
|
|
10576
|
+
const related = relation.related();
|
|
10577
|
+
if (!this.isQueryableModelReference(related)) {
|
|
10578
|
+
return void 0;
|
|
8604
10579
|
}
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
10580
|
+
let query = related.query();
|
|
10581
|
+
const relationResult = relation.constraint?.(query);
|
|
10582
|
+
query = relationResult instanceof _ModelQueryBuilder ? relationResult : query;
|
|
10583
|
+
if (constraint) {
|
|
10584
|
+
const result = constraint(query);
|
|
10585
|
+
query = result instanceof _ModelQueryBuilder ? result : query;
|
|
10586
|
+
}
|
|
10587
|
+
const plan = query.getTableQueryBuilder().getPlan();
|
|
10588
|
+
const relatedDefinition = "definition" in related ? related.definition : related;
|
|
10589
|
+
const observation = createDatabaseQueryObservation(
|
|
10590
|
+
plan,
|
|
10591
|
+
relatedDefinition.connectionName ?? this.getConnectionName(),
|
|
10592
|
+
Object.freeze([])
|
|
10593
|
+
);
|
|
10594
|
+
if (!observation?.patchable || typeof observation.limit !== "undefined" || typeof observation.offset !== "undefined") {
|
|
10595
|
+
return void 0;
|
|
8612
10596
|
}
|
|
8613
|
-
return
|
|
10597
|
+
return Object.freeze({
|
|
10598
|
+
orderBy: observation.orderBy,
|
|
10599
|
+
predicates: observation.predicates
|
|
10600
|
+
});
|
|
8614
10601
|
}
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
const relation = this.resolveBelongsToRelation(relatedEntity, resolvedRelationName);
|
|
8618
|
-
const ownerValue = relatedEntity.get(relation.ownerKey);
|
|
8619
|
-
if (ownerValue === null || typeof ownerValue === "undefined") {
|
|
8620
|
-
return boolean === "and" ? this.whereDoesntHave(resolvedRelationName) : this.orWhereDoesntHave(resolvedRelationName);
|
|
8621
|
-
}
|
|
8622
|
-
return boolean === "and" ? this.whereHas(resolvedRelationName, (query) => query.where(relation.ownerKey, ownerValue)) : this.orWhereHas(resolvedRelationName, (query) => query.where(relation.ownerKey, ownerValue));
|
|
10602
|
+
isQueryableModelReference(value) {
|
|
10603
|
+
return "query" in value && typeof value.query === "function";
|
|
8623
10604
|
}
|
|
8624
|
-
|
|
8625
|
-
if (
|
|
8626
|
-
return
|
|
10605
|
+
rebindRowsToSerializedResult(rows, result) {
|
|
10606
|
+
if (!hasActiveDatabaseDependencyCollector()) {
|
|
10607
|
+
return;
|
|
8627
10608
|
}
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
const definition = "definition" in ref ? ref.definition : ref;
|
|
8632
|
-
return definition.table.tableName === relatedDefinition.table.tableName;
|
|
8633
|
-
}).map(([name]) => name);
|
|
8634
|
-
if (candidates.length === 1) {
|
|
8635
|
-
return candidates[0];
|
|
10609
|
+
if (this.canBindRowsToSerializedResult()) {
|
|
10610
|
+
rebindDatabaseQueryObservationResult(rows, result);
|
|
10611
|
+
return;
|
|
8636
10612
|
}
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
10613
|
+
const hydrations = this.createPatchableEagerRelationHydrations();
|
|
10614
|
+
if (hydrations) {
|
|
10615
|
+
rebindDatabaseQueryObservationHydratedResult(
|
|
10616
|
+
rows,
|
|
10617
|
+
result,
|
|
10618
|
+
hydrations.belongsToHydrations ?? Object.freeze([]),
|
|
10619
|
+
hydrations.relatedHydrations
|
|
8640
10620
|
);
|
|
10621
|
+
return;
|
|
8641
10622
|
}
|
|
8642
|
-
|
|
8643
|
-
`Multiple belongs-to relations on model "${this.repository.definition.name}" match related model "${relatedDefinition.name}". Specify the relation name explicitly.`
|
|
8644
|
-
);
|
|
10623
|
+
disableDatabaseQueryObservationPatching(rows);
|
|
8645
10624
|
}
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8651
|
-
|
|
8652
|
-
|
|
8653
|
-
|
|
10625
|
+
rebindRowsToPaginatedResult(rows, data, meta, currentPage, pageName, perPage, total, offset) {
|
|
10626
|
+
if (!hasActiveDatabaseDependencyCollector()) {
|
|
10627
|
+
return;
|
|
10628
|
+
}
|
|
10629
|
+
const hydrations = this.createPatchableEagerRelationHydrations();
|
|
10630
|
+
if (!this.canBindRowsToSerializedResult() && !hydrations) {
|
|
10631
|
+
disableDatabaseQueryObservationPatching(rows);
|
|
10632
|
+
return;
|
|
10633
|
+
}
|
|
10634
|
+
rebindDatabaseQueryObservationPagination(rows, data, meta, Object.freeze({
|
|
10635
|
+
currentPage,
|
|
10636
|
+
kind: "standard",
|
|
10637
|
+
pageName,
|
|
10638
|
+
perPage,
|
|
10639
|
+
total
|
|
10640
|
+
}), offset, hydrations?.belongsToHydrations, hydrations?.relatedHydrations);
|
|
8654
10641
|
}
|
|
8655
|
-
|
|
8656
|
-
|
|
10642
|
+
rebindRowsToSimplePaginatedResult(rows, data, meta, currentPage, pageName, perPage, rowCount, hasMorePages, offset) {
|
|
10643
|
+
if (!hasActiveDatabaseDependencyCollector()) {
|
|
10644
|
+
return;
|
|
10645
|
+
}
|
|
10646
|
+
const hydrations = this.createPatchableEagerRelationHydrations();
|
|
10647
|
+
if (!this.canBindRowsToSerializedResult() && !hydrations) {
|
|
10648
|
+
disableDatabaseQueryObservationPatching(rows);
|
|
10649
|
+
return;
|
|
10650
|
+
}
|
|
10651
|
+
rebindDatabaseQueryObservationPagination(rows, data, meta, Object.freeze({
|
|
10652
|
+
currentPage,
|
|
10653
|
+
hasMorePages,
|
|
10654
|
+
kind: "simple",
|
|
10655
|
+
pageName,
|
|
10656
|
+
perPage,
|
|
10657
|
+
rowCount
|
|
10658
|
+
}), offset, hydrations?.belongsToHydrations, hydrations?.relatedHydrations);
|
|
10659
|
+
}
|
|
10660
|
+
rebindRowsToCursorPaginatedResult(rows, data, meta, pageRows, rowCount, hasMorePages) {
|
|
10661
|
+
if (!hasActiveDatabaseDependencyCollector()) {
|
|
10662
|
+
return;
|
|
10663
|
+
}
|
|
10664
|
+
const hydrations = this.createPatchableEagerRelationHydrations();
|
|
10665
|
+
if (!this.canBindRowsToSerializedResult() && !hydrations) {
|
|
10666
|
+
disableDatabaseQueryObservationPatching(rows);
|
|
10667
|
+
return;
|
|
10668
|
+
}
|
|
10669
|
+
rebindDatabaseQueryObservationCursorPagination(rows, data, meta, Object.freeze({
|
|
10670
|
+
cursorName: meta.cursorName,
|
|
10671
|
+
hasMorePages,
|
|
10672
|
+
kind: "cursor",
|
|
10673
|
+
nextCursor: meta.nextCursor,
|
|
10674
|
+
perPage: meta.perPage,
|
|
10675
|
+
prevCursor: meta.prevCursor,
|
|
10676
|
+
rows: pageRows,
|
|
10677
|
+
rowCount
|
|
10678
|
+
}), hydrations?.belongsToHydrations, hydrations?.relatedHydrations);
|
|
8657
10679
|
}
|
|
8658
10680
|
prepareCursorPaginationQuery() {
|
|
8659
10681
|
const plan = this.tableQuery.getPlan();
|
|
@@ -8716,6 +10738,8 @@ function setAutomaticEagerLoading(definition, value) {
|
|
|
8716
10738
|
}
|
|
8717
10739
|
|
|
8718
10740
|
// src/model/ModelRepository.ts
|
|
10741
|
+
var relationAggregateObservationMetadata = /* @__PURE__ */ new WeakMap();
|
|
10742
|
+
var relationQueryObservationMetadata = /* @__PURE__ */ new WeakMap();
|
|
8719
10743
|
function hasDefinition(reference) {
|
|
8720
10744
|
return "definition" in reference;
|
|
8721
10745
|
}
|
|
@@ -9060,6 +11084,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9060
11084
|
if (entities.length === 0 || aggregates.length === 0) {
|
|
9061
11085
|
return;
|
|
9062
11086
|
}
|
|
11087
|
+
const observationCount = hasActiveDatabaseDependencyCollector() ? readDatabaseQueryObservationCount() : void 0;
|
|
9063
11088
|
for (const aggregate of aggregates) {
|
|
9064
11089
|
if (aggregate.relation.includes(".")) {
|
|
9065
11090
|
throw new SecurityError("Nested relation aggregates are not supported yet.");
|
|
@@ -9072,6 +11097,12 @@ var ModelRepository = class _ModelRepository {
|
|
|
9072
11097
|
const parentKey = this.getRelationParentValue(entity, relation);
|
|
9073
11098
|
const count = counts.get(parentKey) ?? 0;
|
|
9074
11099
|
entity.setComputed(key, aggregate.kind === "count" ? count : count > 0);
|
|
11100
|
+
if (aggregate.kind === "exists" && typeof observationCount === "number") {
|
|
11101
|
+
this.setRelationAggregateObservationMetadata(entity, key, Object.freeze({
|
|
11102
|
+
count,
|
|
11103
|
+
kind: "count"
|
|
11104
|
+
}));
|
|
11105
|
+
}
|
|
9075
11106
|
}
|
|
9076
11107
|
continue;
|
|
9077
11108
|
}
|
|
@@ -9081,8 +11112,489 @@ var ModelRepository = class _ModelRepository {
|
|
|
9081
11112
|
const values = await this.getRelationAggregateValues(entities, relation, aggregate);
|
|
9082
11113
|
for (const entity of entities) {
|
|
9083
11114
|
const parentKey = this.getRelationParentValue(entity, relation);
|
|
9084
|
-
|
|
11115
|
+
const computation = values.get(parentKey);
|
|
11116
|
+
entity.setComputed(key, computation?.value ?? null);
|
|
11117
|
+
if (computation?.metadata && typeof observationCount === "number") {
|
|
11118
|
+
this.setRelationAggregateObservationMetadata(entity, key, computation.metadata);
|
|
11119
|
+
}
|
|
11120
|
+
}
|
|
11121
|
+
}
|
|
11122
|
+
if (typeof observationCount === "number") {
|
|
11123
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
11124
|
+
}
|
|
11125
|
+
}
|
|
11126
|
+
recordRelationAggregateObservations(entities, aggregates, createPath) {
|
|
11127
|
+
if (!hasActiveDatabaseDependencyCollector() || entities.length === 0 || aggregates.length === 0) {
|
|
11128
|
+
return;
|
|
11129
|
+
}
|
|
11130
|
+
for (const aggregate of aggregates) {
|
|
11131
|
+
if (aggregate.relation.includes(".")) {
|
|
11132
|
+
continue;
|
|
11133
|
+
}
|
|
11134
|
+
const relation = this.getRelationDefinition(aggregate.relation);
|
|
11135
|
+
const key = this.getAggregateAttributeKey(aggregate);
|
|
11136
|
+
for (let index = 0; index < entities.length; index += 1) {
|
|
11137
|
+
const entity = entities[index];
|
|
11138
|
+
if (!entity) {
|
|
11139
|
+
continue;
|
|
11140
|
+
}
|
|
11141
|
+
const target = this.createRelationAggregateObservationTarget(entity, relation);
|
|
11142
|
+
if (!target) {
|
|
11143
|
+
continue;
|
|
11144
|
+
}
|
|
11145
|
+
const aggregateObservation = this.createRelationAggregateObservation(aggregate, entity, key);
|
|
11146
|
+
if (!aggregateObservation) {
|
|
11147
|
+
continue;
|
|
11148
|
+
}
|
|
11149
|
+
const predicateDependency = createTablePredicateCacheDependency(
|
|
11150
|
+
target.connectionName,
|
|
11151
|
+
target.tableName,
|
|
11152
|
+
target.column,
|
|
11153
|
+
target.value
|
|
11154
|
+
);
|
|
11155
|
+
const dependencies = predicateDependency ? Object.freeze([
|
|
11156
|
+
createTableCacheDependency(target.connectionName, target.tableName),
|
|
11157
|
+
predicateDependency
|
|
11158
|
+
]) : Object.freeze([createTableCacheDependency(target.connectionName, target.tableName)]);
|
|
11159
|
+
const resultPath = createPath(index, key);
|
|
11160
|
+
const data = entity.toJSON();
|
|
11161
|
+
recordDatabaseQueryObservation(Object.freeze({
|
|
11162
|
+
aggregate: aggregate.kind === "exists" ? Object.freeze({
|
|
11163
|
+
...aggregateObservation,
|
|
11164
|
+
output: "boolean"
|
|
11165
|
+
}) : aggregateObservation,
|
|
11166
|
+
connectionName: target.connectionName,
|
|
11167
|
+
dependencies,
|
|
11168
|
+
orderBy: [],
|
|
11169
|
+
patchable: true,
|
|
11170
|
+
predicates: Object.freeze([Object.freeze({
|
|
11171
|
+
column: target.column,
|
|
11172
|
+
operator: "=",
|
|
11173
|
+
value: target.value
|
|
11174
|
+
})]),
|
|
11175
|
+
result: data[key],
|
|
11176
|
+
resultPath,
|
|
11177
|
+
selections: [],
|
|
11178
|
+
tableName: target.tableName
|
|
11179
|
+
}));
|
|
11180
|
+
}
|
|
11181
|
+
}
|
|
11182
|
+
}
|
|
11183
|
+
recordRelationObservations(entities, relations, createPath) {
|
|
11184
|
+
if (!hasActiveDatabaseDependencyCollector() || entities.length === 0 || relations.length === 0) {
|
|
11185
|
+
return;
|
|
11186
|
+
}
|
|
11187
|
+
for (const entry of this.normalizeEagerLoads(relations)) {
|
|
11188
|
+
if (entry.relation.includes(".")) {
|
|
11189
|
+
continue;
|
|
11190
|
+
}
|
|
11191
|
+
const relationName = entry.relation;
|
|
11192
|
+
const relation = this.getRelationDefinition(relationName);
|
|
11193
|
+
if (relation.kind === "hasMany") {
|
|
11194
|
+
this.recordHasManyRelationObservations(entities, relationName, relation, createPath);
|
|
11195
|
+
continue;
|
|
11196
|
+
}
|
|
11197
|
+
if (relation.kind === "hasOne") {
|
|
11198
|
+
this.recordHasOneRelationObservations(entities, relationName, relation, createPath);
|
|
11199
|
+
continue;
|
|
11200
|
+
}
|
|
11201
|
+
if (relation.kind === "belongsTo") {
|
|
11202
|
+
this.recordBelongsToRelationObservations(entities, relationName, relation, createPath);
|
|
11203
|
+
continue;
|
|
11204
|
+
}
|
|
11205
|
+
if (relation.constraint) {
|
|
11206
|
+
continue;
|
|
11207
|
+
}
|
|
11208
|
+
if (relation.kind === "belongsToMany") {
|
|
11209
|
+
this.recordBelongsToManyRelationObservations(entities, relationName, relation, createPath);
|
|
11210
|
+
}
|
|
11211
|
+
}
|
|
11212
|
+
}
|
|
11213
|
+
recordHasManyRelationObservations(entities, relationName, relation, createPath) {
|
|
11214
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11215
|
+
for (let index = 0; index < entities.length; index += 1) {
|
|
11216
|
+
const entity = entities[index];
|
|
11217
|
+
if (!entity || !entity.hasRelation(relationName)) {
|
|
11218
|
+
continue;
|
|
11219
|
+
}
|
|
11220
|
+
const observed = this.getRelationQueryObservation(entity, relationName);
|
|
11221
|
+
if (observed) {
|
|
11222
|
+
recordDatabaseQueryObservation(Object.freeze({
|
|
11223
|
+
...observed,
|
|
11224
|
+
resultPath: createPath(index, relationName)
|
|
11225
|
+
}));
|
|
11226
|
+
continue;
|
|
11227
|
+
}
|
|
11228
|
+
if (relation.constraint) {
|
|
11229
|
+
continue;
|
|
9085
11230
|
}
|
|
11231
|
+
const parentKey = this.getRelationParentValue(entity, relation);
|
|
11232
|
+
const predicateDependency = createTablePredicateCacheDependency(
|
|
11233
|
+
related.getConnectionName(),
|
|
11234
|
+
related.definition.table.tableName,
|
|
11235
|
+
relation.foreignKey,
|
|
11236
|
+
parentKey
|
|
11237
|
+
);
|
|
11238
|
+
const dependencies = predicateDependency ? Object.freeze([
|
|
11239
|
+
createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName),
|
|
11240
|
+
predicateDependency
|
|
11241
|
+
]) : Object.freeze([createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName)]);
|
|
11242
|
+
recordDatabaseQueryObservation(Object.freeze({
|
|
11243
|
+
connectionName: related.getConnectionName(),
|
|
11244
|
+
dependencies,
|
|
11245
|
+
orderBy: [],
|
|
11246
|
+
patchable: true,
|
|
11247
|
+
predicates: Object.freeze([Object.freeze({
|
|
11248
|
+
column: relation.foreignKey,
|
|
11249
|
+
operator: "=",
|
|
11250
|
+
value: parentKey
|
|
11251
|
+
})]),
|
|
11252
|
+
resultPath: createPath(index, relationName),
|
|
11253
|
+
selections: [],
|
|
11254
|
+
tableName: related.definition.table.tableName
|
|
11255
|
+
}));
|
|
11256
|
+
}
|
|
11257
|
+
}
|
|
11258
|
+
recordHasOneRelationObservations(entities, relationName, relation, createPath) {
|
|
11259
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11260
|
+
for (let index = 0; index < entities.length; index += 1) {
|
|
11261
|
+
const entity = entities[index];
|
|
11262
|
+
if (!entity || !entity.hasRelation(relationName)) {
|
|
11263
|
+
continue;
|
|
11264
|
+
}
|
|
11265
|
+
const resultPath = createPath(index, relationName);
|
|
11266
|
+
const observed = this.getRelationQueryObservation(entity, relationName);
|
|
11267
|
+
if (observed) {
|
|
11268
|
+
recordDatabaseQueryObservation(this.createNullableSingleRecordRelationObservation(observed, resultPath));
|
|
11269
|
+
continue;
|
|
11270
|
+
}
|
|
11271
|
+
if (relation.constraint) {
|
|
11272
|
+
continue;
|
|
11273
|
+
}
|
|
11274
|
+
const parentKey = this.getRelationParentValue(entity, relation);
|
|
11275
|
+
const predicateDependency = createTablePredicateCacheDependency(
|
|
11276
|
+
related.getConnectionName(),
|
|
11277
|
+
related.definition.table.tableName,
|
|
11278
|
+
relation.foreignKey,
|
|
11279
|
+
parentKey
|
|
11280
|
+
);
|
|
11281
|
+
const dependencies = predicateDependency ? Object.freeze([
|
|
11282
|
+
createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName),
|
|
11283
|
+
predicateDependency
|
|
11284
|
+
]) : Object.freeze([createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName)]);
|
|
11285
|
+
recordDatabaseQueryObservation(this.createNullableSingleRecordRelationObservation(Object.freeze({
|
|
11286
|
+
connectionName: related.getConnectionName(),
|
|
11287
|
+
dependencies,
|
|
11288
|
+
orderBy: [],
|
|
11289
|
+
patchable: true,
|
|
11290
|
+
predicates: Object.freeze([Object.freeze({
|
|
11291
|
+
column: relation.foreignKey,
|
|
11292
|
+
operator: "=",
|
|
11293
|
+
value: parentKey
|
|
11294
|
+
})]),
|
|
11295
|
+
selections: [],
|
|
11296
|
+
tableName: related.definition.table.tableName
|
|
11297
|
+
}), resultPath));
|
|
11298
|
+
}
|
|
11299
|
+
}
|
|
11300
|
+
recordBelongsToRelationObservations(entities, relationName, relation, createPath) {
|
|
11301
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11302
|
+
for (let index = 0; index < entities.length; index += 1) {
|
|
11303
|
+
const entity = entities[index];
|
|
11304
|
+
if (!entity || !entity.hasRelation(relationName)) {
|
|
11305
|
+
continue;
|
|
11306
|
+
}
|
|
11307
|
+
const resultPath = createPath(index, relationName);
|
|
11308
|
+
const observed = this.getRelationQueryObservation(entity, relationName);
|
|
11309
|
+
recordDatabaseQueryObservation(this.createBelongsToParentKeyRelationObservation(
|
|
11310
|
+
entity,
|
|
11311
|
+
relationName,
|
|
11312
|
+
relation,
|
|
11313
|
+
resultPath.slice(0, -1),
|
|
11314
|
+
!relation.constraint
|
|
11315
|
+
));
|
|
11316
|
+
if (observed) {
|
|
11317
|
+
recordDatabaseQueryObservation(this.createNullableSingleRecordRelationObservation(observed, resultPath));
|
|
11318
|
+
continue;
|
|
11319
|
+
}
|
|
11320
|
+
if (relation.constraint) {
|
|
11321
|
+
continue;
|
|
11322
|
+
}
|
|
11323
|
+
const ownerKey = this.getRelationParentValue(entity, relation);
|
|
11324
|
+
if (ownerKey === null || typeof ownerKey === "undefined") {
|
|
11325
|
+
continue;
|
|
11326
|
+
}
|
|
11327
|
+
const predicateDependency = createTablePredicateCacheDependency(
|
|
11328
|
+
related.getConnectionName(),
|
|
11329
|
+
related.definition.table.tableName,
|
|
11330
|
+
relation.ownerKey,
|
|
11331
|
+
ownerKey
|
|
11332
|
+
);
|
|
11333
|
+
const dependencies = predicateDependency ? Object.freeze([
|
|
11334
|
+
createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName),
|
|
11335
|
+
predicateDependency
|
|
11336
|
+
]) : Object.freeze([createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName)]);
|
|
11337
|
+
recordDatabaseQueryObservation(this.createNullableSingleRecordRelationObservation(Object.freeze({
|
|
11338
|
+
connectionName: related.getConnectionName(),
|
|
11339
|
+
dependencies,
|
|
11340
|
+
orderBy: [],
|
|
11341
|
+
patchable: true,
|
|
11342
|
+
predicates: Object.freeze([Object.freeze({
|
|
11343
|
+
column: relation.ownerKey,
|
|
11344
|
+
operator: "=",
|
|
11345
|
+
value: ownerKey
|
|
11346
|
+
})]),
|
|
11347
|
+
selections: [],
|
|
11348
|
+
tableName: related.definition.table.tableName
|
|
11349
|
+
}), resultPath));
|
|
11350
|
+
}
|
|
11351
|
+
}
|
|
11352
|
+
createBelongsToParentKeyRelationObservation(entity, relationName, relation, resultPath, patchable) {
|
|
11353
|
+
const parentKey = entity.toAttributes()[this.definition.primaryKey];
|
|
11354
|
+
if (parentKey === null || typeof parentKey === "undefined") {
|
|
11355
|
+
return void 0;
|
|
11356
|
+
}
|
|
11357
|
+
const predicateDependency = createTablePredicateCacheDependency(
|
|
11358
|
+
this.getConnectionName(),
|
|
11359
|
+
this.definition.table.tableName,
|
|
11360
|
+
this.definition.primaryKey,
|
|
11361
|
+
parentKey
|
|
11362
|
+
);
|
|
11363
|
+
const dependencies = predicateDependency ? Object.freeze([
|
|
11364
|
+
createTableCacheDependency(this.getConnectionName(), this.definition.table.tableName),
|
|
11365
|
+
predicateDependency
|
|
11366
|
+
]) : Object.freeze([createTableCacheDependency(this.getConnectionName(), this.definition.table.tableName)]);
|
|
11367
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11368
|
+
return Object.freeze({
|
|
11369
|
+
connectionName: this.getConnectionName(),
|
|
11370
|
+
dependencies,
|
|
11371
|
+
orderBy: [],
|
|
11372
|
+
patchable,
|
|
11373
|
+
predicates: Object.freeze([Object.freeze({
|
|
11374
|
+
column: this.definition.primaryKey,
|
|
11375
|
+
operator: "=",
|
|
11376
|
+
value: parentKey
|
|
11377
|
+
})]),
|
|
11378
|
+
relation: Object.freeze({
|
|
11379
|
+
foreignKey: relation.foreignKey,
|
|
11380
|
+
kind: "belongsToParentKey",
|
|
11381
|
+
ownerKey: relation.ownerKey,
|
|
11382
|
+
relationKey: relationName,
|
|
11383
|
+
relatedConnectionName: related.getConnectionName(),
|
|
11384
|
+
relatedTableName: related.definition.table.tableName
|
|
11385
|
+
}),
|
|
11386
|
+
resultPath,
|
|
11387
|
+
selections: Object.freeze([Object.freeze({
|
|
11388
|
+
column: relation.foreignKey,
|
|
11389
|
+
resultKey: relation.foreignKey
|
|
11390
|
+
})]),
|
|
11391
|
+
tableName: this.definition.table.tableName
|
|
11392
|
+
});
|
|
11393
|
+
}
|
|
11394
|
+
createNullableSingleRecordRelationObservation(observation, resultPath) {
|
|
11395
|
+
return Object.freeze({
|
|
11396
|
+
...observation,
|
|
11397
|
+
emptyRecordValue: null,
|
|
11398
|
+
limit: 1,
|
|
11399
|
+
resultPath,
|
|
11400
|
+
rowWindowMode: "single"
|
|
11401
|
+
});
|
|
11402
|
+
}
|
|
11403
|
+
rememberHasManyRelationObservation(entity, relationName, relation, related, constrainedPlan, parentKey) {
|
|
11404
|
+
const observation = this.createHasManyRelationObservation(relation, related, constrainedPlan, parentKey);
|
|
11405
|
+
if (!observation) {
|
|
11406
|
+
return;
|
|
11407
|
+
}
|
|
11408
|
+
const observations = relationQueryObservationMetadata.get(entity) ?? /* @__PURE__ */ new Map();
|
|
11409
|
+
observations.set(relationName, observation);
|
|
11410
|
+
relationQueryObservationMetadata.set(entity, observations);
|
|
11411
|
+
}
|
|
11412
|
+
rememberBelongsToRelationObservation(entity, relationName, relation, related, constrainedPlan, ownerKey) {
|
|
11413
|
+
const observation = this.createBelongsToRelationObservation(relation, related, constrainedPlan, ownerKey);
|
|
11414
|
+
if (!observation) {
|
|
11415
|
+
return;
|
|
11416
|
+
}
|
|
11417
|
+
const observations = relationQueryObservationMetadata.get(entity) ?? /* @__PURE__ */ new Map();
|
|
11418
|
+
observations.set(relationName, observation);
|
|
11419
|
+
relationQueryObservationMetadata.set(entity, observations);
|
|
11420
|
+
}
|
|
11421
|
+
getRelationQueryObservation(entity, relationName) {
|
|
11422
|
+
return relationQueryObservationMetadata.get(entity)?.get(relationName);
|
|
11423
|
+
}
|
|
11424
|
+
createHasManyRelationObservation(relation, related, constrainedPlan, parentKey) {
|
|
11425
|
+
if (parentKey === null || typeof parentKey === "undefined") {
|
|
11426
|
+
return void 0;
|
|
11427
|
+
}
|
|
11428
|
+
const parentPlan = withPredicate(constrainedPlan, {
|
|
11429
|
+
kind: "comparison",
|
|
11430
|
+
column: relation.foreignKey,
|
|
11431
|
+
operator: "=",
|
|
11432
|
+
value: parentKey
|
|
11433
|
+
});
|
|
11434
|
+
const dependencies = resolveQueryCacheDependencies(parentPlan, related.getConnectionName());
|
|
11435
|
+
return dependencies ? createDatabaseQueryObservation(parentPlan, related.getConnectionName(), dependencies) : void 0;
|
|
11436
|
+
}
|
|
11437
|
+
createBelongsToRelationObservation(relation, related, constrainedPlan, ownerKey) {
|
|
11438
|
+
if (ownerKey === null || typeof ownerKey === "undefined") {
|
|
11439
|
+
return void 0;
|
|
11440
|
+
}
|
|
11441
|
+
const ownerPlan = withPredicate(constrainedPlan, {
|
|
11442
|
+
kind: "comparison",
|
|
11443
|
+
column: relation.ownerKey,
|
|
11444
|
+
operator: "=",
|
|
11445
|
+
value: ownerKey
|
|
11446
|
+
});
|
|
11447
|
+
const dependencies = resolveQueryCacheDependencies(ownerPlan, related.getConnectionName());
|
|
11448
|
+
return dependencies ? createDatabaseQueryObservation(ownerPlan, related.getConnectionName(), dependencies) : void 0;
|
|
11449
|
+
}
|
|
11450
|
+
recordBelongsToManyRelationObservations(entities, relationName, relation, createPath) {
|
|
11451
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11452
|
+
const pivotTableName = this.resolvePivotTableName(relation.pivotTable);
|
|
11453
|
+
for (let index = 0; index < entities.length; index += 1) {
|
|
11454
|
+
const entity = entities[index];
|
|
11455
|
+
if (!entity || !entity.hasRelation(relationName)) {
|
|
11456
|
+
continue;
|
|
11457
|
+
}
|
|
11458
|
+
const parentKey = this.getRelationParentValue(entity, relation);
|
|
11459
|
+
const predicateDependency = createTablePredicateCacheDependency(
|
|
11460
|
+
this.getConnectionName(),
|
|
11461
|
+
pivotTableName,
|
|
11462
|
+
relation.foreignPivotKey,
|
|
11463
|
+
parentKey
|
|
11464
|
+
);
|
|
11465
|
+
const relatedMetadata = this.createBelongsToManyRelatedObservationMetadata(entity, relationName, relation, related);
|
|
11466
|
+
const dependencies = predicateDependency ? Object.freeze([
|
|
11467
|
+
createTableCacheDependency(this.getConnectionName(), pivotTableName),
|
|
11468
|
+
predicateDependency,
|
|
11469
|
+
...relatedMetadata.dependencies
|
|
11470
|
+
]) : Object.freeze([
|
|
11471
|
+
createTableCacheDependency(this.getConnectionName(), pivotTableName),
|
|
11472
|
+
...relatedMetadata.dependencies
|
|
11473
|
+
]);
|
|
11474
|
+
const relationObservation = Object.freeze({
|
|
11475
|
+
foreignPivotKey: relation.foreignPivotKey,
|
|
11476
|
+
kind: "belongsToMany",
|
|
11477
|
+
pivotAccessor: relation.pivotAccessor,
|
|
11478
|
+
pivotColumns: relation.pivotColumns,
|
|
11479
|
+
pivotOrderBy: relation.pivotOrderBy,
|
|
11480
|
+
relatedConnectionName: related.getConnectionName(),
|
|
11481
|
+
relatedKey: relation.relatedKey,
|
|
11482
|
+
relatedPivotKey: relation.relatedPivotKey,
|
|
11483
|
+
relatedTableName: related.definition.table.tableName
|
|
11484
|
+
});
|
|
11485
|
+
recordDatabaseQueryObservation(Object.freeze({
|
|
11486
|
+
connectionName: this.getConnectionName(),
|
|
11487
|
+
dependencies,
|
|
11488
|
+
orderBy: relation.pivotOrderBy,
|
|
11489
|
+
patchable: relation.pivotWheres.length === 0,
|
|
11490
|
+
predicates: Object.freeze([Object.freeze({
|
|
11491
|
+
column: relation.foreignPivotKey,
|
|
11492
|
+
operator: "=",
|
|
11493
|
+
value: parentKey
|
|
11494
|
+
})]),
|
|
11495
|
+
relation: relationObservation,
|
|
11496
|
+
resultPath: createPath(index, relationName),
|
|
11497
|
+
selections: [],
|
|
11498
|
+
tableName: pivotTableName
|
|
11499
|
+
}));
|
|
11500
|
+
if (relatedMetadata.values.length === 0) {
|
|
11501
|
+
continue;
|
|
11502
|
+
}
|
|
11503
|
+
recordDatabaseQueryObservation(Object.freeze({
|
|
11504
|
+
connectionName: related.getConnectionName(),
|
|
11505
|
+
dependencies: Object.freeze([
|
|
11506
|
+
createTableCacheDependency(related.getConnectionName(), related.definition.table.tableName),
|
|
11507
|
+
...relatedMetadata.dependencies
|
|
11508
|
+
]),
|
|
11509
|
+
orderBy: [],
|
|
11510
|
+
patchable: true,
|
|
11511
|
+
predicates: Object.freeze([Object.freeze({
|
|
11512
|
+
column: relation.relatedKey,
|
|
11513
|
+
operator: "in",
|
|
11514
|
+
value: relatedMetadata.values
|
|
11515
|
+
})]),
|
|
11516
|
+
relation: relationObservation,
|
|
11517
|
+
resultPath: createPath(index, relationName),
|
|
11518
|
+
selections: [],
|
|
11519
|
+
tableName: related.definition.table.tableName
|
|
11520
|
+
}));
|
|
11521
|
+
}
|
|
11522
|
+
}
|
|
11523
|
+
createBelongsToManyRelatedObservationMetadata(entity, relationName, relation, related) {
|
|
11524
|
+
const loaded = entity.getRelation(relationName);
|
|
11525
|
+
const dependencies = [];
|
|
11526
|
+
const values = [];
|
|
11527
|
+
for (const relatedEntity of loaded) {
|
|
11528
|
+
if (!isEntity2(relatedEntity)) {
|
|
11529
|
+
continue;
|
|
11530
|
+
}
|
|
11531
|
+
const relatedValue = relatedEntity.get(relation.relatedKey);
|
|
11532
|
+
values.push(relatedValue);
|
|
11533
|
+
const dependency = createTablePredicateCacheDependency(
|
|
11534
|
+
related.getConnectionName(),
|
|
11535
|
+
related.definition.table.tableName,
|
|
11536
|
+
relation.relatedKey,
|
|
11537
|
+
relatedValue
|
|
11538
|
+
);
|
|
11539
|
+
if (dependency) {
|
|
11540
|
+
dependencies.push(dependency);
|
|
11541
|
+
}
|
|
11542
|
+
}
|
|
11543
|
+
return Object.freeze({
|
|
11544
|
+
dependencies: Object.freeze(dependencies),
|
|
11545
|
+
values: Object.freeze(values)
|
|
11546
|
+
});
|
|
11547
|
+
}
|
|
11548
|
+
createRelationAggregateObservation(aggregate, entity, key) {
|
|
11549
|
+
const metadata = this.getRelationAggregateObservationMetadata(entity, key);
|
|
11550
|
+
if (metadata) {
|
|
11551
|
+
return metadata;
|
|
11552
|
+
}
|
|
11553
|
+
if (aggregate.kind === "count" || aggregate.kind === "exists") {
|
|
11554
|
+
return Object.freeze({
|
|
11555
|
+
kind: "count"
|
|
11556
|
+
});
|
|
11557
|
+
}
|
|
11558
|
+
if (!aggregate.column) {
|
|
11559
|
+
return void 0;
|
|
11560
|
+
}
|
|
11561
|
+
return Object.freeze({
|
|
11562
|
+
column: aggregate.column,
|
|
11563
|
+
kind: aggregate.kind
|
|
11564
|
+
});
|
|
11565
|
+
}
|
|
11566
|
+
setRelationAggregateObservationMetadata(entity, key, metadata) {
|
|
11567
|
+
const byKey = relationAggregateObservationMetadata.get(entity) ?? /* @__PURE__ */ new Map();
|
|
11568
|
+
byKey.set(key, metadata);
|
|
11569
|
+
relationAggregateObservationMetadata.set(entity, byKey);
|
|
11570
|
+
}
|
|
11571
|
+
getRelationAggregateObservationMetadata(entity, key) {
|
|
11572
|
+
return relationAggregateObservationMetadata.get(entity)?.get(key);
|
|
11573
|
+
}
|
|
11574
|
+
createRelationAggregateObservationTarget(entity, relation) {
|
|
11575
|
+
switch (relation.kind) {
|
|
11576
|
+
case "belongsTo": {
|
|
11577
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11578
|
+
return {
|
|
11579
|
+
column: relation.ownerKey,
|
|
11580
|
+
connectionName: related.getConnectionName(),
|
|
11581
|
+
tableName: related.definition.table.tableName,
|
|
11582
|
+
value: this.getRelationParentValue(entity, relation)
|
|
11583
|
+
};
|
|
11584
|
+
}
|
|
11585
|
+
case "hasMany":
|
|
11586
|
+
case "hasOne":
|
|
11587
|
+
case "hasOneOfMany": {
|
|
11588
|
+
const related = this.resolveRelatedRepository(relation.related);
|
|
11589
|
+
return {
|
|
11590
|
+
column: relation.foreignKey,
|
|
11591
|
+
connectionName: related.getConnectionName(),
|
|
11592
|
+
tableName: related.definition.table.tableName,
|
|
11593
|
+
value: this.getRelationParentValue(entity, relation)
|
|
11594
|
+
};
|
|
11595
|
+
}
|
|
11596
|
+
default:
|
|
11597
|
+
return void 0;
|
|
9086
11598
|
}
|
|
9087
11599
|
}
|
|
9088
11600
|
async create(values) {
|
|
@@ -9771,13 +12283,22 @@ var ModelRepository = class _ModelRepository {
|
|
|
9771
12283
|
return;
|
|
9772
12284
|
}
|
|
9773
12285
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9774
|
-
const
|
|
12286
|
+
const observationCount = hasActiveDatabaseDependencyCollector() ? readDatabaseQueryObservationCount() : void 0;
|
|
12287
|
+
const constrainedQuery = this.applyRelationConstraint(relation, related, constraint);
|
|
12288
|
+
const constrainedPlan = typeof observationCount === "number" ? constrainedQuery.getTableQueryBuilder().getPlan() : void 0;
|
|
12289
|
+
const relatedEntities = await constrainedQuery.where(relation.ownerKey, "in", foreignKeys).get();
|
|
12290
|
+
if (typeof observationCount === "number") {
|
|
12291
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12292
|
+
}
|
|
9775
12293
|
const relatedMap = new Map(
|
|
9776
12294
|
relatedEntities.map((entity) => [entity.get(relation.ownerKey), entity])
|
|
9777
12295
|
);
|
|
9778
12296
|
for (const entity of entities) {
|
|
9779
12297
|
const foreignKey = entity.toAttributes()[relation.foreignKey];
|
|
9780
12298
|
entity.setRelation(relationName, relatedMap.get(foreignKey) ?? null);
|
|
12299
|
+
if (constrainedPlan) {
|
|
12300
|
+
this.rememberBelongsToRelationObservation(entity, relationName, relation, related, constrainedPlan, foreignKey);
|
|
12301
|
+
}
|
|
9781
12302
|
}
|
|
9782
12303
|
}
|
|
9783
12304
|
async loadHasManyRelation(entities, relationName, relation, constraint) {
|
|
@@ -9791,7 +12312,13 @@ var ModelRepository = class _ModelRepository {
|
|
|
9791
12312
|
return;
|
|
9792
12313
|
}
|
|
9793
12314
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9794
|
-
const
|
|
12315
|
+
const observationCount = hasActiveDatabaseDependencyCollector() ? readDatabaseQueryObservationCount() : void 0;
|
|
12316
|
+
const constrainedQuery = this.applyRelationConstraint(relation, related, constraint);
|
|
12317
|
+
const constrainedPlan = typeof observationCount === "number" ? constrainedQuery.getTableQueryBuilder().getPlan() : void 0;
|
|
12318
|
+
const relatedEntities = await constrainedQuery.where(relation.foreignKey, "in", localKeys).get();
|
|
12319
|
+
if (typeof observationCount === "number") {
|
|
12320
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12321
|
+
}
|
|
9795
12322
|
const grouped = /* @__PURE__ */ new Map();
|
|
9796
12323
|
for (const relatedEntity of relatedEntities) {
|
|
9797
12324
|
const foreignKey = relatedEntity.get(relation.foreignKey);
|
|
@@ -9802,6 +12329,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
9802
12329
|
for (const entity of entities) {
|
|
9803
12330
|
const localKey = entity.toAttributes()[relation.localKey];
|
|
9804
12331
|
entity.setRelation(relationName, grouped.get(localKey) ?? []);
|
|
12332
|
+
if (constrainedPlan) {
|
|
12333
|
+
this.rememberHasManyRelationObservation(entity, relationName, relation, related, constrainedPlan, localKey);
|
|
12334
|
+
}
|
|
9805
12335
|
}
|
|
9806
12336
|
}
|
|
9807
12337
|
async loadHasOneRelation(entities, relationName, relation, constraint) {
|
|
@@ -9873,8 +12403,12 @@ var ModelRepository = class _ModelRepository {
|
|
|
9873
12403
|
}
|
|
9874
12404
|
return;
|
|
9875
12405
|
}
|
|
12406
|
+
const observationCount = hasActiveDatabaseDependencyCollector() ? readDatabaseQueryObservationCount() : void 0;
|
|
9876
12407
|
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
9877
12408
|
if (pivotRows.length === 0) {
|
|
12409
|
+
if (typeof observationCount === "number") {
|
|
12410
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12411
|
+
}
|
|
9878
12412
|
for (const entity of entities) {
|
|
9879
12413
|
entity.setRelation(relationName, []);
|
|
9880
12414
|
}
|
|
@@ -9884,6 +12418,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
9884
12418
|
pivotRows.map((row) => row[relation.relatedPivotKey]).filter((value) => value !== null && typeof value !== "undefined")
|
|
9885
12419
|
)];
|
|
9886
12420
|
if (relatedIds.length === 0) {
|
|
12421
|
+
if (typeof observationCount === "number") {
|
|
12422
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12423
|
+
}
|
|
9887
12424
|
for (const entity of entities) {
|
|
9888
12425
|
entity.setRelation(relationName, []);
|
|
9889
12426
|
}
|
|
@@ -9891,6 +12428,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
9891
12428
|
}
|
|
9892
12429
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9893
12430
|
const relatedEntities = await this.applyRelationConstraint(relation, related, constraint).where(relation.relatedKey, "in", relatedIds).get();
|
|
12431
|
+
if (typeof observationCount === "number") {
|
|
12432
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12433
|
+
}
|
|
9894
12434
|
const relatedMap = new Map(
|
|
9895
12435
|
relatedEntities.map((entity) => [entity.get(relation.relatedKey), entity])
|
|
9896
12436
|
);
|
|
@@ -10203,31 +12743,53 @@ var ModelRepository = class _ModelRepository {
|
|
|
10203
12743
|
switch (kind) {
|
|
10204
12744
|
case "sum": {
|
|
10205
12745
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
10206
|
-
return
|
|
12746
|
+
return Object.freeze({
|
|
12747
|
+
value: numbers.reduce((sum, value) => sum + value, 0)
|
|
12748
|
+
});
|
|
10207
12749
|
}
|
|
10208
12750
|
case "avg": {
|
|
10209
12751
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
12752
|
+
const sum = numbers.reduce((total, value) => total + value, 0);
|
|
12753
|
+
const metadata = Object.freeze({
|
|
12754
|
+
column: column2,
|
|
12755
|
+
count: numbers.length,
|
|
12756
|
+
kind,
|
|
12757
|
+
sum
|
|
12758
|
+
});
|
|
10210
12759
|
if (numbers.length === 0) {
|
|
10211
|
-
return
|
|
12760
|
+
return Object.freeze({
|
|
12761
|
+
metadata,
|
|
12762
|
+
value: null
|
|
12763
|
+
});
|
|
10212
12764
|
}
|
|
10213
|
-
return
|
|
12765
|
+
return Object.freeze({
|
|
12766
|
+
metadata,
|
|
12767
|
+
value: sum / numbers.length
|
|
12768
|
+
});
|
|
10214
12769
|
}
|
|
10215
12770
|
case "min": {
|
|
10216
12771
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
10217
|
-
|
|
10218
|
-
return null;
|
|
10219
|
-
}
|
|
10220
|
-
return Math.min(...numbers);
|
|
12772
|
+
return this.computeExtremeAggregateValue(kind, column2, numbers);
|
|
10221
12773
|
}
|
|
10222
12774
|
case "max": {
|
|
10223
12775
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
10224
|
-
|
|
10225
|
-
return null;
|
|
10226
|
-
}
|
|
10227
|
-
return Math.max(...numbers);
|
|
12776
|
+
return this.computeExtremeAggregateValue(kind, column2, numbers);
|
|
10228
12777
|
}
|
|
10229
12778
|
}
|
|
10230
12779
|
}
|
|
12780
|
+
computeExtremeAggregateValue(kind, column2, numbers) {
|
|
12781
|
+
const value = numbers.length === 0 ? null : kind === "min" ? Math.min(...numbers) : Math.max(...numbers);
|
|
12782
|
+
const metadata = Object.freeze({
|
|
12783
|
+
column: column2,
|
|
12784
|
+
currentValueCount: typeof value === "number" ? numbers.filter((number) => number === value).length : 0,
|
|
12785
|
+
kind,
|
|
12786
|
+
valueCounts: createAggregateValueCounts(numbers)
|
|
12787
|
+
});
|
|
12788
|
+
return Object.freeze({
|
|
12789
|
+
metadata,
|
|
12790
|
+
value
|
|
12791
|
+
});
|
|
12792
|
+
}
|
|
10231
12793
|
assertNumericAggregateValue(value, kind, column2) {
|
|
10232
12794
|
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
10233
12795
|
throw new DatabaseError(`Relation aggregate "${kind}" requires numeric values for column "${column2}".`);
|
|
@@ -10795,6 +13357,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
10795
13357
|
createBelongsToManyPivotQuery(relation, connection) {
|
|
10796
13358
|
return this.applyPivotQueryConfig(new TableQueryBuilder(relation.pivotTable, connection), relation);
|
|
10797
13359
|
}
|
|
13360
|
+
resolvePivotTableName(pivotTable) {
|
|
13361
|
+
return typeof pivotTable === "string" ? pivotTable : pivotTable.tableName;
|
|
13362
|
+
}
|
|
10798
13363
|
createMorphToManyPivotQuery(relation, connection) {
|
|
10799
13364
|
return this.applyPivotQueryConfig(new TableQueryBuilder(relation.pivotTable, connection), relation);
|
|
10800
13365
|
}
|
|
@@ -14298,14 +16863,14 @@ function getHoloModelReferenceRegistry() {
|
|
|
14298
16863
|
|
|
14299
16864
|
// src/model/serialize.ts
|
|
14300
16865
|
function isSerializableModel(value) {
|
|
14301
|
-
return
|
|
16866
|
+
return typeof value.toJSON === "function";
|
|
14302
16867
|
}
|
|
14303
16868
|
function serializeModels(value) {
|
|
14304
16869
|
if (value instanceof Date || value === null || typeof value !== "object") {
|
|
14305
16870
|
return value;
|
|
14306
16871
|
}
|
|
14307
16872
|
if (isSerializableModel(value)) {
|
|
14308
|
-
return value.toJSON();
|
|
16873
|
+
return serializeModels(value.toJSON());
|
|
14309
16874
|
}
|
|
14310
16875
|
if (Array.isArray(value)) {
|
|
14311
16876
|
return value.map((item) => serializeModels(item));
|