@holo-js/db 0.2.5 → 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 +279 -6
- package/dist/index.mjs +2639 -204
- 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,20 +145,32 @@ 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
|
}
|
|
159
176
|
function hasActiveDatabaseDependencyCollector() {
|
|
@@ -163,12 +180,227 @@ function recordDatabaseQueryDependencies(dependencies) {
|
|
|
163
180
|
if (!dependencies || dependencies.length === 0) {
|
|
164
181
|
return;
|
|
165
182
|
}
|
|
166
|
-
const
|
|
167
|
-
if (!
|
|
183
|
+
const state = databaseDependencyCollector.getStore();
|
|
184
|
+
if (!state) {
|
|
168
185
|
return;
|
|
169
186
|
}
|
|
170
187
|
for (const dependency of dependencies) {
|
|
171
|
-
|
|
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;
|
|
172
404
|
}
|
|
173
405
|
}
|
|
174
406
|
function hasDatabaseDependencyInvalidationListeners() {
|
|
@@ -239,15 +471,173 @@ function resolveQueryCacheKey(statement, connectionName, config) {
|
|
|
239
471
|
function createTableCacheDependency(connectionName, tableName) {
|
|
240
472
|
return `db:${connectionName}:${tableName}`;
|
|
241
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
|
+
}
|
|
242
512
|
function createTableRowCacheDependency(connectionName, tableName, columnName, value) {
|
|
243
513
|
if (typeof value === "undefined") {
|
|
244
514
|
return void 0;
|
|
245
515
|
}
|
|
246
|
-
return `db:${connectionName}:${tableName}:row:${columnName}:${
|
|
516
|
+
return `db:${connectionName}:${tableName}:row:${columnName}:${encodeDependencyValue(value)}`;
|
|
247
517
|
}
|
|
248
518
|
function createTableRowWildcardCacheDependency(connectionName, tableName) {
|
|
249
519
|
return `db:${connectionName}:${tableName}:row:*`;
|
|
250
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
|
+
}
|
|
251
641
|
function normalizeQueryCacheDependencies(connectionName, dependencies) {
|
|
252
642
|
return Object.freeze(dependencies.map((dependency) => {
|
|
253
643
|
return dependency.startsWith("db:") ? dependency : createTableCacheDependency(connectionName, dependency);
|
|
@@ -309,8 +699,367 @@ function findExactPrimaryKeyValue(predicates, primaryKeyColumn) {
|
|
|
309
699
|
}
|
|
310
700
|
return void 0;
|
|
311
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
|
+
}
|
|
312
1061
|
function supportsAutomaticQueryCacheInvalidation(plan) {
|
|
313
|
-
if (plan.joins.length > 0 || plan.unions.length > 0 || plan
|
|
1062
|
+
if (plan.joins.length > 0 || plan.unions.length > 0 || !isSupportedGroupedCountHaving(plan)) {
|
|
314
1063
|
return false;
|
|
315
1064
|
}
|
|
316
1065
|
if (plan.selections.some((selection) => selection.kind === "raw" || selection.kind === "subquery")) {
|
|
@@ -341,18 +1090,48 @@ function inferAutomaticQueryCacheDependencies(plan, connectionName) {
|
|
|
341
1090
|
]);
|
|
342
1091
|
}
|
|
343
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
|
+
}
|
|
344
1106
|
return Object.freeze([
|
|
345
1107
|
createTableCacheDependency(connectionName, plan.source.tableName)
|
|
346
1108
|
]);
|
|
347
1109
|
}
|
|
348
|
-
function inferAutomaticQueryCacheInvalidationDependencies(plan, connectionName) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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];
|
|
352
1116
|
if (hasDisjunctivePredicate(plan.predicates)) {
|
|
353
1117
|
dependencies.push(createTableRowWildcardCacheDependency(connectionName, plan.source.tableName));
|
|
354
|
-
return Object.freeze(
|
|
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
|
+
});
|
|
355
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);
|
|
356
1135
|
const primaryKeyColumn = getPrimaryKeyColumn(plan);
|
|
357
1136
|
const primaryKeyValue = findExactPrimaryKeyValue(plan.predicates, primaryKeyColumn);
|
|
358
1137
|
const primaryKeyDependency = createTableRowCacheDependency(
|
|
@@ -361,27 +1140,118 @@ function inferAutomaticQueryCacheInvalidationDependencies(plan, connectionName)
|
|
|
361
1140
|
primaryKeyColumn,
|
|
362
1141
|
primaryKeyValue
|
|
363
1142
|
);
|
|
364
|
-
|
|
365
|
-
|
|
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
|
+
});
|
|
366
1193
|
}
|
|
367
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);
|
|
368
1199
|
const dependencies = /* @__PURE__ */ new Set([
|
|
369
|
-
|
|
1200
|
+
tableKey
|
|
370
1201
|
]);
|
|
1202
|
+
const directDependencies = /* @__PURE__ */ new Set();
|
|
1203
|
+
const exactPredicates = /* @__PURE__ */ new Map();
|
|
1204
|
+
const predicates = /* @__PURE__ */ new Map();
|
|
371
1205
|
for (const row of rows) {
|
|
372
1206
|
const dependency = createTableRowCacheDependency(connectionName, tableName, "id", row.id);
|
|
373
1207
|
if (dependency) {
|
|
374
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);
|
|
375
1233
|
}
|
|
376
1234
|
}
|
|
377
1235
|
const lastInsertDependency = createTableRowCacheDependency(connectionName, tableName, "id", lastInsertId);
|
|
378
1236
|
if (lastInsertDependency) {
|
|
379
1237
|
dependencies.add(lastInsertDependency);
|
|
1238
|
+
directDependencies.add(lastInsertDependency);
|
|
380
1239
|
}
|
|
381
1240
|
if (dependencies.size === 1) {
|
|
382
|
-
|
|
1241
|
+
const rowWildcardDependency = createTableRowWildcardCacheDependency(connectionName, tableName);
|
|
1242
|
+
dependencies.add(rowWildcardDependency);
|
|
1243
|
+
directDependencies.add(rowWildcardDependency);
|
|
383
1244
|
}
|
|
384
|
-
return Object.freeze(
|
|
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
|
+
});
|
|
385
1255
|
}
|
|
386
1256
|
function resolveQueryCacheDependencies(plan, connectionName, explicit) {
|
|
387
1257
|
if (explicit && explicit.length > 0) {
|
|
@@ -389,17 +1259,18 @@ function resolveQueryCacheDependencies(plan, connectionName, explicit) {
|
|
|
389
1259
|
}
|
|
390
1260
|
return inferAutomaticQueryCacheDependencies(plan, connectionName);
|
|
391
1261
|
}
|
|
392
|
-
async function invalidateQueryCacheDependencies(connection, dependencies) {
|
|
1262
|
+
async function invalidateQueryCacheDependencies(connection, dependencies, mutations = [], plan) {
|
|
393
1263
|
if (dependencies.length === 0) {
|
|
394
1264
|
return;
|
|
395
1265
|
}
|
|
396
1266
|
const invalidate = async () => {
|
|
397
1267
|
const bridge = getDatabaseQueryCacheBridge();
|
|
398
1268
|
await bridge?.invalidateDependencies(dependencies);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
1269
|
+
if (hasDatabaseDependencyInvalidationListeners()) {
|
|
1270
|
+
await notifyDatabaseDependencyInvalidationListeners(
|
|
1271
|
+
createDatabaseDependencyInvalidationEvent(connection.getConnectionName(), dependencies, mutations, plan?.metadata)
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
403
1274
|
};
|
|
404
1275
|
if (connection.getScope().kind === "root") {
|
|
405
1276
|
await invalidate();
|
|
@@ -408,9 +1279,12 @@ async function invalidateQueryCacheDependencies(connection, dependencies) {
|
|
|
408
1279
|
connection.afterCommit(invalidate);
|
|
409
1280
|
}
|
|
410
1281
|
var queryCacheInternals = {
|
|
411
|
-
collectDatabaseQueryDependencies,
|
|
1282
|
+
collectDatabaseQueryDependencies: collectDatabaseQueryDependenciesInternal,
|
|
412
1283
|
configureDatabaseQueryCacheBridge,
|
|
1284
|
+
createDatabaseMutationEvent,
|
|
1285
|
+
createDatabaseQueryObservation,
|
|
413
1286
|
createDeterministicQueryCacheKey,
|
|
1287
|
+
createTablePredicateCacheDependency,
|
|
414
1288
|
createTableCacheDependency,
|
|
415
1289
|
createTableRowCacheDependency,
|
|
416
1290
|
createTableRowWildcardCacheDependency,
|
|
@@ -418,13 +1292,20 @@ var queryCacheInternals = {
|
|
|
418
1292
|
hasActiveDatabaseDependencyCollector,
|
|
419
1293
|
hasDatabaseDependencyInvalidationListeners,
|
|
420
1294
|
inferAutomaticInsertCacheInvalidationDependencies,
|
|
1295
|
+
inferAutomaticInsertCacheInvalidationPlan,
|
|
421
1296
|
inferAutomaticQueryCacheDependencies,
|
|
422
1297
|
inferAutomaticQueryCacheInvalidationDependencies,
|
|
1298
|
+
inferAutomaticQueryCacheInvalidationPlan,
|
|
423
1299
|
normalizeQueryCacheConfig,
|
|
424
1300
|
normalizeQueryCacheDependencies,
|
|
425
1301
|
notifyDatabaseDependencyInvalidationListeners,
|
|
1302
|
+
disableDatabaseQueryObservationPatching,
|
|
1303
|
+
rebindDatabaseQueryObservationResult,
|
|
1304
|
+
rebindDatabaseQueryObservationScalar,
|
|
1305
|
+
rebindDatabaseQueryObservationScalarList,
|
|
426
1306
|
onDatabaseDependencyInvalidated,
|
|
427
1307
|
recordDatabaseQueryDependencies,
|
|
1308
|
+
recordDatabaseQueryObservation,
|
|
428
1309
|
resolveQueryCacheDependencies,
|
|
429
1310
|
resolveQueryCacheKey,
|
|
430
1311
|
resetDatabaseDependencyInvalidationListeners,
|
|
@@ -800,34 +1681,47 @@ function createInsertQueryPlan(source, values, options = {}) {
|
|
|
800
1681
|
kind: "insert",
|
|
801
1682
|
source,
|
|
802
1683
|
ignoreConflicts: options.ignoreConflicts ?? false,
|
|
1684
|
+
returning: options.returning === true,
|
|
803
1685
|
values: Object.freeze(values.map((value) => Object.freeze({ ...value })))
|
|
804
1686
|
});
|
|
805
1687
|
}
|
|
806
|
-
function createUpsertQueryPlan(source, values, uniqueBy, updateColumns) {
|
|
1688
|
+
function createUpsertQueryPlan(source, values, uniqueBy, updateColumns, options = {}) {
|
|
807
1689
|
return Object.freeze({
|
|
808
1690
|
kind: "upsert",
|
|
809
1691
|
source,
|
|
1692
|
+
returning: options.returning === true,
|
|
810
1693
|
values: Object.freeze(values.map((value) => Object.freeze({ ...value }))),
|
|
811
1694
|
uniqueBy: Object.freeze([...uniqueBy]),
|
|
812
1695
|
updateColumns: Object.freeze([...updateColumns])
|
|
813
1696
|
});
|
|
814
1697
|
}
|
|
815
|
-
function createUpdateQueryPlan(source, predicates, values) {
|
|
1698
|
+
function createUpdateQueryPlan(source, predicates, values, options = {}) {
|
|
816
1699
|
return Object.freeze({
|
|
817
1700
|
kind: "update",
|
|
818
1701
|
source,
|
|
819
1702
|
predicates: Object.freeze([...predicates]),
|
|
1703
|
+
returning: options.returning === true,
|
|
820
1704
|
values: Object.freeze({ ...values })
|
|
821
1705
|
});
|
|
822
1706
|
}
|
|
823
|
-
function createDeleteQueryPlan(source, predicates) {
|
|
1707
|
+
function createDeleteQueryPlan(source, predicates, options = {}) {
|
|
824
1708
|
return Object.freeze({
|
|
825
1709
|
kind: "delete",
|
|
826
1710
|
source,
|
|
827
|
-
predicates: Object.freeze([...predicates])
|
|
1711
|
+
predicates: Object.freeze([...predicates]),
|
|
1712
|
+
returning: options.returning === true
|
|
828
1713
|
});
|
|
829
1714
|
}
|
|
830
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
|
+
|
|
831
1725
|
// src/query/validator.ts
|
|
832
1726
|
var IDENTIFIER_PATTERN = /^[A-Z_]\w*$/i;
|
|
833
1727
|
var OPERATORS = /* @__PURE__ */ new Set([
|
|
@@ -1464,8 +2358,9 @@ var SQLQueryCompiler = class {
|
|
|
1464
2358
|
return `${this.quoteIdentifier(column2)} = ${this.compileUpdateValue(column2, plan.values[column2], bindings)}`;
|
|
1465
2359
|
}).join(", ");
|
|
1466
2360
|
const whereClause = this.compilePredicates(plan.predicates, bindings);
|
|
2361
|
+
const returningClause = this.compileReturningClause(plan.returning === true);
|
|
1467
2362
|
return this.withMetadata({
|
|
1468
|
-
sql: `UPDATE ${this.quoteIdentifier(plan.source.tableName)} SET ${assignments}${whereClause}`,
|
|
2363
|
+
sql: `UPDATE ${this.quoteIdentifier(plan.source.tableName)} SET ${assignments}${whereClause}${returningClause}`,
|
|
1469
2364
|
bindings,
|
|
1470
2365
|
source: `query:update:${plan.source.tableName}`
|
|
1471
2366
|
}, this.createWriteMetadata("update", plan.source.tableName, this.calculatePlanComplexity(plan)));
|
|
@@ -1473,8 +2368,9 @@ var SQLQueryCompiler = class {
|
|
|
1473
2368
|
compileDelete(plan) {
|
|
1474
2369
|
const bindings = [];
|
|
1475
2370
|
const whereClause = this.compilePredicates(plan.predicates, bindings);
|
|
2371
|
+
const returningClause = this.compileReturningClause(plan.returning === true);
|
|
1476
2372
|
return this.withMetadata({
|
|
1477
|
-
sql: `DELETE FROM ${this.quoteIdentifier(plan.source.tableName)}${whereClause}`,
|
|
2373
|
+
sql: `DELETE FROM ${this.quoteIdentifier(plan.source.tableName)}${whereClause}${returningClause}`,
|
|
1478
2374
|
bindings,
|
|
1479
2375
|
source: `query:delete:${plan.source.tableName}`
|
|
1480
2376
|
}, this.createWriteMetadata("delete", plan.source.tableName, this.calculatePlanComplexity(plan)));
|
|
@@ -1751,15 +2647,19 @@ var SQLQueryCompiler = class {
|
|
|
1751
2647
|
return "INSERT INTO";
|
|
1752
2648
|
}
|
|
1753
2649
|
compileInsertSuffix(_plan) {
|
|
1754
|
-
return "";
|
|
2650
|
+
return _plan.returning === true ? " RETURNING *" : "";
|
|
1755
2651
|
}
|
|
1756
2652
|
compileUpsertSuffix(plan, _insertColumns) {
|
|
1757
2653
|
const conflictColumns = plan.uniqueBy.map((column2) => this.quoteIdentifier(column2)).join(", ");
|
|
2654
|
+
const returning = plan.returning === true ? " RETURNING *" : "";
|
|
1758
2655
|
if (plan.updateColumns.length === 0) {
|
|
1759
|
-
return ` ON CONFLICT (${conflictColumns}) DO NOTHING`;
|
|
2656
|
+
return ` ON CONFLICT (${conflictColumns}) DO NOTHING${returning}`;
|
|
1760
2657
|
}
|
|
1761
2658
|
const updates = plan.updateColumns.map((column2) => `${this.quoteIdentifier(column2)} = EXCLUDED.${this.quoteIdentifier(column2)}`).join(", ");
|
|
1762
|
-
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 *" : "";
|
|
1763
2663
|
}
|
|
1764
2664
|
compileHavingExpression(expression) {
|
|
1765
2665
|
const aggregateMatch = expression.match(/^(count|sum|avg|min|max)\((\*|[A-Z_]\w*)\)$/i);
|
|
@@ -1941,12 +2841,18 @@ var PostgresQueryCompiler = class extends SQLQueryCompiler {
|
|
|
1941
2841
|
return lockMode === "update" ? "FOR UPDATE" : "FOR SHARE";
|
|
1942
2842
|
}
|
|
1943
2843
|
compileInsertSuffix(plan) {
|
|
2844
|
+
if (plan.returning === true) {
|
|
2845
|
+
return `${plan.ignoreConflicts ? " ON CONFLICT DO NOTHING" : ""} RETURNING *`;
|
|
2846
|
+
}
|
|
1944
2847
|
const primaryKey = Object.values(plan.source.table?.columns ?? {}).find((column2) => column2.primaryKey)?.name;
|
|
1945
2848
|
const returning = primaryKey ? ` RETURNING ${this.quoteIdentifier(primaryKey)}` : "";
|
|
1946
2849
|
return `${plan.ignoreConflicts ? " ON CONFLICT DO NOTHING" : ""}${returning}`;
|
|
1947
2850
|
}
|
|
1948
2851
|
compileUpsertSuffix(plan, insertColumns) {
|
|
1949
2852
|
const suffix = super.compileUpsertSuffix(plan, insertColumns);
|
|
2853
|
+
if (plan.returning === true) {
|
|
2854
|
+
return suffix;
|
|
2855
|
+
}
|
|
1950
2856
|
const primaryKey = Object.values(plan.source.table?.columns ?? {}).find((column2) => column2.primaryKey)?.name;
|
|
1951
2857
|
return primaryKey ? `${suffix} RETURNING ${this.quoteIdentifier(primaryKey)}` : suffix;
|
|
1952
2858
|
}
|
|
@@ -2224,6 +3130,15 @@ function normalizeDialectWriteValue(dialect, column2, value) {
|
|
|
2224
3130
|
}
|
|
2225
3131
|
|
|
2226
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";
|
|
2227
3142
|
function normalizeAtomicQueryCacheTtl(ttl) {
|
|
2228
3143
|
if (ttl instanceof Date) {
|
|
2229
3144
|
const expiresAt = ttl.getTime();
|
|
@@ -2921,14 +3836,23 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2921
3836
|
async get() {
|
|
2922
3837
|
const statement = this.toSQL();
|
|
2923
3838
|
const cacheConfig = this.queryCacheConfig;
|
|
2924
|
-
const
|
|
3839
|
+
const activeDependencyCollector = hasActiveDatabaseDependencyCollector();
|
|
3840
|
+
const dependencies = this.plan.lockMode || !cacheConfig && !activeDependencyCollector ? void 0 : resolveQueryCacheDependencies(
|
|
2925
3841
|
this.plan,
|
|
2926
3842
|
this.connection.getConnectionName(),
|
|
2927
3843
|
cacheConfig?.invalidate
|
|
2928
3844
|
);
|
|
2929
|
-
|
|
3845
|
+
const observationDependencies = activeDependencyCollector && !this.plan.lockMode ? dependencies ?? inferDatabaseQueryObservationDependencies(this.plan, this.connection.getConnectionName()) : dependencies;
|
|
3846
|
+
const createObservation = dependencies ? createDatabaseQueryObservation : createDatabaseQueryFallbackObservation;
|
|
3847
|
+
recordDatabaseQueryDependencies(observationDependencies);
|
|
2930
3848
|
if (!cacheConfig || this.plan.lockMode) {
|
|
2931
3849
|
const result = await this.connection.queryCompiled(statement);
|
|
3850
|
+
await this.recordCollectedQueryObservation(
|
|
3851
|
+
activeDependencyCollector,
|
|
3852
|
+
observationDependencies,
|
|
3853
|
+
createObservation,
|
|
3854
|
+
result.rows
|
|
3855
|
+
);
|
|
2932
3856
|
return result.rows;
|
|
2933
3857
|
}
|
|
2934
3858
|
const bridge = getDatabaseQueryCacheBridge();
|
|
@@ -2937,7 +3861,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2937
3861
|
}
|
|
2938
3862
|
const cacheKey = resolveQueryCacheKey(statement, this.connection.getConnectionName(), cacheConfig);
|
|
2939
3863
|
if (cacheConfig.flexible) {
|
|
2940
|
-
|
|
3864
|
+
const rows2 = await bridge.flexible(
|
|
2941
3865
|
cacheKey,
|
|
2942
3866
|
cacheConfig.flexible,
|
|
2943
3867
|
async () => {
|
|
@@ -2949,11 +3873,18 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2949
3873
|
dependencies
|
|
2950
3874
|
}
|
|
2951
3875
|
);
|
|
3876
|
+
await this.recordCollectedQueryObservation(
|
|
3877
|
+
activeDependencyCollector,
|
|
3878
|
+
observationDependencies,
|
|
3879
|
+
createObservation,
|
|
3880
|
+
rows2
|
|
3881
|
+
);
|
|
3882
|
+
return rows2;
|
|
2952
3883
|
}
|
|
2953
3884
|
if (typeof cacheConfig.ttl === "undefined") {
|
|
2954
3885
|
throw new ConfigurationError('[@holo-js/db] Query cache config requires "ttl" or "flexible".');
|
|
2955
3886
|
}
|
|
2956
|
-
|
|
3887
|
+
const rows = await bridge.flexible(
|
|
2957
3888
|
cacheKey,
|
|
2958
3889
|
normalizeAtomicQueryCacheTtl(cacheConfig.ttl),
|
|
2959
3890
|
async () => {
|
|
@@ -2965,17 +3896,227 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2965
3896
|
dependencies
|
|
2966
3897
|
}
|
|
2967
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;
|
|
2968
4105
|
}
|
|
2969
4106
|
async first() {
|
|
2970
4107
|
const rows = await this.limit(1).get();
|
|
2971
|
-
|
|
4108
|
+
const row = rows[0];
|
|
4109
|
+
rebindDatabaseQueryObservationResult(rows, row);
|
|
4110
|
+
return row;
|
|
2972
4111
|
}
|
|
2973
4112
|
async sole() {
|
|
2974
4113
|
const rows = await this.limit(2).get();
|
|
2975
4114
|
if (rows.length !== 1) {
|
|
2976
4115
|
throw new CompilerError(`Query expected exactly one row but found ${rows.length}.`);
|
|
2977
4116
|
}
|
|
2978
|
-
|
|
4117
|
+
const row = rows[0];
|
|
4118
|
+
rebindDatabaseQueryObservationResult(rows, row);
|
|
4119
|
+
return row;
|
|
2979
4120
|
}
|
|
2980
4121
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
2981
4122
|
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
@@ -2987,7 +4128,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2987
4128
|
const data = rows.slice(offset, offset + perPage);
|
|
2988
4129
|
const from = data.length === 0 ? null : offset + 1;
|
|
2989
4130
|
const to = data.length === 0 ? null : offset + data.length;
|
|
2990
|
-
|
|
4131
|
+
const result = createPaginator(data, {
|
|
2991
4132
|
total,
|
|
2992
4133
|
perPage,
|
|
2993
4134
|
pageName,
|
|
@@ -2997,6 +4138,14 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2997
4138
|
to,
|
|
2998
4139
|
hasMorePages: offset + data.length < total
|
|
2999
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;
|
|
3000
4149
|
}
|
|
3001
4150
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
3002
4151
|
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
@@ -3009,7 +4158,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3009
4158
|
const data = hasMorePages ? pageRows.slice(0, perPage) : pageRows;
|
|
3010
4159
|
const from = data.length === 0 ? null : offset + 1;
|
|
3011
4160
|
const to = data.length === 0 ? null : offset + data.length;
|
|
3012
|
-
|
|
4161
|
+
const result = createSimplePaginator(data, {
|
|
3013
4162
|
perPage,
|
|
3014
4163
|
pageName,
|
|
3015
4164
|
currentPage: page,
|
|
@@ -3017,6 +4166,15 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3017
4166
|
to,
|
|
3018
4167
|
hasMorePages
|
|
3019
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;
|
|
3020
4178
|
}
|
|
3021
4179
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
3022
4180
|
assertPositiveInteger(perPage, "Per-page value", (message) => new SecurityError(message));
|
|
@@ -3034,12 +4192,32 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3034
4192
|
const hasMorePages = pageRows.length > perPage;
|
|
3035
4193
|
const data = hasMorePages ? pageRows.slice(0, perPage) : pageRows;
|
|
3036
4194
|
const lastRow = data.at(-1);
|
|
3037
|
-
|
|
4195
|
+
const result = createCursorPaginator(data, {
|
|
3038
4196
|
perPage,
|
|
3039
4197
|
cursorName,
|
|
3040
4198
|
nextCursor: hasMorePages && lastRow ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastRow, order.column))) : null,
|
|
3041
4199
|
prevCursor: cursor
|
|
3042
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;
|
|
3043
4221
|
}
|
|
3044
4222
|
async chunk(size, callback) {
|
|
3045
4223
|
assertPositiveInteger(size, "Chunk size", (message) => new SecurityError(message));
|
|
@@ -3103,35 +4281,66 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3103
4281
|
}
|
|
3104
4282
|
}
|
|
3105
4283
|
async count() {
|
|
3106
|
-
|
|
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;
|
|
3107
4290
|
}
|
|
3108
4291
|
async exists() {
|
|
3109
|
-
|
|
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;
|
|
3110
4302
|
}
|
|
3111
4303
|
async doesntExist() {
|
|
3112
|
-
|
|
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;
|
|
3113
4314
|
}
|
|
3114
4315
|
async pluck(column2) {
|
|
3115
4316
|
const rows = await this.get();
|
|
3116
|
-
|
|
4317
|
+
const result = rows.map((row) => row[column2]);
|
|
4318
|
+
rebindDatabaseQueryObservationScalarList(rows, result, column2);
|
|
4319
|
+
return result;
|
|
3117
4320
|
}
|
|
3118
4321
|
async value(column2) {
|
|
3119
4322
|
const row = await this.first();
|
|
3120
|
-
|
|
4323
|
+
const result = row?.[column2];
|
|
4324
|
+
rebindDatabaseQueryObservationScalar(row, result, column2);
|
|
4325
|
+
return result;
|
|
3121
4326
|
}
|
|
3122
4327
|
async valueOrFail(column2) {
|
|
3123
4328
|
const row = await this.first();
|
|
3124
4329
|
if (!row || typeof row[column2] === "undefined") {
|
|
3125
4330
|
throw new CompilerError(`Query returned no value for column "${column2}".`);
|
|
3126
4331
|
}
|
|
3127
|
-
|
|
4332
|
+
const result = row[column2];
|
|
4333
|
+
rebindDatabaseQueryObservationScalar(row, result, column2);
|
|
4334
|
+
return result;
|
|
3128
4335
|
}
|
|
3129
4336
|
async soleValue(column2) {
|
|
3130
4337
|
const row = await this.sole();
|
|
3131
4338
|
if (typeof row[column2] === "undefined") {
|
|
3132
4339
|
throw new CompilerError(`Query returned no value for column "${column2}".`);
|
|
3133
4340
|
}
|
|
3134
|
-
|
|
4341
|
+
const result = row[column2];
|
|
4342
|
+
rebindDatabaseQueryObservationScalar(row, result, column2);
|
|
4343
|
+
return result;
|
|
3135
4344
|
}
|
|
3136
4345
|
async sum(column2) {
|
|
3137
4346
|
return this.aggregateNumeric(column2, "sum");
|
|
@@ -3139,45 +4348,95 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3139
4348
|
async avg(column2) {
|
|
3140
4349
|
const rows = await this.get();
|
|
3141
4350
|
if (rows.length === 0) {
|
|
4351
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4352
|
+
rebindDatabaseQueryObservationAggregate(rows, null, Object.freeze({ column: column2, count: 0, kind: "avg", sum: 0 }));
|
|
4353
|
+
}
|
|
3142
4354
|
return null;
|
|
3143
4355
|
}
|
|
3144
4356
|
const values = this.extractNumericValues(rows, column2, "avg");
|
|
3145
|
-
|
|
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;
|
|
3146
4363
|
}
|
|
3147
4364
|
async min(column2) {
|
|
3148
4365
|
const rows = await this.get();
|
|
3149
4366
|
if (rows.length === 0) {
|
|
4367
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4368
|
+
rebindDatabaseQueryObservationAggregate(rows, null, Object.freeze({ column: column2, kind: "min" }));
|
|
4369
|
+
}
|
|
3150
4370
|
return null;
|
|
3151
4371
|
}
|
|
3152
4372
|
const values = this.extractNumericValues(rows, column2, "min");
|
|
3153
|
-
|
|
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;
|
|
3154
4383
|
}
|
|
3155
4384
|
async max(column2) {
|
|
3156
4385
|
const rows = await this.get();
|
|
3157
4386
|
if (rows.length === 0) {
|
|
4387
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
4388
|
+
rebindDatabaseQueryObservationAggregate(rows, null, Object.freeze({ column: column2, kind: "max" }));
|
|
4389
|
+
}
|
|
3158
4390
|
return null;
|
|
3159
4391
|
}
|
|
3160
4392
|
const values = this.extractNumericValues(rows, column2, "max");
|
|
3161
|
-
|
|
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;
|
|
3162
4403
|
}
|
|
3163
4404
|
async find(value, column2 = "id") {
|
|
3164
4405
|
return this.where(column2, value).limit(1).first();
|
|
3165
4406
|
}
|
|
3166
4407
|
async insert(values) {
|
|
3167
4408
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
3168
|
-
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(
|
|
3169
4415
|
createInsertQueryPlan(this.source, rows)
|
|
3170
4416
|
));
|
|
3171
|
-
await this.invalidateInsertQueries(rows, result.lastInsertId);
|
|
3172
|
-
return
|
|
4417
|
+
await this.invalidateInsertQueries("insert", result.rows?.rows ?? rows, result.lastInsertId);
|
|
4418
|
+
return {
|
|
4419
|
+
affectedRows: result.affectedRows,
|
|
4420
|
+
lastInsertId: result.lastInsertId
|
|
4421
|
+
};
|
|
3173
4422
|
}
|
|
3174
4423
|
async insertOrIgnore(values) {
|
|
3175
4424
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
3176
|
-
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(
|
|
3177
4431
|
createInsertQueryPlan(this.source, rows, { ignoreConflicts: true })
|
|
3178
4432
|
));
|
|
3179
|
-
|
|
3180
|
-
|
|
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
|
+
};
|
|
3181
4440
|
}
|
|
3182
4441
|
async insertGetId(values) {
|
|
3183
4442
|
const result = await this.insert(values);
|
|
@@ -3185,78 +4444,272 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3185
4444
|
}
|
|
3186
4445
|
async upsert(values, uniqueBy, updateColumns = []) {
|
|
3187
4446
|
const rows = Array.isArray(values) ? values.map((value) => this.normalizeWriteRecord(value)) : [this.normalizeWriteRecord(values)];
|
|
3188
|
-
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(
|
|
3189
4454
|
createUpsertQueryPlan(this.source, rows, uniqueBy, updateColumns)
|
|
3190
4455
|
));
|
|
3191
|
-
|
|
3192
|
-
|
|
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
|
+
};
|
|
3193
4463
|
}
|
|
3194
4464
|
async increment(column2, amount = 1, extraValues = {}) {
|
|
3195
4465
|
return this.adjustNumericColumn(column2, amount, extraValues);
|
|
3196
4466
|
}
|
|
3197
|
-
async decrement(column2, amount = 1, extraValues = {}) {
|
|
3198
|
-
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);
|
|
3199
4581
|
}
|
|
3200
|
-
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
if (result.affectedRows !== 0) {
|
|
3205
|
-
await this.invalidateMutationQueries();
|
|
4582
|
+
applyCapturedJsonPathValue(currentValue, path, value) {
|
|
4583
|
+
const segment = path[0];
|
|
4584
|
+
if (typeof segment === "undefined") {
|
|
4585
|
+
return value;
|
|
3206
4586
|
}
|
|
3207
|
-
|
|
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
|
+
});
|
|
3208
4593
|
}
|
|
3209
|
-
|
|
3210
|
-
return
|
|
4594
|
+
isJsonRecord(value) {
|
|
4595
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3211
4596
|
}
|
|
3212
|
-
async
|
|
3213
|
-
const
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
if (result.affectedRows !== 0) {
|
|
3217
|
-
await this.invalidateMutationQueries();
|
|
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;
|
|
3218
4601
|
}
|
|
3219
|
-
|
|
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);
|
|
3220
4622
|
}
|
|
3221
|
-
|
|
3222
|
-
return
|
|
3223
|
-
...statement,
|
|
3224
|
-
unsafe: true,
|
|
3225
|
-
source: `table:${this.source.tableName}`
|
|
3226
|
-
});
|
|
4623
|
+
hasUniqueByValues(row, uniqueBy) {
|
|
4624
|
+
return uniqueBy.every((column2) => Object.prototype.hasOwnProperty.call(row, column2));
|
|
3227
4625
|
}
|
|
3228
|
-
|
|
3229
|
-
return
|
|
3230
|
-
...statement,
|
|
3231
|
-
unsafe: true,
|
|
3232
|
-
source: `table:${this.source.tableName}`
|
|
3233
|
-
});
|
|
4626
|
+
rowsMatchUniqueBy(left, right, uniqueBy) {
|
|
4627
|
+
return uniqueBy.every((column2) => left[column2] === right[column2]);
|
|
3234
4628
|
}
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
4629
|
+
shouldUseReturningMutationRows(hasInvalidationListeners) {
|
|
4630
|
+
return hasInvalidationListeners && this.connection.getCapabilities().returning;
|
|
4631
|
+
}
|
|
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
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
freezeMutationRows(rows) {
|
|
4644
|
+
return Object.freeze(rows.map((row) => Object.freeze({ ...row })));
|
|
4645
|
+
}
|
|
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;
|
|
3238
4652
|
}
|
|
3239
|
-
async invalidateInsertQueries(rows, lastInsertId) {
|
|
3240
|
-
|
|
4653
|
+
async invalidateInsertQueries(kind, rows, lastInsertId, previousRows) {
|
|
4654
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4655
|
+
if (!getDatabaseQueryCacheBridge() && !hasInvalidationListeners) {
|
|
3241
4656
|
return;
|
|
3242
4657
|
}
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
4658
|
+
const mutations = hasInvalidationListeners ? [
|
|
4659
|
+
createDatabaseMutationEvent(
|
|
4660
|
+
kind,
|
|
3246
4661
|
this.connection.getConnectionName(),
|
|
3247
4662
|
this.source.tableName,
|
|
3248
|
-
|
|
3249
|
-
|
|
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
|
|
3250
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
|
|
3251
4684
|
);
|
|
3252
4685
|
}
|
|
3253
|
-
async invalidateMutationQueries() {
|
|
3254
|
-
|
|
4686
|
+
async invalidateMutationQueries(values = {}, capturedRows) {
|
|
4687
|
+
const hasInvalidationListeners = hasDatabaseDependencyInvalidationListeners();
|
|
4688
|
+
if (!getDatabaseQueryCacheBridge() && !hasInvalidationListeners) {
|
|
3255
4689
|
return;
|
|
3256
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
|
+
);
|
|
3257
4698
|
await invalidateQueryCacheDependencies(
|
|
3258
4699
|
this.connection,
|
|
3259
|
-
|
|
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
|
|
3260
4713
|
);
|
|
3261
4714
|
}
|
|
3262
4715
|
getCompiler() {
|
|
@@ -3400,10 +4853,11 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3400
4853
|
}
|
|
3401
4854
|
async aggregateNumeric(column2, kind) {
|
|
3402
4855
|
const rows = await this.get();
|
|
3403
|
-
|
|
3404
|
-
|
|
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 }));
|
|
3405
4859
|
}
|
|
3406
|
-
return
|
|
4860
|
+
return result;
|
|
3407
4861
|
}
|
|
3408
4862
|
extractNumericValues(rows, column2, kind) {
|
|
3409
4863
|
return rows.map((row) => {
|
|
@@ -8219,6 +9673,13 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8219
9673
|
}
|
|
8220
9674
|
async get() {
|
|
8221
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) {
|
|
8222
9683
|
const hasQueryCasts = Object.keys(this.queryCasts).length > 0;
|
|
8223
9684
|
let entities = await Promise.all(
|
|
8224
9685
|
rows.map((row) => hasQueryCasts ? this.repository.retrieveWithCasts(row, this.queryCasts) : this.repository.retrieve(row))
|
|
@@ -8230,39 +9691,76 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8230
9691
|
return this.repository.createCollection(entities);
|
|
8231
9692
|
}
|
|
8232
9693
|
async getJson() {
|
|
8233
|
-
|
|
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;
|
|
8234
9701
|
}
|
|
8235
9702
|
async first() {
|
|
8236
|
-
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);
|
|
8237
9709
|
return entity;
|
|
8238
9710
|
}
|
|
8239
9711
|
async firstJson() {
|
|
8240
|
-
|
|
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;
|
|
8241
9719
|
}
|
|
8242
9720
|
async sole() {
|
|
8243
|
-
const
|
|
8244
|
-
|
|
9721
|
+
const query = this.limit(2);
|
|
9722
|
+
const { collection, rows } = await query.getRowsAndEntities();
|
|
9723
|
+
if (collection.length === 0) {
|
|
8245
9724
|
throw new ModelNotFoundException(this.repository.definition.name, `${this.repository.definition.name} query expected exactly one result but found 0.`);
|
|
8246
9725
|
}
|
|
8247
|
-
if (
|
|
8248
|
-
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}.`);
|
|
8249
9728
|
}
|
|
8250
|
-
|
|
9729
|
+
const entity = collection[0];
|
|
9730
|
+
query.recordSingleRelationObservations(entity);
|
|
9731
|
+
query.recordSingleRelationAggregateObservations(entity);
|
|
9732
|
+
query.rebindRowsToSerializedResult(rows, entity);
|
|
9733
|
+
return entity;
|
|
8251
9734
|
}
|
|
8252
9735
|
async soleJson() {
|
|
8253
|
-
|
|
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;
|
|
8254
9749
|
}
|
|
8255
9750
|
async paginate(perPage = 15, page = 1, options = {}) {
|
|
8256
9751
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
8257
9752
|
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
8258
9753
|
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
8259
|
-
const entities = await this.
|
|
9754
|
+
const { collection: entities, rows } = await this.getUnpaginatedRowsAndEntities();
|
|
8260
9755
|
const total = entities.length;
|
|
8261
9756
|
const offset = (page - 1) * perPage;
|
|
8262
9757
|
const data = entities.slice(offset, offset + perPage);
|
|
8263
9758
|
const from = data.length === 0 ? null : offset + 1;
|
|
8264
9759
|
const to = data.length === 0 ? null : offset + data.length;
|
|
8265
|
-
|
|
9760
|
+
const collection = this.repository.createCollection(data);
|
|
9761
|
+
this.recordPaginatedRelationObservations(collection);
|
|
9762
|
+
this.recordPaginatedRelationAggregateObservations(collection);
|
|
9763
|
+
const result = createPaginator(collection, {
|
|
8266
9764
|
total,
|
|
8267
9765
|
perPage,
|
|
8268
9766
|
pageName,
|
|
@@ -8272,22 +9770,50 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8272
9770
|
to,
|
|
8273
9771
|
hasMorePages: offset + data.length < total
|
|
8274
9772
|
});
|
|
9773
|
+
this.rebindRowsToPaginatedResult(rows, result.data, result.meta, page, pageName, perPage, total, offset);
|
|
9774
|
+
return result;
|
|
8275
9775
|
}
|
|
8276
9776
|
async paginateJson(perPage = 15, page = 1, options = {}) {
|
|
8277
|
-
|
|
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;
|
|
8278
9801
|
}
|
|
8279
9802
|
async simplePaginate(perPage = 15, page = 1, options = {}) {
|
|
8280
9803
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
8281
9804
|
assertPositiveInteger(page, "Page", (message) => new HydrationError(message));
|
|
8282
9805
|
const pageName = normalizePaginationParameterName(options.pageName, "page", (message) => new HydrationError(message));
|
|
8283
|
-
const entities = await this.
|
|
9806
|
+
const { collection: entities, rows } = await this.getUnpaginatedRowsAndEntities();
|
|
8284
9807
|
const offset = (page - 1) * perPage;
|
|
8285
9808
|
const pageEntities = entities.slice(offset, offset + perPage + 1);
|
|
8286
9809
|
const hasMorePages = pageEntities.length > perPage;
|
|
8287
9810
|
const data = hasMorePages ? pageEntities.slice(0, perPage) : pageEntities;
|
|
8288
9811
|
const from = data.length === 0 ? null : offset + 1;
|
|
8289
9812
|
const to = data.length === 0 ? null : offset + data.length;
|
|
8290
|
-
|
|
9813
|
+
const collection = this.repository.createCollection(data);
|
|
9814
|
+
this.recordPaginatedRelationObservations(collection);
|
|
9815
|
+
this.recordPaginatedRelationAggregateObservations(collection);
|
|
9816
|
+
const result = createSimplePaginator(collection, {
|
|
8291
9817
|
perPage,
|
|
8292
9818
|
pageName,
|
|
8293
9819
|
currentPage: page,
|
|
@@ -8295,9 +9821,33 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8295
9821
|
to,
|
|
8296
9822
|
hasMorePages
|
|
8297
9823
|
});
|
|
9824
|
+
this.rebindRowsToSimplePaginatedResult(rows, result.data, result.meta, page, pageName, perPage, entities.length, hasMorePages, offset);
|
|
9825
|
+
return result;
|
|
8298
9826
|
}
|
|
8299
9827
|
async simplePaginateJson(perPage = 15, page = 1, options = {}) {
|
|
8300
|
-
|
|
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;
|
|
8301
9851
|
}
|
|
8302
9852
|
async cursorPaginate(perPage = 15, cursor = null, options = {}) {
|
|
8303
9853
|
assertPositiveInteger(perPage, "Per-page value", (message) => new HydrationError(message));
|
|
@@ -8305,7 +9855,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8305
9855
|
const decodedCursor = decodeValueCursor(cursor, (message) => new HydrationError(message));
|
|
8306
9856
|
const orderedQuery = this.prepareCursorPaginationQuery();
|
|
8307
9857
|
const cursorOrders = orderedQuery.resolveCursorOrders();
|
|
8308
|
-
const entities = await orderedQuery.
|
|
9858
|
+
const { collection: entities, rows } = await orderedQuery.getUnpaginatedRowsAndEntities();
|
|
8309
9859
|
const filteredEntities = decodedCursor ? entities.filter((entity) => isRowAfterCursor(
|
|
8310
9860
|
cursorOrders.map((order) => orderedQuery.readCursorColumnValue(entity, order.column)),
|
|
8311
9861
|
decodedCursor.values,
|
|
@@ -8315,15 +9865,65 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8315
9865
|
const hasMorePages = pageEntities.length > perPage;
|
|
8316
9866
|
const data = hasMorePages ? pageEntities.slice(0, perPage) : pageEntities;
|
|
8317
9867
|
const lastEntity = data.at(-1);
|
|
8318
|
-
|
|
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, {
|
|
8319
9873
|
perPage,
|
|
8320
9874
|
cursorName,
|
|
8321
9875
|
nextCursor: hasMorePages && lastEntity ? encodeValueCursor(cursorOrders.map((order) => orderedQuery.readCursorColumnValue(lastEntity, order.column))) : null,
|
|
8322
9876
|
prevCursor: cursor
|
|
8323
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;
|
|
8324
9889
|
}
|
|
8325
9890
|
async cursorPaginateJson(perPage = 15, cursor = null, options = {}) {
|
|
8326
|
-
|
|
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;
|
|
8327
9927
|
}
|
|
8328
9928
|
async chunk(size, callback) {
|
|
8329
9929
|
assertPositiveInteger(size, "Chunk size", (message) => new HydrationError(message));
|
|
@@ -8387,21 +9987,42 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8387
9987
|
}
|
|
8388
9988
|
}
|
|
8389
9989
|
async count() {
|
|
8390
|
-
|
|
9990
|
+
const collection = await this.get();
|
|
9991
|
+
const result = collection.length;
|
|
9992
|
+
rebindDatabaseQueryObservationAggregate(collection, result, Object.freeze({ kind: "count" }));
|
|
9993
|
+
return result;
|
|
8391
9994
|
}
|
|
8392
9995
|
async exists() {
|
|
8393
|
-
|
|
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;
|
|
8394
10004
|
}
|
|
8395
10005
|
async doesntExist() {
|
|
8396
|
-
|
|
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;
|
|
8397
10014
|
}
|
|
8398
10015
|
async pluck(column2) {
|
|
8399
|
-
const
|
|
8400
|
-
|
|
10016
|
+
const { collection, rows } = await this.getRowsAndEntities();
|
|
10017
|
+
const result = collection.map((entity) => entity.get(column2));
|
|
10018
|
+
rebindDatabaseQueryObservationScalarList(rows, result, column2);
|
|
10019
|
+
return result;
|
|
8401
10020
|
}
|
|
8402
10021
|
async value(column2) {
|
|
8403
10022
|
const entity = await this.first();
|
|
8404
|
-
|
|
10023
|
+
const value = entity?.get(column2);
|
|
10024
|
+
rebindDatabaseQueryObservationScalar(entity, value, column2);
|
|
10025
|
+
return value;
|
|
8405
10026
|
}
|
|
8406
10027
|
async valueOrFail(column2) {
|
|
8407
10028
|
const entity = await this.first();
|
|
@@ -8412,6 +10033,7 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8412
10033
|
if (typeof value === "undefined") {
|
|
8413
10034
|
throw new HydrationError(`${this.repository.definition.name} query returned no value for column "${column2}".`);
|
|
8414
10035
|
}
|
|
10036
|
+
rebindDatabaseQueryObservationScalar(entity, value, column2);
|
|
8415
10037
|
return value;
|
|
8416
10038
|
}
|
|
8417
10039
|
async soleValue(column2) {
|
|
@@ -8420,36 +10042,78 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8420
10042
|
if (typeof value === "undefined") {
|
|
8421
10043
|
throw new HydrationError(`${this.repository.definition.name} query returned no value for column "${column2}".`);
|
|
8422
10044
|
}
|
|
10045
|
+
rebindDatabaseQueryObservationScalar(entity, value, column2);
|
|
8423
10046
|
return value;
|
|
8424
10047
|
}
|
|
8425
10048
|
async sum(column2) {
|
|
8426
10049
|
const entities = await this.get();
|
|
8427
10050
|
if (entities.length === 0) {
|
|
10051
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10052
|
+
rebindDatabaseQueryObservationAggregate(entities, 0, Object.freeze({ column: column2, kind: "sum" }));
|
|
10053
|
+
}
|
|
8428
10054
|
return 0;
|
|
8429
10055
|
}
|
|
8430
|
-
|
|
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;
|
|
8431
10061
|
}
|
|
8432
10062
|
async avg(column2) {
|
|
8433
10063
|
const entities = await this.get();
|
|
8434
10064
|
if (entities.length === 0) {
|
|
10065
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10066
|
+
rebindDatabaseQueryObservationAggregate(entities, null, Object.freeze({ column: column2, count: 0, kind: "avg", sum: 0 }));
|
|
10067
|
+
}
|
|
8435
10068
|
return null;
|
|
8436
10069
|
}
|
|
8437
10070
|
const values = this.extractNumericValues(entities, column2, "avg");
|
|
8438
|
-
|
|
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;
|
|
8439
10077
|
}
|
|
8440
10078
|
async min(column2) {
|
|
8441
10079
|
const entities = await this.get();
|
|
8442
10080
|
if (entities.length === 0) {
|
|
10081
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10082
|
+
rebindDatabaseQueryObservationAggregate(entities, null, Object.freeze({ column: column2, kind: "min" }));
|
|
10083
|
+
}
|
|
8443
10084
|
return null;
|
|
8444
10085
|
}
|
|
8445
|
-
|
|
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;
|
|
8446
10097
|
}
|
|
8447
10098
|
async max(column2) {
|
|
8448
10099
|
const entities = await this.get();
|
|
8449
10100
|
if (entities.length === 0) {
|
|
10101
|
+
if (hasActiveDatabaseDependencyCollector()) {
|
|
10102
|
+
rebindDatabaseQueryObservationAggregate(entities, null, Object.freeze({ column: column2, kind: "max" }));
|
|
10103
|
+
}
|
|
8450
10104
|
return null;
|
|
8451
10105
|
}
|
|
8452
|
-
|
|
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;
|
|
8453
10117
|
}
|
|
8454
10118
|
async firstOrFail() {
|
|
8455
10119
|
const entity = await this.first();
|
|
@@ -8722,68 +10386,296 @@ var ModelQueryBuilder = class _ModelQueryBuilder {
|
|
|
8722
10386
|
column: column2
|
|
8723
10387
|
}));
|
|
8724
10388
|
}
|
|
8725
|
-
parseAggregateRelation(spec) {
|
|
8726
|
-
const [relationPart, aliasPart] = spec.split(/\s+as\s+/i);
|
|
8727
|
-
const relation = relationPart?.trim();
|
|
8728
|
-
const alias = aliasPart?.trim();
|
|
8729
|
-
if (!relation) {
|
|
8730
|
-
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
|
+
});
|
|
8731
10575
|
}
|
|
8732
|
-
|
|
8733
|
-
|
|
10576
|
+
const related = relation.related();
|
|
10577
|
+
if (!this.isQueryableModelReference(related)) {
|
|
10578
|
+
return void 0;
|
|
8734
10579
|
}
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
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;
|
|
8742
10596
|
}
|
|
8743
|
-
return
|
|
10597
|
+
return Object.freeze({
|
|
10598
|
+
orderBy: observation.orderBy,
|
|
10599
|
+
predicates: observation.predicates
|
|
10600
|
+
});
|
|
8744
10601
|
}
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
const relation = this.resolveBelongsToRelation(relatedEntity, resolvedRelationName);
|
|
8748
|
-
const ownerValue = relatedEntity.get(relation.ownerKey);
|
|
8749
|
-
if (ownerValue === null || typeof ownerValue === "undefined") {
|
|
8750
|
-
return boolean === "and" ? this.whereDoesntHave(resolvedRelationName) : this.orWhereDoesntHave(resolvedRelationName);
|
|
8751
|
-
}
|
|
8752
|
-
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";
|
|
8753
10604
|
}
|
|
8754
|
-
|
|
8755
|
-
if (
|
|
8756
|
-
return
|
|
10605
|
+
rebindRowsToSerializedResult(rows, result) {
|
|
10606
|
+
if (!hasActiveDatabaseDependencyCollector()) {
|
|
10607
|
+
return;
|
|
8757
10608
|
}
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
const definition = "definition" in ref ? ref.definition : ref;
|
|
8762
|
-
return definition.table.tableName === relatedDefinition.table.tableName;
|
|
8763
|
-
}).map(([name]) => name);
|
|
8764
|
-
if (candidates.length === 1) {
|
|
8765
|
-
return candidates[0];
|
|
10609
|
+
if (this.canBindRowsToSerializedResult()) {
|
|
10610
|
+
rebindDatabaseQueryObservationResult(rows, result);
|
|
10611
|
+
return;
|
|
8766
10612
|
}
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
10613
|
+
const hydrations = this.createPatchableEagerRelationHydrations();
|
|
10614
|
+
if (hydrations) {
|
|
10615
|
+
rebindDatabaseQueryObservationHydratedResult(
|
|
10616
|
+
rows,
|
|
10617
|
+
result,
|
|
10618
|
+
hydrations.belongsToHydrations ?? Object.freeze([]),
|
|
10619
|
+
hydrations.relatedHydrations
|
|
8770
10620
|
);
|
|
10621
|
+
return;
|
|
8771
10622
|
}
|
|
8772
|
-
|
|
8773
|
-
`Multiple belongs-to relations on model "${this.repository.definition.name}" match related model "${relatedDefinition.name}". Specify the relation name explicitly.`
|
|
8774
|
-
);
|
|
10623
|
+
disableDatabaseQueryObservationPatching(rows);
|
|
8775
10624
|
}
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
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);
|
|
8784
10641
|
}
|
|
8785
|
-
|
|
8786
|
-
|
|
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);
|
|
8787
10679
|
}
|
|
8788
10680
|
prepareCursorPaginationQuery() {
|
|
8789
10681
|
const plan = this.tableQuery.getPlan();
|
|
@@ -8846,6 +10738,8 @@ function setAutomaticEagerLoading(definition, value) {
|
|
|
8846
10738
|
}
|
|
8847
10739
|
|
|
8848
10740
|
// src/model/ModelRepository.ts
|
|
10741
|
+
var relationAggregateObservationMetadata = /* @__PURE__ */ new WeakMap();
|
|
10742
|
+
var relationQueryObservationMetadata = /* @__PURE__ */ new WeakMap();
|
|
8849
10743
|
function hasDefinition(reference) {
|
|
8850
10744
|
return "definition" in reference;
|
|
8851
10745
|
}
|
|
@@ -9190,6 +11084,7 @@ var ModelRepository = class _ModelRepository {
|
|
|
9190
11084
|
if (entities.length === 0 || aggregates.length === 0) {
|
|
9191
11085
|
return;
|
|
9192
11086
|
}
|
|
11087
|
+
const observationCount = hasActiveDatabaseDependencyCollector() ? readDatabaseQueryObservationCount() : void 0;
|
|
9193
11088
|
for (const aggregate of aggregates) {
|
|
9194
11089
|
if (aggregate.relation.includes(".")) {
|
|
9195
11090
|
throw new SecurityError("Nested relation aggregates are not supported yet.");
|
|
@@ -9202,6 +11097,12 @@ var ModelRepository = class _ModelRepository {
|
|
|
9202
11097
|
const parentKey = this.getRelationParentValue(entity, relation);
|
|
9203
11098
|
const count = counts.get(parentKey) ?? 0;
|
|
9204
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
|
+
}
|
|
9205
11106
|
}
|
|
9206
11107
|
continue;
|
|
9207
11108
|
}
|
|
@@ -9211,8 +11112,489 @@ var ModelRepository = class _ModelRepository {
|
|
|
9211
11112
|
const values = await this.getRelationAggregateValues(entities, relation, aggregate);
|
|
9212
11113
|
for (const entity of entities) {
|
|
9213
11114
|
const parentKey = this.getRelationParentValue(entity, relation);
|
|
9214
|
-
|
|
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;
|
|
9215
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;
|
|
9216
11598
|
}
|
|
9217
11599
|
}
|
|
9218
11600
|
async create(values) {
|
|
@@ -9901,13 +12283,22 @@ var ModelRepository = class _ModelRepository {
|
|
|
9901
12283
|
return;
|
|
9902
12284
|
}
|
|
9903
12285
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9904
|
-
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
|
+
}
|
|
9905
12293
|
const relatedMap = new Map(
|
|
9906
12294
|
relatedEntities.map((entity) => [entity.get(relation.ownerKey), entity])
|
|
9907
12295
|
);
|
|
9908
12296
|
for (const entity of entities) {
|
|
9909
12297
|
const foreignKey = entity.toAttributes()[relation.foreignKey];
|
|
9910
12298
|
entity.setRelation(relationName, relatedMap.get(foreignKey) ?? null);
|
|
12299
|
+
if (constrainedPlan) {
|
|
12300
|
+
this.rememberBelongsToRelationObservation(entity, relationName, relation, related, constrainedPlan, foreignKey);
|
|
12301
|
+
}
|
|
9911
12302
|
}
|
|
9912
12303
|
}
|
|
9913
12304
|
async loadHasManyRelation(entities, relationName, relation, constraint) {
|
|
@@ -9921,7 +12312,13 @@ var ModelRepository = class _ModelRepository {
|
|
|
9921
12312
|
return;
|
|
9922
12313
|
}
|
|
9923
12314
|
const related = this.resolveRelatedRepository(relation.related);
|
|
9924
|
-
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
|
+
}
|
|
9925
12322
|
const grouped = /* @__PURE__ */ new Map();
|
|
9926
12323
|
for (const relatedEntity of relatedEntities) {
|
|
9927
12324
|
const foreignKey = relatedEntity.get(relation.foreignKey);
|
|
@@ -9932,6 +12329,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
9932
12329
|
for (const entity of entities) {
|
|
9933
12330
|
const localKey = entity.toAttributes()[relation.localKey];
|
|
9934
12331
|
entity.setRelation(relationName, grouped.get(localKey) ?? []);
|
|
12332
|
+
if (constrainedPlan) {
|
|
12333
|
+
this.rememberHasManyRelationObservation(entity, relationName, relation, related, constrainedPlan, localKey);
|
|
12334
|
+
}
|
|
9935
12335
|
}
|
|
9936
12336
|
}
|
|
9937
12337
|
async loadHasOneRelation(entities, relationName, relation, constraint) {
|
|
@@ -10003,8 +12403,12 @@ var ModelRepository = class _ModelRepository {
|
|
|
10003
12403
|
}
|
|
10004
12404
|
return;
|
|
10005
12405
|
}
|
|
12406
|
+
const observationCount = hasActiveDatabaseDependencyCollector() ? readDatabaseQueryObservationCount() : void 0;
|
|
10006
12407
|
const pivotRows = await this.createBelongsToManyPivotQuery(relation, this.getConnection()).where(relation.foreignPivotKey, "in", parentKeys).get();
|
|
10007
12408
|
if (pivotRows.length === 0) {
|
|
12409
|
+
if (typeof observationCount === "number") {
|
|
12410
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12411
|
+
}
|
|
10008
12412
|
for (const entity of entities) {
|
|
10009
12413
|
entity.setRelation(relationName, []);
|
|
10010
12414
|
}
|
|
@@ -10014,6 +12418,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
10014
12418
|
pivotRows.map((row) => row[relation.relatedPivotKey]).filter((value) => value !== null && typeof value !== "undefined")
|
|
10015
12419
|
)];
|
|
10016
12420
|
if (relatedIds.length === 0) {
|
|
12421
|
+
if (typeof observationCount === "number") {
|
|
12422
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12423
|
+
}
|
|
10017
12424
|
for (const entity of entities) {
|
|
10018
12425
|
entity.setRelation(relationName, []);
|
|
10019
12426
|
}
|
|
@@ -10021,6 +12428,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
10021
12428
|
}
|
|
10022
12429
|
const related = this.resolveRelatedRepository(relation.related);
|
|
10023
12430
|
const relatedEntities = await this.applyRelationConstraint(relation, related, constraint).where(relation.relatedKey, "in", relatedIds).get();
|
|
12431
|
+
if (typeof observationCount === "number") {
|
|
12432
|
+
truncateDatabaseQueryObservations(observationCount);
|
|
12433
|
+
}
|
|
10024
12434
|
const relatedMap = new Map(
|
|
10025
12435
|
relatedEntities.map((entity) => [entity.get(relation.relatedKey), entity])
|
|
10026
12436
|
);
|
|
@@ -10333,31 +12743,53 @@ var ModelRepository = class _ModelRepository {
|
|
|
10333
12743
|
switch (kind) {
|
|
10334
12744
|
case "sum": {
|
|
10335
12745
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
10336
|
-
return
|
|
12746
|
+
return Object.freeze({
|
|
12747
|
+
value: numbers.reduce((sum, value) => sum + value, 0)
|
|
12748
|
+
});
|
|
10337
12749
|
}
|
|
10338
12750
|
case "avg": {
|
|
10339
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
|
+
});
|
|
10340
12759
|
if (numbers.length === 0) {
|
|
10341
|
-
return
|
|
12760
|
+
return Object.freeze({
|
|
12761
|
+
metadata,
|
|
12762
|
+
value: null
|
|
12763
|
+
});
|
|
10342
12764
|
}
|
|
10343
|
-
return
|
|
12765
|
+
return Object.freeze({
|
|
12766
|
+
metadata,
|
|
12767
|
+
value: sum / numbers.length
|
|
12768
|
+
});
|
|
10344
12769
|
}
|
|
10345
12770
|
case "min": {
|
|
10346
12771
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
10347
|
-
|
|
10348
|
-
return null;
|
|
10349
|
-
}
|
|
10350
|
-
return Math.min(...numbers);
|
|
12772
|
+
return this.computeExtremeAggregateValue(kind, column2, numbers);
|
|
10351
12773
|
}
|
|
10352
12774
|
case "max": {
|
|
10353
12775
|
const numbers = values.map((value) => this.assertNumericAggregateValue(value, kind, column2));
|
|
10354
|
-
|
|
10355
|
-
return null;
|
|
10356
|
-
}
|
|
10357
|
-
return Math.max(...numbers);
|
|
12776
|
+
return this.computeExtremeAggregateValue(kind, column2, numbers);
|
|
10358
12777
|
}
|
|
10359
12778
|
}
|
|
10360
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
|
+
}
|
|
10361
12793
|
assertNumericAggregateValue(value, kind, column2) {
|
|
10362
12794
|
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
10363
12795
|
throw new DatabaseError(`Relation aggregate "${kind}" requires numeric values for column "${column2}".`);
|
|
@@ -10925,6 +13357,9 @@ var ModelRepository = class _ModelRepository {
|
|
|
10925
13357
|
createBelongsToManyPivotQuery(relation, connection) {
|
|
10926
13358
|
return this.applyPivotQueryConfig(new TableQueryBuilder(relation.pivotTable, connection), relation);
|
|
10927
13359
|
}
|
|
13360
|
+
resolvePivotTableName(pivotTable) {
|
|
13361
|
+
return typeof pivotTable === "string" ? pivotTable : pivotTable.tableName;
|
|
13362
|
+
}
|
|
10928
13363
|
createMorphToManyPivotQuery(relation, connection) {
|
|
10929
13364
|
return this.applyPivotQueryConfig(new TableQueryBuilder(relation.pivotTable, connection), relation);
|
|
10930
13365
|
}
|
|
@@ -14428,14 +16863,14 @@ function getHoloModelReferenceRegistry() {
|
|
|
14428
16863
|
|
|
14429
16864
|
// src/model/serialize.ts
|
|
14430
16865
|
function isSerializableModel(value) {
|
|
14431
|
-
return
|
|
16866
|
+
return typeof value.toJSON === "function";
|
|
14432
16867
|
}
|
|
14433
16868
|
function serializeModels(value) {
|
|
14434
16869
|
if (value instanceof Date || value === null || typeof value !== "object") {
|
|
14435
16870
|
return value;
|
|
14436
16871
|
}
|
|
14437
16872
|
if (isSerializableModel(value)) {
|
|
14438
|
-
return value.toJSON();
|
|
16873
|
+
return serializeModels(value.toJSON());
|
|
14439
16874
|
}
|
|
14440
16875
|
if (Array.isArray(value)) {
|
|
14441
16876
|
return value.map((item) => serializeModels(item));
|