@holo-js/db 0.2.4 → 0.2.5
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 +14 -1
- package/dist/index.mjs +140 -10
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -692,24 +692,36 @@ declare function resetDatabaseQueryCacheBridge(): void;
|
|
|
692
692
|
declare function onDatabaseDependencyInvalidated(listener: DatabaseDependencyInvalidationListener): () => void;
|
|
693
693
|
declare function resetDatabaseDependencyInvalidationListeners(): void;
|
|
694
694
|
declare function collectDatabaseQueryDependencies<TValue>(callback: () => TValue | Promise<TValue>): Promise<DatabaseDependencyCollectionResult<TValue>>;
|
|
695
|
+
declare function hasActiveDatabaseDependencyCollector(): boolean;
|
|
695
696
|
declare function recordDatabaseQueryDependencies(dependencies: readonly string[] | undefined): void;
|
|
697
|
+
declare function hasDatabaseDependencyInvalidationListeners(): boolean;
|
|
696
698
|
declare function notifyDatabaseDependencyInvalidationListeners(event: DatabaseDependencyInvalidationEvent): Promise<void>;
|
|
697
699
|
declare function normalizeQueryCacheConfig(input: QueryCacheTtlInput | QueryCacheConfig): NormalizedQueryCacheConfig;
|
|
698
700
|
declare function createDeterministicQueryCacheKey(statement: CompiledStatement, connectionName: string): string;
|
|
699
701
|
declare function resolveQueryCacheKey(statement: CompiledStatement, connectionName: string, config: NormalizedQueryCacheConfig): string;
|
|
700
702
|
declare function createTableCacheDependency(connectionName: string, tableName: string): string;
|
|
703
|
+
declare function createTableRowCacheDependency(connectionName: string, tableName: string, columnName: string, value: unknown): string | undefined;
|
|
704
|
+
declare function createTableRowWildcardCacheDependency(connectionName: string, tableName: string): string;
|
|
701
705
|
declare function normalizeQueryCacheDependencies(connectionName: string, dependencies: readonly string[]): readonly string[];
|
|
702
706
|
declare function supportsAutomaticPredicateInvalidation(predicate: QueryPredicateNode): boolean;
|
|
703
707
|
declare function supportsAutomaticQueryCacheInvalidation(plan: SelectQueryPlan): boolean;
|
|
704
708
|
declare function inferAutomaticQueryCacheDependencies(plan: SelectQueryPlan, connectionName: string): readonly string[] | undefined;
|
|
709
|
+
declare function inferAutomaticQueryCacheInvalidationDependencies(plan: SelectQueryPlan, connectionName: string): readonly string[];
|
|
710
|
+
declare function inferAutomaticInsertCacheInvalidationDependencies(connectionName: string, tableName: string, rows: readonly Readonly<Record<string, unknown>>[], lastInsertId?: number | string): readonly string[];
|
|
705
711
|
declare function resolveQueryCacheDependencies(plan: SelectQueryPlan, connectionName: string, explicit?: readonly string[]): readonly string[] | undefined;
|
|
706
712
|
declare const queryCacheInternals: {
|
|
707
713
|
collectDatabaseQueryDependencies: typeof collectDatabaseQueryDependencies;
|
|
708
714
|
configureDatabaseQueryCacheBridge: typeof configureDatabaseQueryCacheBridge;
|
|
709
715
|
createDeterministicQueryCacheKey: typeof createDeterministicQueryCacheKey;
|
|
710
716
|
createTableCacheDependency: typeof createTableCacheDependency;
|
|
717
|
+
createTableRowCacheDependency: typeof createTableRowCacheDependency;
|
|
718
|
+
createTableRowWildcardCacheDependency: typeof createTableRowWildcardCacheDependency;
|
|
711
719
|
getQueryCacheBridgeState: typeof getQueryCacheBridgeState;
|
|
720
|
+
hasActiveDatabaseDependencyCollector: typeof hasActiveDatabaseDependencyCollector;
|
|
721
|
+
hasDatabaseDependencyInvalidationListeners: typeof hasDatabaseDependencyInvalidationListeners;
|
|
722
|
+
inferAutomaticInsertCacheInvalidationDependencies: typeof inferAutomaticInsertCacheInvalidationDependencies;
|
|
712
723
|
inferAutomaticQueryCacheDependencies: typeof inferAutomaticQueryCacheDependencies;
|
|
724
|
+
inferAutomaticQueryCacheInvalidationDependencies: typeof inferAutomaticQueryCacheInvalidationDependencies;
|
|
713
725
|
normalizeQueryCacheConfig: typeof normalizeQueryCacheConfig;
|
|
714
726
|
normalizeQueryCacheDependencies: typeof normalizeQueryCacheDependencies;
|
|
715
727
|
notifyDatabaseDependencyInvalidationListeners: typeof notifyDatabaseDependencyInvalidationListeners;
|
|
@@ -1017,7 +1029,8 @@ declare class TableQueryBuilder<TTableOrName extends TableReference = string, TS
|
|
|
1017
1029
|
unsafeQuery<TRow extends Record<string, unknown> = Record<string, unknown>>(statement: Omit<UnsafeStatement, 'source'>): Promise<DriverQueryResult<TRow>>;
|
|
1018
1030
|
unsafeExecute(statement: Omit<UnsafeStatement, 'source'>): Promise<DriverExecutionResult>;
|
|
1019
1031
|
private clone;
|
|
1020
|
-
private
|
|
1032
|
+
private invalidateInsertQueries;
|
|
1033
|
+
private invalidateMutationQueries;
|
|
1021
1034
|
private getCompiler;
|
|
1022
1035
|
private getUnpaginatedRows;
|
|
1023
1036
|
private resolvePrimaryKeyColumn;
|
package/dist/index.mjs
CHANGED
|
@@ -156,6 +156,9 @@ async function collectDatabaseQueryDependencies(callback) {
|
|
|
156
156
|
dependencies: Object.freeze([...dependencies])
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
|
+
function hasActiveDatabaseDependencyCollector() {
|
|
160
|
+
return typeof databaseDependencyCollector.getStore() !== "undefined";
|
|
161
|
+
}
|
|
159
162
|
function recordDatabaseQueryDependencies(dependencies) {
|
|
160
163
|
if (!dependencies || dependencies.length === 0) {
|
|
161
164
|
return;
|
|
@@ -168,6 +171,10 @@ function recordDatabaseQueryDependencies(dependencies) {
|
|
|
168
171
|
active.add(dependency);
|
|
169
172
|
}
|
|
170
173
|
}
|
|
174
|
+
function hasDatabaseDependencyInvalidationListeners() {
|
|
175
|
+
const listeners = getQueryCacheBridgeState().dependencyInvalidationListeners;
|
|
176
|
+
return typeof listeners !== "undefined" && listeners.size > 0;
|
|
177
|
+
}
|
|
171
178
|
async function notifyDatabaseDependencyInvalidationListeners(event) {
|
|
172
179
|
const listeners = getQueryCacheBridgeState().dependencyInvalidationListeners;
|
|
173
180
|
if (!listeners || listeners.size === 0) {
|
|
@@ -232,6 +239,15 @@ function resolveQueryCacheKey(statement, connectionName, config) {
|
|
|
232
239
|
function createTableCacheDependency(connectionName, tableName) {
|
|
233
240
|
return `db:${connectionName}:${tableName}`;
|
|
234
241
|
}
|
|
242
|
+
function createTableRowCacheDependency(connectionName, tableName, columnName, value) {
|
|
243
|
+
if (typeof value === "undefined") {
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
return `db:${connectionName}:${tableName}:row:${columnName}:${encodeURIComponent(JSON.stringify(value))}`;
|
|
247
|
+
}
|
|
248
|
+
function createTableRowWildcardCacheDependency(connectionName, tableName) {
|
|
249
|
+
return `db:${connectionName}:${tableName}:row:*`;
|
|
250
|
+
}
|
|
235
251
|
function normalizeQueryCacheDependencies(connectionName, dependencies) {
|
|
236
252
|
return Object.freeze(dependencies.map((dependency) => {
|
|
237
253
|
return dependency.startsWith("db:") ? dependency : createTableCacheDependency(connectionName, dependency);
|
|
@@ -257,6 +273,42 @@ function supportsAutomaticPredicateInvalidation(predicate) {
|
|
|
257
273
|
return false;
|
|
258
274
|
}
|
|
259
275
|
}
|
|
276
|
+
function getColumnName(column2) {
|
|
277
|
+
const segments = column2.split(".");
|
|
278
|
+
return segments[segments.length - 1] ?? column2;
|
|
279
|
+
}
|
|
280
|
+
function getPrimaryKeyColumn(plan) {
|
|
281
|
+
const columns = plan.source.table?.columns;
|
|
282
|
+
if (!columns) {
|
|
283
|
+
return "id";
|
|
284
|
+
}
|
|
285
|
+
return Object.values(columns).find((column2) => column2.primaryKey)?.name ?? "id";
|
|
286
|
+
}
|
|
287
|
+
function hasDisjunctivePredicate(predicates) {
|
|
288
|
+
return predicates.some((predicate) => {
|
|
289
|
+
if (predicate.boolean === "or") {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
if (predicate.kind !== "group") {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
return predicate.negated === true || hasDisjunctivePredicate(predicate.predicates);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function findExactPrimaryKeyValue(predicates, primaryKeyColumn) {
|
|
299
|
+
for (const predicate of predicates) {
|
|
300
|
+
if (predicate.kind === "comparison" && predicate.operator === "=" && getColumnName(predicate.column) === primaryKeyColumn) {
|
|
301
|
+
return predicate.value;
|
|
302
|
+
}
|
|
303
|
+
if (predicate.kind === "group" && !predicate.negated && predicate.boolean !== "or") {
|
|
304
|
+
const value = findExactPrimaryKeyValue(predicate.predicates, primaryKeyColumn);
|
|
305
|
+
if (typeof value !== "undefined") {
|
|
306
|
+
return value;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return void 0;
|
|
311
|
+
}
|
|
260
312
|
function supportsAutomaticQueryCacheInvalidation(plan) {
|
|
261
313
|
if (plan.joins.length > 0 || plan.unions.length > 0 || plan.having.length > 0) {
|
|
262
314
|
return false;
|
|
@@ -273,10 +325,64 @@ function inferAutomaticQueryCacheDependencies(plan, connectionName) {
|
|
|
273
325
|
if (!supportsAutomaticQueryCacheInvalidation(plan)) {
|
|
274
326
|
return void 0;
|
|
275
327
|
}
|
|
328
|
+
if (!hasDisjunctivePredicate(plan.predicates)) {
|
|
329
|
+
const primaryKeyColumn = getPrimaryKeyColumn(plan);
|
|
330
|
+
const primaryKeyValue = findExactPrimaryKeyValue(plan.predicates, primaryKeyColumn);
|
|
331
|
+
const primaryKeyDependency = createTableRowCacheDependency(
|
|
332
|
+
connectionName,
|
|
333
|
+
plan.source.tableName,
|
|
334
|
+
primaryKeyColumn,
|
|
335
|
+
primaryKeyValue
|
|
336
|
+
);
|
|
337
|
+
if (primaryKeyDependency) {
|
|
338
|
+
return Object.freeze([
|
|
339
|
+
primaryKeyDependency,
|
|
340
|
+
createTableRowWildcardCacheDependency(connectionName, plan.source.tableName)
|
|
341
|
+
]);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
276
344
|
return Object.freeze([
|
|
277
345
|
createTableCacheDependency(connectionName, plan.source.tableName)
|
|
278
346
|
]);
|
|
279
347
|
}
|
|
348
|
+
function inferAutomaticQueryCacheInvalidationDependencies(plan, connectionName) {
|
|
349
|
+
const dependencies = [
|
|
350
|
+
createTableCacheDependency(connectionName, plan.source.tableName)
|
|
351
|
+
];
|
|
352
|
+
if (hasDisjunctivePredicate(plan.predicates)) {
|
|
353
|
+
dependencies.push(createTableRowWildcardCacheDependency(connectionName, plan.source.tableName));
|
|
354
|
+
return Object.freeze(dependencies);
|
|
355
|
+
}
|
|
356
|
+
const primaryKeyColumn = getPrimaryKeyColumn(plan);
|
|
357
|
+
const primaryKeyValue = findExactPrimaryKeyValue(plan.predicates, primaryKeyColumn);
|
|
358
|
+
const primaryKeyDependency = createTableRowCacheDependency(
|
|
359
|
+
connectionName,
|
|
360
|
+
plan.source.tableName,
|
|
361
|
+
primaryKeyColumn,
|
|
362
|
+
primaryKeyValue
|
|
363
|
+
);
|
|
364
|
+
dependencies.push(primaryKeyDependency ?? createTableRowWildcardCacheDependency(connectionName, plan.source.tableName));
|
|
365
|
+
return Object.freeze(dependencies);
|
|
366
|
+
}
|
|
367
|
+
function inferAutomaticInsertCacheInvalidationDependencies(connectionName, tableName, rows, lastInsertId) {
|
|
368
|
+
const dependencies = /* @__PURE__ */ new Set([
|
|
369
|
+
createTableCacheDependency(connectionName, tableName)
|
|
370
|
+
]);
|
|
371
|
+
for (const row of rows) {
|
|
372
|
+
const dependency = createTableRowCacheDependency(connectionName, tableName, "id", row.id);
|
|
373
|
+
if (dependency) {
|
|
374
|
+
dependencies.add(dependency);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
const lastInsertDependency = createTableRowCacheDependency(connectionName, tableName, "id", lastInsertId);
|
|
378
|
+
if (lastInsertDependency) {
|
|
379
|
+
dependencies.add(lastInsertDependency);
|
|
380
|
+
}
|
|
381
|
+
if (dependencies.size === 1) {
|
|
382
|
+
dependencies.add(createTableRowWildcardCacheDependency(connectionName, tableName));
|
|
383
|
+
}
|
|
384
|
+
return Object.freeze([...dependencies]);
|
|
385
|
+
}
|
|
280
386
|
function resolveQueryCacheDependencies(plan, connectionName, explicit) {
|
|
281
387
|
if (explicit && explicit.length > 0) {
|
|
282
388
|
return normalizeQueryCacheDependencies(connectionName, explicit);
|
|
@@ -306,8 +412,14 @@ var queryCacheInternals = {
|
|
|
306
412
|
configureDatabaseQueryCacheBridge,
|
|
307
413
|
createDeterministicQueryCacheKey,
|
|
308
414
|
createTableCacheDependency,
|
|
415
|
+
createTableRowCacheDependency,
|
|
416
|
+
createTableRowWildcardCacheDependency,
|
|
309
417
|
getQueryCacheBridgeState,
|
|
418
|
+
hasActiveDatabaseDependencyCollector,
|
|
419
|
+
hasDatabaseDependencyInvalidationListeners,
|
|
420
|
+
inferAutomaticInsertCacheInvalidationDependencies,
|
|
310
421
|
inferAutomaticQueryCacheDependencies,
|
|
422
|
+
inferAutomaticQueryCacheInvalidationDependencies,
|
|
311
423
|
normalizeQueryCacheConfig,
|
|
312
424
|
normalizeQueryCacheDependencies,
|
|
313
425
|
notifyDatabaseDependencyInvalidationListeners,
|
|
@@ -2809,7 +2921,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
2809
2921
|
async get() {
|
|
2810
2922
|
const statement = this.toSQL();
|
|
2811
2923
|
const cacheConfig = this.queryCacheConfig;
|
|
2812
|
-
const dependencies = this.plan.lockMode ? void 0 : resolveQueryCacheDependencies(
|
|
2924
|
+
const dependencies = this.plan.lockMode || !cacheConfig && !hasActiveDatabaseDependencyCollector() ? void 0 : resolveQueryCacheDependencies(
|
|
2813
2925
|
this.plan,
|
|
2814
2926
|
this.connection.getConnectionName(),
|
|
2815
2927
|
cacheConfig?.invalidate
|
|
@@ -3056,7 +3168,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3056
3168
|
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
3057
3169
|
createInsertQueryPlan(this.source, rows)
|
|
3058
3170
|
));
|
|
3059
|
-
await this.
|
|
3171
|
+
await this.invalidateInsertQueries(rows, result.lastInsertId);
|
|
3060
3172
|
return result;
|
|
3061
3173
|
}
|
|
3062
3174
|
async insertOrIgnore(values) {
|
|
@@ -3064,7 +3176,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3064
3176
|
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
3065
3177
|
createInsertQueryPlan(this.source, rows, { ignoreConflicts: true })
|
|
3066
3178
|
));
|
|
3067
|
-
await this.
|
|
3179
|
+
await this.invalidateInsertQueries(rows, result.lastInsertId);
|
|
3068
3180
|
return result;
|
|
3069
3181
|
}
|
|
3070
3182
|
async insertGetId(values) {
|
|
@@ -3076,7 +3188,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3076
3188
|
const result = await this.connection.executeCompiled(this.getCompiler().compile(
|
|
3077
3189
|
createUpsertQueryPlan(this.source, rows, uniqueBy, updateColumns)
|
|
3078
3190
|
));
|
|
3079
|
-
await this.
|
|
3191
|
+
await this.invalidateInsertQueries(rows, result.lastInsertId);
|
|
3080
3192
|
return result;
|
|
3081
3193
|
}
|
|
3082
3194
|
async increment(column2, amount = 1, extraValues = {}) {
|
|
@@ -3090,7 +3202,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3090
3202
|
createUpdateQueryPlan(this.source, this.plan.predicates, this.normalizeUpdateValues(values))
|
|
3091
3203
|
));
|
|
3092
3204
|
if (result.affectedRows !== 0) {
|
|
3093
|
-
await this.
|
|
3205
|
+
await this.invalidateMutationQueries();
|
|
3094
3206
|
}
|
|
3095
3207
|
return result;
|
|
3096
3208
|
}
|
|
@@ -3102,7 +3214,7 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3102
3214
|
createDeleteQueryPlan(this.source, this.plan.predicates)
|
|
3103
3215
|
));
|
|
3104
3216
|
if (result.affectedRows !== 0) {
|
|
3105
|
-
await this.
|
|
3217
|
+
await this.invalidateMutationQueries();
|
|
3106
3218
|
}
|
|
3107
3219
|
return result;
|
|
3108
3220
|
}
|
|
@@ -3124,10 +3236,28 @@ var TableQueryBuilder = class _TableQueryBuilder {
|
|
|
3124
3236
|
const table = this.source.table ?? this.source.tableName;
|
|
3125
3237
|
return new _TableQueryBuilder(table, this.connection, plan, this.queryCacheConfig);
|
|
3126
3238
|
}
|
|
3127
|
-
async
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3239
|
+
async invalidateInsertQueries(rows, lastInsertId) {
|
|
3240
|
+
if (!getDatabaseQueryCacheBridge() && !hasDatabaseDependencyInvalidationListeners()) {
|
|
3241
|
+
return;
|
|
3242
|
+
}
|
|
3243
|
+
await invalidateQueryCacheDependencies(
|
|
3244
|
+
this.connection,
|
|
3245
|
+
inferAutomaticInsertCacheInvalidationDependencies(
|
|
3246
|
+
this.connection.getConnectionName(),
|
|
3247
|
+
this.source.tableName,
|
|
3248
|
+
rows,
|
|
3249
|
+
lastInsertId
|
|
3250
|
+
)
|
|
3251
|
+
);
|
|
3252
|
+
}
|
|
3253
|
+
async invalidateMutationQueries() {
|
|
3254
|
+
if (!getDatabaseQueryCacheBridge() && !hasDatabaseDependencyInvalidationListeners()) {
|
|
3255
|
+
return;
|
|
3256
|
+
}
|
|
3257
|
+
await invalidateQueryCacheDependencies(
|
|
3258
|
+
this.connection,
|
|
3259
|
+
inferAutomaticQueryCacheInvalidationDependencies(this.plan, this.connection.getConnectionName())
|
|
3260
|
+
);
|
|
3131
3261
|
}
|
|
3132
3262
|
getCompiler() {
|
|
3133
3263
|
const dialect = this.connection.getDialect();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/db",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Holo-JS Framework - portable database, ORM, migrations, factories, and seeders",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"uuid": "^12.0.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@holo-js/db-mysql": "^0.2.
|
|
32
|
-
"@holo-js/db-postgres": "^0.2.
|
|
33
|
-
"@holo-js/db-sqlite": "^0.2.
|
|
31
|
+
"@holo-js/db-mysql": "^0.2.5",
|
|
32
|
+
"@holo-js/db-postgres": "^0.2.5",
|
|
33
|
+
"@holo-js/db-sqlite": "^0.2.5"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@holo-js/db-mysql": {
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@holo-js/db-mysql": "^0.2.
|
|
48
|
-
"@holo-js/db-postgres": "^0.2.
|
|
49
|
-
"@holo-js/db-sqlite": "^0.2.
|
|
47
|
+
"@holo-js/db-mysql": "^0.2.5",
|
|
48
|
+
"@holo-js/db-postgres": "^0.2.5",
|
|
49
|
+
"@holo-js/db-sqlite": "^0.2.5",
|
|
50
50
|
"tsup": "^8.3.5",
|
|
51
51
|
"typescript": "^5.7.2"
|
|
52
52
|
}
|