@tanstack/db 0.5.11 → 0.5.12
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/cjs/SortedMap.cjs +40 -26
- package/dist/cjs/SortedMap.cjs.map +1 -1
- package/dist/cjs/SortedMap.d.cts +10 -15
- package/dist/cjs/collection/change-events.cjs.map +1 -1
- package/dist/cjs/collection/changes.cjs.map +1 -1
- package/dist/cjs/collection/events.cjs.map +1 -1
- package/dist/cjs/collection/events.d.cts +12 -4
- package/dist/cjs/collection/index.cjs +2 -1
- package/dist/cjs/collection/index.cjs.map +1 -1
- package/dist/cjs/collection/indexes.cjs.map +1 -1
- package/dist/cjs/collection/lifecycle.cjs.map +1 -1
- package/dist/cjs/collection/mutations.cjs +5 -2
- package/dist/cjs/collection/mutations.cjs.map +1 -1
- package/dist/cjs/collection/state.cjs +6 -5
- package/dist/cjs/collection/state.cjs.map +1 -1
- package/dist/cjs/collection/state.d.cts +4 -1
- package/dist/cjs/collection/subscription.cjs +60 -53
- package/dist/cjs/collection/subscription.cjs.map +1 -1
- package/dist/cjs/collection/subscription.d.cts +18 -4
- package/dist/cjs/collection/sync.cjs.map +1 -1
- package/dist/cjs/errors.cjs +9 -0
- package/dist/cjs/errors.cjs.map +1 -1
- package/dist/cjs/errors.d.cts +3 -0
- package/dist/cjs/event-emitter.cjs.map +1 -1
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/indexes/auto-index.cjs.map +1 -1
- package/dist/cjs/indexes/base-index.cjs.map +1 -1
- package/dist/cjs/indexes/btree-index.cjs +8 -6
- package/dist/cjs/indexes/btree-index.cjs.map +1 -1
- package/dist/cjs/indexes/lazy-index.cjs.map +1 -1
- package/dist/cjs/indexes/reverse-index.cjs.map +1 -1
- package/dist/cjs/local-only.cjs.map +1 -1
- package/dist/cjs/local-storage.cjs.map +1 -1
- package/dist/cjs/optimistic-action.cjs.map +1 -1
- package/dist/cjs/paced-mutations.cjs.map +1 -1
- package/dist/cjs/proxy.cjs.map +1 -1
- package/dist/cjs/query/builder/functions.cjs.map +1 -1
- package/dist/cjs/query/builder/index.cjs.map +1 -1
- package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -1
- package/dist/cjs/query/compiler/evaluators.cjs.map +1 -1
- package/dist/cjs/query/compiler/expressions.cjs.map +1 -1
- package/dist/cjs/query/compiler/group-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/index.cjs.map +1 -1
- package/dist/cjs/query/compiler/joins.cjs.map +1 -1
- package/dist/cjs/query/compiler/order-by.cjs +91 -38
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/order-by.d.cts +6 -2
- package/dist/cjs/query/compiler/select.cjs.map +1 -1
- package/dist/cjs/query/expression-helpers.cjs.map +1 -1
- package/dist/cjs/query/index.d.cts +1 -1
- package/dist/cjs/query/ir.cjs.map +1 -1
- package/dist/cjs/query/live/collection-config-builder.cjs.map +1 -1
- package/dist/cjs/query/live/collection-registry.cjs.map +1 -1
- package/dist/cjs/query/live/collection-subscriber.cjs +30 -15
- package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
- package/dist/cjs/query/live/internal.cjs.map +1 -1
- package/dist/cjs/query/live-query-collection.cjs.map +1 -1
- package/dist/cjs/query/optimizer.cjs.map +1 -1
- package/dist/cjs/query/predicate-utils.cjs +19 -2
- package/dist/cjs/query/predicate-utils.cjs.map +1 -1
- package/dist/cjs/query/predicate-utils.d.cts +32 -1
- package/dist/cjs/query/subset-dedupe.cjs.map +1 -1
- package/dist/cjs/scheduler.cjs.map +1 -1
- package/dist/cjs/strategies/debounceStrategy.cjs.map +1 -1
- package/dist/cjs/strategies/queueStrategy.cjs.map +1 -1
- package/dist/cjs/strategies/throttleStrategy.cjs.map +1 -1
- package/dist/cjs/transactions.cjs.map +1 -1
- package/dist/cjs/types.d.cts +43 -5
- package/dist/cjs/utils/browser-polyfills.cjs.map +1 -1
- package/dist/cjs/utils/btree.cjs.map +1 -1
- package/dist/cjs/utils/comparison.cjs.map +1 -1
- package/dist/cjs/utils/cursor.cjs +39 -0
- package/dist/cjs/utils/cursor.cjs.map +1 -0
- package/dist/cjs/utils/cursor.d.cts +18 -0
- package/dist/cjs/utils/index-optimization.cjs.map +1 -1
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/esm/SortedMap.d.ts +10 -15
- package/dist/esm/SortedMap.js +40 -26
- package/dist/esm/SortedMap.js.map +1 -1
- package/dist/esm/collection/change-events.js.map +1 -1
- package/dist/esm/collection/changes.js.map +1 -1
- package/dist/esm/collection/events.d.ts +12 -4
- package/dist/esm/collection/events.js.map +1 -1
- package/dist/esm/collection/index.js +2 -1
- package/dist/esm/collection/index.js.map +1 -1
- package/dist/esm/collection/indexes.js.map +1 -1
- package/dist/esm/collection/lifecycle.js.map +1 -1
- package/dist/esm/collection/mutations.js +6 -3
- package/dist/esm/collection/mutations.js.map +1 -1
- package/dist/esm/collection/state.d.ts +4 -1
- package/dist/esm/collection/state.js +6 -5
- package/dist/esm/collection/state.js.map +1 -1
- package/dist/esm/collection/subscription.d.ts +18 -4
- package/dist/esm/collection/subscription.js +61 -54
- package/dist/esm/collection/subscription.js.map +1 -1
- package/dist/esm/collection/sync.js.map +1 -1
- package/dist/esm/errors.d.ts +3 -0
- package/dist/esm/errors.js +9 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/event-emitter.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/indexes/auto-index.js.map +1 -1
- package/dist/esm/indexes/base-index.js.map +1 -1
- package/dist/esm/indexes/btree-index.js +8 -6
- package/dist/esm/indexes/btree-index.js.map +1 -1
- package/dist/esm/indexes/lazy-index.js.map +1 -1
- package/dist/esm/indexes/reverse-index.js.map +1 -1
- package/dist/esm/local-only.js.map +1 -1
- package/dist/esm/local-storage.js.map +1 -1
- package/dist/esm/optimistic-action.js.map +1 -1
- package/dist/esm/paced-mutations.js.map +1 -1
- package/dist/esm/proxy.js.map +1 -1
- package/dist/esm/query/builder/functions.js.map +1 -1
- package/dist/esm/query/builder/index.js.map +1 -1
- package/dist/esm/query/builder/ref-proxy.js.map +1 -1
- package/dist/esm/query/compiler/evaluators.js.map +1 -1
- package/dist/esm/query/compiler/expressions.js.map +1 -1
- package/dist/esm/query/compiler/group-by.js.map +1 -1
- package/dist/esm/query/compiler/index.js.map +1 -1
- package/dist/esm/query/compiler/joins.js.map +1 -1
- package/dist/esm/query/compiler/order-by.d.ts +6 -2
- package/dist/esm/query/compiler/order-by.js +91 -38
- package/dist/esm/query/compiler/order-by.js.map +1 -1
- package/dist/esm/query/compiler/select.js.map +1 -1
- package/dist/esm/query/expression-helpers.js.map +1 -1
- package/dist/esm/query/index.d.ts +1 -1
- package/dist/esm/query/ir.js.map +1 -1
- package/dist/esm/query/live/collection-config-builder.js.map +1 -1
- package/dist/esm/query/live/collection-registry.js.map +1 -1
- package/dist/esm/query/live/collection-subscriber.js +30 -15
- package/dist/esm/query/live/collection-subscriber.js.map +1 -1
- package/dist/esm/query/live/internal.js.map +1 -1
- package/dist/esm/query/live-query-collection.js.map +1 -1
- package/dist/esm/query/optimizer.js.map +1 -1
- package/dist/esm/query/predicate-utils.d.ts +32 -1
- package/dist/esm/query/predicate-utils.js +19 -2
- package/dist/esm/query/predicate-utils.js.map +1 -1
- package/dist/esm/query/subset-dedupe.js.map +1 -1
- package/dist/esm/scheduler.js.map +1 -1
- package/dist/esm/strategies/debounceStrategy.js.map +1 -1
- package/dist/esm/strategies/queueStrategy.js.map +1 -1
- package/dist/esm/strategies/throttleStrategy.js.map +1 -1
- package/dist/esm/transactions.js.map +1 -1
- package/dist/esm/types.d.ts +43 -5
- package/dist/esm/utils/browser-polyfills.js.map +1 -1
- package/dist/esm/utils/btree.js.map +1 -1
- package/dist/esm/utils/comparison.js.map +1 -1
- package/dist/esm/utils/cursor.d.ts +18 -0
- package/dist/esm/utils/cursor.js +39 -0
- package/dist/esm/utils/cursor.js.map +1 -0
- package/dist/esm/utils/index-optimization.js.map +1 -1
- package/dist/esm/utils.js.map +1 -1
- package/package.json +30 -28
- package/src/SortedMap.ts +50 -31
- package/src/collection/change-events.ts +20 -20
- package/src/collection/changes.ts +12 -12
- package/src/collection/events.ts +20 -10
- package/src/collection/index.ts +47 -46
- package/src/collection/indexes.ts +14 -14
- package/src/collection/lifecycle.ts +16 -16
- package/src/collection/mutations.ts +25 -20
- package/src/collection/state.ts +43 -36
- package/src/collection/subscription.ts +114 -83
- package/src/collection/sync.ts +13 -13
- package/src/duplicate-instance-check.ts +1 -1
- package/src/errors.ts +49 -40
- package/src/event-emitter.ts +5 -5
- package/src/index.ts +21 -21
- package/src/indexes/auto-index.ts +11 -11
- package/src/indexes/base-index.ts +13 -13
- package/src/indexes/btree-index.ts +21 -17
- package/src/indexes/index-options.ts +3 -3
- package/src/indexes/lazy-index.ts +8 -8
- package/src/indexes/reverse-index.ts +5 -5
- package/src/local-only.ts +12 -12
- package/src/local-storage.ts +17 -17
- package/src/optimistic-action.ts +5 -5
- package/src/paced-mutations.ts +6 -6
- package/src/proxy.ts +43 -43
- package/src/query/builder/functions.ts +28 -28
- package/src/query/builder/index.ts +22 -22
- package/src/query/builder/ref-proxy.ts +4 -4
- package/src/query/builder/types.ts +8 -8
- package/src/query/compiler/evaluators.ts +9 -9
- package/src/query/compiler/expressions.ts +6 -6
- package/src/query/compiler/group-by.ts +24 -24
- package/src/query/compiler/index.ts +44 -44
- package/src/query/compiler/joins.ts +37 -37
- package/src/query/compiler/order-by.ts +170 -77
- package/src/query/compiler/select.ts +13 -13
- package/src/query/compiler/types.ts +2 -2
- package/src/query/expression-helpers.ts +16 -16
- package/src/query/index.ts +10 -9
- package/src/query/ir.ts +13 -13
- package/src/query/live/collection-config-builder.ts +53 -53
- package/src/query/live/collection-registry.ts +6 -6
- package/src/query/live/collection-subscriber.ts +87 -48
- package/src/query/live/internal.ts +1 -1
- package/src/query/live/types.ts +4 -4
- package/src/query/live-query-collection.ts +15 -15
- package/src/query/optimizer.ts +29 -29
- package/src/query/predicate-utils.ts +105 -50
- package/src/query/subset-dedupe.ts +6 -6
- package/src/scheduler.ts +3 -3
- package/src/strategies/debounceStrategy.ts +6 -6
- package/src/strategies/index.ts +4 -4
- package/src/strategies/queueStrategy.ts +5 -5
- package/src/strategies/throttleStrategy.ts +6 -6
- package/src/strategies/types.ts +2 -2
- package/src/transactions.ts +9 -9
- package/src/types.ts +51 -12
- package/src/utils/array-utils.ts +1 -1
- package/src/utils/browser-polyfills.ts +2 -2
- package/src/utils/btree.ts +22 -22
- package/src/utils/comparison.ts +3 -3
- package/src/utils/cursor.ts +78 -0
- package/src/utils/index-optimization.ts +14 -14
- package/src/utils.ts +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Func, Value } from
|
|
2
|
-
import type { BasicExpression, OrderBy, PropRef } from
|
|
3
|
-
import type { LoadSubsetOptions } from
|
|
1
|
+
import { Func, Value } from './ir.js'
|
|
2
|
+
import type { BasicExpression, OrderBy, PropRef } from './ir.js'
|
|
3
|
+
import type { LoadSubsetOptions } from '../types.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Check if one where clause is a logical subset of another.
|
|
@@ -20,7 +20,7 @@ import type { LoadSubsetOptions } from "../types.js"
|
|
|
20
20
|
*/
|
|
21
21
|
export function isWhereSubset(
|
|
22
22
|
subset: BasicExpression<boolean> | undefined,
|
|
23
|
-
superset: BasicExpression<boolean> | undefined
|
|
23
|
+
superset: BasicExpression<boolean> | undefined,
|
|
24
24
|
): boolean {
|
|
25
25
|
// undefined/missing where clause means "no filter" (all data)
|
|
26
26
|
// Both undefined means subset relationship holds (all data ⊆ all data)
|
|
@@ -44,7 +44,7 @@ export function isWhereSubset(
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function makeDisjunction(
|
|
47
|
-
preds: Array<BasicExpression<boolean
|
|
47
|
+
preds: Array<BasicExpression<boolean>>,
|
|
48
48
|
): BasicExpression<boolean> {
|
|
49
49
|
if (preds.length === 0) {
|
|
50
50
|
return new Value(false)
|
|
@@ -57,14 +57,14 @@ function makeDisjunction(
|
|
|
57
57
|
|
|
58
58
|
function convertInToOr(inField: InField) {
|
|
59
59
|
const equalities = inField.values.map(
|
|
60
|
-
(value) => new Func(`eq`, [inField.ref, new Value(value)])
|
|
60
|
+
(value) => new Func(`eq`, [inField.ref, new Value(value)]),
|
|
61
61
|
)
|
|
62
62
|
return makeDisjunction(equalities)
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function isWhereSubsetInternal(
|
|
66
66
|
subset: BasicExpression<boolean>,
|
|
67
|
-
superset: BasicExpression<boolean
|
|
67
|
+
superset: BasicExpression<boolean>,
|
|
68
68
|
): boolean {
|
|
69
69
|
// If subset is false it is requesting no data,
|
|
70
70
|
// thus the result set is empty
|
|
@@ -83,7 +83,7 @@ function isWhereSubsetInternal(
|
|
|
83
83
|
// Example: (age > 20) ⊆ (age > 10 AND status = 'active') is false (doesn't imply status condition)
|
|
84
84
|
if (superset.type === `func` && superset.name === `and`) {
|
|
85
85
|
return superset.args.every((arg) =>
|
|
86
|
-
isWhereSubsetInternal(subset, arg as BasicExpression<boolean>)
|
|
86
|
+
isWhereSubsetInternal(subset, arg as BasicExpression<boolean>),
|
|
87
87
|
)
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -91,7 +91,7 @@ function isWhereSubsetInternal(
|
|
|
91
91
|
if (subset.type === `func` && subset.name === `and`) {
|
|
92
92
|
// For (A AND B) ⊆ C, since (A AND B) implies A, we check if any conjunct implies C
|
|
93
93
|
return subset.args.some((arg) =>
|
|
94
|
-
isWhereSubsetInternal(arg as BasicExpression<boolean>, superset)
|
|
94
|
+
isWhereSubsetInternal(arg as BasicExpression<boolean>, superset),
|
|
95
95
|
)
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -114,7 +114,7 @@ function isWhereSubsetInternal(
|
|
|
114
114
|
// Handle OR in subset: (A OR B) is subset of C only if both A and B are subsets of C
|
|
115
115
|
if (subset.type === `func` && subset.name === `or`) {
|
|
116
116
|
return subset.args.every((arg) =>
|
|
117
|
-
isWhereSubsetInternal(arg as BasicExpression<boolean>, superset)
|
|
117
|
+
isWhereSubsetInternal(arg as BasicExpression<boolean>, superset),
|
|
118
118
|
)
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -123,7 +123,7 @@ function isWhereSubsetInternal(
|
|
|
123
123
|
// If subset is contained in any disjunct, it's contained in the union
|
|
124
124
|
if (superset.type === `func` && superset.name === `or`) {
|
|
125
125
|
return superset.args.some((arg) =>
|
|
126
|
-
isWhereSubsetInternal(subset, arg as BasicExpression<boolean>)
|
|
126
|
+
isWhereSubsetInternal(subset, arg as BasicExpression<boolean>),
|
|
127
127
|
)
|
|
128
128
|
}
|
|
129
129
|
|
|
@@ -145,7 +145,7 @@ function isWhereSubsetInternal(
|
|
|
145
145
|
subsetFunc,
|
|
146
146
|
subsetField.value,
|
|
147
147
|
supersetFunc,
|
|
148
|
-
supersetField.value
|
|
148
|
+
supersetField.value,
|
|
149
149
|
)
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -205,8 +205,8 @@ function combineWherePredicates(
|
|
|
205
205
|
predicates: Array<BasicExpression<boolean>>,
|
|
206
206
|
operation: `and` | `or`,
|
|
207
207
|
simplifyFn: (
|
|
208
|
-
preds: Array<BasicExpression<boolean
|
|
209
|
-
) => BasicExpression<boolean> | null
|
|
208
|
+
preds: Array<BasicExpression<boolean>>,
|
|
209
|
+
) => BasicExpression<boolean> | null,
|
|
210
210
|
): BasicExpression<boolean> {
|
|
211
211
|
const emptyValue = operation === `and` ? true : false
|
|
212
212
|
const identityValue = operation === `and` ? true : false
|
|
@@ -293,7 +293,7 @@ function combineWherePredicates(
|
|
|
293
293
|
* @returns Combined predicate representing the union
|
|
294
294
|
*/
|
|
295
295
|
export function unionWherePredicates(
|
|
296
|
-
predicates: Array<BasicExpression<boolean
|
|
296
|
+
predicates: Array<BasicExpression<boolean>>,
|
|
297
297
|
): BasicExpression<boolean> {
|
|
298
298
|
return combineWherePredicates(predicates, `or`, unionSameFieldPredicates)
|
|
299
299
|
}
|
|
@@ -337,7 +337,7 @@ export function unionWherePredicates(
|
|
|
337
337
|
*/
|
|
338
338
|
export function minusWherePredicates(
|
|
339
339
|
fromPredicate: BasicExpression<boolean> | undefined,
|
|
340
|
-
subtractPredicate: BasicExpression<boolean> | undefined
|
|
340
|
+
subtractPredicate: BasicExpression<boolean> | undefined,
|
|
341
341
|
): BasicExpression<boolean> | null {
|
|
342
342
|
// If nothing to subtract, return the original
|
|
343
343
|
if (subtractPredicate === undefined) {
|
|
@@ -367,20 +367,20 @@ export function minusWherePredicates(
|
|
|
367
367
|
// Try to detect and handle common conditions
|
|
368
368
|
const commonConditions = findCommonConditions(
|
|
369
369
|
fromPredicate,
|
|
370
|
-
subtractPredicate
|
|
370
|
+
subtractPredicate,
|
|
371
371
|
)
|
|
372
372
|
if (commonConditions.length > 0) {
|
|
373
373
|
// Extract predicates without common conditions
|
|
374
374
|
const fromWithoutCommon = removeConditions(fromPredicate, commonConditions)
|
|
375
375
|
const subtractWithoutCommon = removeConditions(
|
|
376
376
|
subtractPredicate,
|
|
377
|
-
commonConditions
|
|
377
|
+
commonConditions,
|
|
378
378
|
)
|
|
379
379
|
|
|
380
380
|
// Recursively compute difference on simplified predicates
|
|
381
381
|
const simplifiedDifference = minusWherePredicates(
|
|
382
382
|
fromWithoutCommon,
|
|
383
|
-
subtractWithoutCommon
|
|
383
|
+
subtractWithoutCommon,
|
|
384
384
|
)
|
|
385
385
|
|
|
386
386
|
if (simplifiedDifference !== null) {
|
|
@@ -406,7 +406,7 @@ export function minusWherePredicates(
|
|
|
406
406
|
*/
|
|
407
407
|
function minusSameFieldPredicates(
|
|
408
408
|
fromPred: Func,
|
|
409
|
-
subtractPred: Func
|
|
409
|
+
subtractPred: Func,
|
|
410
410
|
): BasicExpression<boolean> | null {
|
|
411
411
|
// Extract field information
|
|
412
412
|
const fromField =
|
|
@@ -439,8 +439,8 @@ function minusSameFieldPredicates(
|
|
|
439
439
|
subtractInField.values,
|
|
440
440
|
v,
|
|
441
441
|
subtractInField.primitiveSet ?? null,
|
|
442
|
-
subtractInField.areAllPrimitives
|
|
443
|
-
)
|
|
442
|
+
subtractInField.areAllPrimitives,
|
|
443
|
+
),
|
|
444
444
|
)
|
|
445
445
|
|
|
446
446
|
if (remainingValues.length === 0) {
|
|
@@ -468,7 +468,7 @@ function minusSameFieldPredicates(
|
|
|
468
468
|
const subtractValue = (subtractField as { ref: PropRef; value: any }).value
|
|
469
469
|
|
|
470
470
|
const remainingValues = fromInField.values.filter(
|
|
471
|
-
(v) => !areValuesEqual(v, subtractValue)
|
|
471
|
+
(v) => !areValuesEqual(v, subtractValue),
|
|
472
472
|
)
|
|
473
473
|
|
|
474
474
|
if (remainingValues.length === 0) {
|
|
@@ -517,7 +517,7 @@ function minusSameFieldPredicates(
|
|
|
517
517
|
fromPred,
|
|
518
518
|
fromComp.value,
|
|
519
519
|
subtractPred,
|
|
520
|
-
subtractComp.value
|
|
520
|
+
subtractComp.value,
|
|
521
521
|
)
|
|
522
522
|
return result
|
|
523
523
|
}
|
|
@@ -533,7 +533,7 @@ function minusRangePredicates(
|
|
|
533
533
|
fromFunc: Func,
|
|
534
534
|
fromValue: any,
|
|
535
535
|
subtractFunc: Func,
|
|
536
|
-
subtractValue: any
|
|
536
|
+
subtractValue: any,
|
|
537
537
|
): BasicExpression<boolean> | null {
|
|
538
538
|
const fromOp = fromFunc.name as `gt` | `gte` | `lt` | `lte` | `eq`
|
|
539
539
|
const subtractOp = subtractFunc.name as `gt` | `gte` | `lt` | `lte` | `eq`
|
|
@@ -712,7 +712,7 @@ function minusRangePredicates(
|
|
|
712
712
|
*/
|
|
713
713
|
export function isOrderBySubset(
|
|
714
714
|
subset: OrderBy | undefined,
|
|
715
|
-
superset: OrderBy | undefined
|
|
715
|
+
superset: OrderBy | undefined,
|
|
716
716
|
): boolean {
|
|
717
717
|
// No ordering requirement is always satisfied
|
|
718
718
|
if (!subset || subset.length === 0) {
|
|
@@ -742,7 +742,7 @@ export function isOrderBySubset(
|
|
|
742
742
|
if (
|
|
743
743
|
!areCompareOptionsEqual(
|
|
744
744
|
subClause.compareOptions,
|
|
745
|
-
superClause.compareOptions
|
|
745
|
+
superClause.compareOptions,
|
|
746
746
|
)
|
|
747
747
|
) {
|
|
748
748
|
return false
|
|
@@ -756,6 +756,9 @@ export function isOrderBySubset(
|
|
|
756
756
|
* Check if one limit is a subset of another.
|
|
757
757
|
* Returns true if the subset limit requirements are satisfied by the superset limit.
|
|
758
758
|
*
|
|
759
|
+
* Note: This function does NOT consider offset. For offset-aware subset checking,
|
|
760
|
+
* use `isOffsetLimitSubset` instead.
|
|
761
|
+
*
|
|
759
762
|
* @example
|
|
760
763
|
* isLimitSubset(10, 20) // true (requesting 10 items when 20 are available)
|
|
761
764
|
* isLimitSubset(20, 10) // false (requesting 20 items when only 10 are available)
|
|
@@ -767,7 +770,7 @@ export function isOrderBySubset(
|
|
|
767
770
|
*/
|
|
768
771
|
export function isLimitSubset(
|
|
769
772
|
subset: number | undefined,
|
|
770
|
-
superset: number | undefined
|
|
773
|
+
superset: number | undefined,
|
|
771
774
|
): boolean {
|
|
772
775
|
// Unlimited superset satisfies any limit requirement
|
|
773
776
|
if (superset === undefined) {
|
|
@@ -785,7 +788,57 @@ export function isLimitSubset(
|
|
|
785
788
|
}
|
|
786
789
|
|
|
787
790
|
/**
|
|
788
|
-
* Check if one
|
|
791
|
+
* Check if one offset+limit range is a subset of another.
|
|
792
|
+
* Returns true if the subset range is fully contained within the superset range.
|
|
793
|
+
*
|
|
794
|
+
* A query with `{limit: 10, offset: 0}` loads rows [0, 10).
|
|
795
|
+
* A query with `{limit: 10, offset: 20}` loads rows [20, 30).
|
|
796
|
+
*
|
|
797
|
+
* For subset to be satisfied by superset:
|
|
798
|
+
* - Superset must start at or before subset (superset.offset <= subset.offset)
|
|
799
|
+
* - Superset must end at or after subset (superset.offset + superset.limit >= subset.offset + subset.limit)
|
|
800
|
+
*
|
|
801
|
+
* @example
|
|
802
|
+
* isOffsetLimitSubset({ offset: 0, limit: 5 }, { offset: 0, limit: 10 }) // true
|
|
803
|
+
* isOffsetLimitSubset({ offset: 5, limit: 5 }, { offset: 0, limit: 10 }) // true (rows 5-9 within 0-9)
|
|
804
|
+
* isOffsetLimitSubset({ offset: 5, limit: 10 }, { offset: 0, limit: 10 }) // false (rows 5-14 exceed 0-9)
|
|
805
|
+
* isOffsetLimitSubset({ offset: 20, limit: 10 }, { offset: 0, limit: 10 }) // false (rows 20-29 outside 0-9)
|
|
806
|
+
*
|
|
807
|
+
* @param subset - The offset+limit requirements to check
|
|
808
|
+
* @param superset - The offset+limit that might satisfy the requirements
|
|
809
|
+
* @returns true if subset range is fully contained within superset range
|
|
810
|
+
*/
|
|
811
|
+
export function isOffsetLimitSubset(
|
|
812
|
+
subset: { offset?: number; limit?: number },
|
|
813
|
+
superset: { offset?: number; limit?: number },
|
|
814
|
+
): boolean {
|
|
815
|
+
const subsetOffset = subset.offset ?? 0
|
|
816
|
+
const supersetOffset = superset.offset ?? 0
|
|
817
|
+
|
|
818
|
+
// Superset must start at or before subset
|
|
819
|
+
if (supersetOffset > subsetOffset) {
|
|
820
|
+
return false
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// If superset is unlimited, it covers everything from its offset onwards
|
|
824
|
+
if (superset.limit === undefined) {
|
|
825
|
+
return true
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// If subset is unlimited but superset has a limit, subset can't be satisfied
|
|
829
|
+
if (subset.limit === undefined) {
|
|
830
|
+
return false
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Both have limits - check if subset range is within superset range
|
|
834
|
+
const subsetEnd = subsetOffset + subset.limit
|
|
835
|
+
const supersetEnd = supersetOffset + superset.limit
|
|
836
|
+
|
|
837
|
+
return subsetEnd <= supersetEnd
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Check if one predicate (where + orderBy + limit + offset) is a subset of another.
|
|
789
842
|
* Returns true if all aspects of the subset predicate are satisfied by the superset.
|
|
790
843
|
*
|
|
791
844
|
* @example
|
|
@@ -800,7 +853,7 @@ export function isLimitSubset(
|
|
|
800
853
|
*/
|
|
801
854
|
export function isPredicateSubset(
|
|
802
855
|
subset: LoadSubsetOptions,
|
|
803
|
-
superset: LoadSubsetOptions
|
|
856
|
+
superset: LoadSubsetOptions,
|
|
804
857
|
): boolean {
|
|
805
858
|
// When the superset has a limit, we can only determine subset relationship
|
|
806
859
|
// if the where clauses are equal (not just subset relationship).
|
|
@@ -813,9 +866,9 @@ export function isPredicateSubset(
|
|
|
813
866
|
// The top 10 items matching 'search%' might include items outside the overall top 10.
|
|
814
867
|
//
|
|
815
868
|
// However, if the where clauses are equal, then the subset relationship can
|
|
816
|
-
// be determined by orderBy and
|
|
817
|
-
// Example: superset = {where: status='active', limit: 10, orderBy: desc}
|
|
818
|
-
// subset = {where: status='active', limit: 5, orderBy: desc}
|
|
869
|
+
// be determined by orderBy, limit, and offset:
|
|
870
|
+
// Example: superset = {where: status='active', limit: 10, offset: 0, orderBy: desc}
|
|
871
|
+
// subset = {where: status='active', limit: 5, offset: 0, orderBy: desc}
|
|
819
872
|
// The top 5 active items ARE contained in the top 10 active items.
|
|
820
873
|
if (superset.limit !== undefined) {
|
|
821
874
|
// For limited supersets, where clauses must be equal
|
|
@@ -824,15 +877,17 @@ export function isPredicateSubset(
|
|
|
824
877
|
}
|
|
825
878
|
return (
|
|
826
879
|
isOrderBySubset(subset.orderBy, superset.orderBy) &&
|
|
827
|
-
|
|
880
|
+
isOffsetLimitSubset(subset, superset)
|
|
828
881
|
)
|
|
829
882
|
}
|
|
830
883
|
|
|
831
884
|
// For unlimited supersets, use the normal subset logic
|
|
885
|
+
// Still need to consider offset - an unlimited query with offset only covers
|
|
886
|
+
// rows from that offset onwards
|
|
832
887
|
return (
|
|
833
888
|
isWhereSubset(subset.where, superset.where) &&
|
|
834
889
|
isOrderBySubset(subset.orderBy, superset.orderBy) &&
|
|
835
|
-
|
|
890
|
+
isOffsetLimitSubset(subset, superset)
|
|
836
891
|
)
|
|
837
892
|
}
|
|
838
893
|
|
|
@@ -842,7 +897,7 @@ export function isPredicateSubset(
|
|
|
842
897
|
*/
|
|
843
898
|
function areWhereClausesEqual(
|
|
844
899
|
a: BasicExpression<boolean> | undefined,
|
|
845
|
-
b: BasicExpression<boolean> | undefined
|
|
900
|
+
b: BasicExpression<boolean> | undefined,
|
|
846
901
|
): boolean {
|
|
847
902
|
if (a === undefined && b === undefined) {
|
|
848
903
|
return true
|
|
@@ -863,7 +918,7 @@ function areWhereClausesEqual(
|
|
|
863
918
|
*/
|
|
864
919
|
function findCommonConditions(
|
|
865
920
|
predicate1: BasicExpression<boolean>,
|
|
866
|
-
predicate2: BasicExpression<boolean
|
|
921
|
+
predicate2: BasicExpression<boolean>,
|
|
867
922
|
): Array<BasicExpression<boolean>> {
|
|
868
923
|
const conditions1 = extractAllConditions(predicate1)
|
|
869
924
|
const conditions2 = extractAllConditions(predicate2)
|
|
@@ -889,7 +944,7 @@ function findCommonConditions(
|
|
|
889
944
|
* Extract all individual conditions from a predicate, flattening AND operations.
|
|
890
945
|
*/
|
|
891
946
|
function extractAllConditions(
|
|
892
|
-
predicate: BasicExpression<boolean
|
|
947
|
+
predicate: BasicExpression<boolean>,
|
|
893
948
|
): Array<BasicExpression<boolean>> {
|
|
894
949
|
if (predicate.type === `func` && predicate.name === `and`) {
|
|
895
950
|
const conditions: Array<BasicExpression<boolean>> = []
|
|
@@ -908,14 +963,14 @@ function extractAllConditions(
|
|
|
908
963
|
*/
|
|
909
964
|
function removeConditions(
|
|
910
965
|
predicate: BasicExpression<boolean>,
|
|
911
|
-
conditionsToRemove: Array<BasicExpression<boolean
|
|
966
|
+
conditionsToRemove: Array<BasicExpression<boolean>>,
|
|
912
967
|
): BasicExpression<boolean> | undefined {
|
|
913
968
|
if (predicate.type === `func` && predicate.name === `and`) {
|
|
914
969
|
const remainingArgs = predicate.args.filter(
|
|
915
970
|
(arg) =>
|
|
916
971
|
!conditionsToRemove.some((cond) =>
|
|
917
|
-
areExpressionsEqual(arg as BasicExpression<boolean>, cond)
|
|
918
|
-
)
|
|
972
|
+
areExpressionsEqual(arg as BasicExpression<boolean>, cond),
|
|
973
|
+
),
|
|
919
974
|
)
|
|
920
975
|
|
|
921
976
|
if (remainingArgs.length === 0) {
|
|
@@ -940,7 +995,7 @@ function removeConditions(
|
|
|
940
995
|
* Flattens nested AND operations to avoid unnecessary nesting.
|
|
941
996
|
*/
|
|
942
997
|
function combineConditions(
|
|
943
|
-
conditions: Array<BasicExpression<boolean
|
|
998
|
+
conditions: Array<BasicExpression<boolean>>,
|
|
944
999
|
): BasicExpression<boolean> {
|
|
945
1000
|
if (conditions.length === 0) {
|
|
946
1001
|
return { type: `val`, value: true } as BasicExpression<boolean>
|
|
@@ -977,7 +1032,7 @@ function combineConditions(
|
|
|
977
1032
|
function findPredicateWithOperator(
|
|
978
1033
|
predicates: Array<BasicExpression<boolean>>,
|
|
979
1034
|
operator: string,
|
|
980
|
-
value: any
|
|
1035
|
+
value: any,
|
|
981
1036
|
): BasicExpression<boolean> | undefined {
|
|
982
1037
|
return predicates.find((p) => {
|
|
983
1038
|
if (p.type === `func`) {
|
|
@@ -1012,7 +1067,7 @@ function areExpressionsEqual(a: BasicExpression, b: BasicExpression): boolean {
|
|
|
1012
1067
|
return false
|
|
1013
1068
|
}
|
|
1014
1069
|
return aFunc.args.every((arg, i) =>
|
|
1015
|
-
areExpressionsEqual(arg, bFunc.args[i]!)
|
|
1070
|
+
areExpressionsEqual(arg, bFunc.args[i]!),
|
|
1016
1071
|
)
|
|
1017
1072
|
}
|
|
1018
1073
|
|
|
@@ -1086,7 +1141,7 @@ function arrayIncludesWithSet(
|
|
|
1086
1141
|
array: Array<any>,
|
|
1087
1142
|
value: any,
|
|
1088
1143
|
primitiveSet: Set<any> | null,
|
|
1089
|
-
arrayIsAllPrimitives?: boolean
|
|
1144
|
+
arrayIsAllPrimitives?: boolean,
|
|
1090
1145
|
): boolean {
|
|
1091
1146
|
// Fast path: use pre-built Set for O(1) lookup
|
|
1092
1147
|
if (primitiveSet) {
|
|
@@ -1124,7 +1179,7 @@ function minValue(a: any, b: any): any {
|
|
|
1124
1179
|
|
|
1125
1180
|
function areCompareOptionsEqual(
|
|
1126
1181
|
a: { direction?: `asc` | `desc`; [key: string]: any },
|
|
1127
|
-
b: { direction?: `asc` | `desc`; [key: string]: any }
|
|
1182
|
+
b: { direction?: `asc` | `desc`; [key: string]: any },
|
|
1128
1183
|
): boolean {
|
|
1129
1184
|
// For now, just compare direction - could be enhanced for other options
|
|
1130
1185
|
return a.direction === b.direction
|
|
@@ -1215,7 +1270,7 @@ function isComparisonSubset(
|
|
|
1215
1270
|
subsetFunc: Func,
|
|
1216
1271
|
subsetValue: any,
|
|
1217
1272
|
supersetFunc: Func,
|
|
1218
|
-
supersetValue: any
|
|
1273
|
+
supersetValue: any,
|
|
1219
1274
|
): boolean {
|
|
1220
1275
|
const subOp = subsetFunc.name
|
|
1221
1276
|
const superOp = supersetFunc.name
|
|
@@ -1283,7 +1338,7 @@ function isComparisonSubset(
|
|
|
1283
1338
|
}
|
|
1284
1339
|
|
|
1285
1340
|
function groupPredicatesByField(
|
|
1286
|
-
predicates: Array<BasicExpression<boolean
|
|
1341
|
+
predicates: Array<BasicExpression<boolean>>,
|
|
1287
1342
|
): Map<string | null, Array<BasicExpression<boolean>>> {
|
|
1288
1343
|
const groups = new Map<string | null, Array<BasicExpression<boolean>>>()
|
|
1289
1344
|
|
|
@@ -1310,7 +1365,7 @@ function groupPredicatesByField(
|
|
|
1310
1365
|
}
|
|
1311
1366
|
|
|
1312
1367
|
function unionSameFieldPredicates(
|
|
1313
|
-
predicates: Array<BasicExpression<boolean
|
|
1368
|
+
predicates: Array<BasicExpression<boolean>>,
|
|
1314
1369
|
): BasicExpression<boolean> | null {
|
|
1315
1370
|
if (predicates.length === 1) {
|
|
1316
1371
|
return predicates[0]!
|
|
@@ -1436,7 +1491,7 @@ function unionSameFieldPredicates(
|
|
|
1436
1491
|
return (p as Func).name === `in`
|
|
1437
1492
|
}
|
|
1438
1493
|
return false
|
|
1439
|
-
})
|
|
1494
|
+
})!,
|
|
1440
1495
|
)
|
|
1441
1496
|
}
|
|
1442
1497
|
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
isWhereSubset,
|
|
4
4
|
minusWherePredicates,
|
|
5
5
|
unionWherePredicates,
|
|
6
|
-
} from
|
|
7
|
-
import type { BasicExpression } from
|
|
8
|
-
import type { LoadSubsetOptions } from
|
|
6
|
+
} from './predicate-utils.js'
|
|
7
|
+
import type { BasicExpression } from './ir.js'
|
|
8
|
+
import type { LoadSubsetOptions } from '../types.js'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Deduplicated wrapper for a loadSubset function.
|
|
@@ -34,7 +34,7 @@ import type { LoadSubsetOptions } from "../types.js"
|
|
|
34
34
|
export class DeduplicatedLoadSubset {
|
|
35
35
|
// The underlying loadSubset function to wrap
|
|
36
36
|
private readonly _loadSubset: (
|
|
37
|
-
options: LoadSubsetOptions
|
|
37
|
+
options: LoadSubsetOptions,
|
|
38
38
|
) => true | Promise<void>
|
|
39
39
|
|
|
40
40
|
// An optional callback function that is invoked when a loadSubset call is deduplicated.
|
|
@@ -101,7 +101,7 @@ export class DeduplicatedLoadSubset {
|
|
|
101
101
|
// Check against limited calls
|
|
102
102
|
if (options.limit !== undefined) {
|
|
103
103
|
const alreadyLoaded = this.limitedCalls.some((loaded) =>
|
|
104
|
-
isPredicateSubset(options, loaded)
|
|
104
|
+
isPredicateSubset(options, loaded),
|
|
105
105
|
)
|
|
106
106
|
|
|
107
107
|
if (alreadyLoaded) {
|
|
@@ -113,7 +113,7 @@ export class DeduplicatedLoadSubset {
|
|
|
113
113
|
// Check against in-flight calls using the same subset logic as resolved calls
|
|
114
114
|
// This prevents duplicate requests when concurrent calls have subset relationships
|
|
115
115
|
const matchingInflight = this.inflightCalls.find((inflight) =>
|
|
116
|
-
isPredicateSubset(options, inflight.options)
|
|
116
|
+
isPredicateSubset(options, inflight.options),
|
|
117
117
|
)
|
|
118
118
|
|
|
119
119
|
if (matchingInflight !== undefined) {
|
package/src/scheduler.ts
CHANGED
|
@@ -54,7 +54,7 @@ export class Scheduler {
|
|
|
54
54
|
* Get or create the state bucket for a context.
|
|
55
55
|
*/
|
|
56
56
|
private getOrCreateContext(
|
|
57
|
-
contextId: SchedulerContextId
|
|
57
|
+
contextId: SchedulerContextId,
|
|
58
58
|
): SchedulerContextState {
|
|
59
59
|
let context = this.contexts.get(contextId)
|
|
60
60
|
if (!context) {
|
|
@@ -166,8 +166,8 @@ export class Scheduler {
|
|
|
166
166
|
if (!ranThisPass) {
|
|
167
167
|
throw new Error(
|
|
168
168
|
`Scheduler detected unresolved dependencies for context ${String(
|
|
169
|
-
contextId
|
|
170
|
-
)}
|
|
169
|
+
contextId,
|
|
170
|
+
)}.`,
|
|
171
171
|
)
|
|
172
172
|
}
|
|
173
173
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LiteDebouncer } from
|
|
2
|
-
import type { DebounceStrategy, DebounceStrategyOptions } from
|
|
3
|
-
import type { Transaction } from
|
|
1
|
+
import { LiteDebouncer } from '@tanstack/pacer-lite/lite-debouncer'
|
|
2
|
+
import type { DebounceStrategy, DebounceStrategyOptions } from './types'
|
|
3
|
+
import type { Transaction } from '../transactions'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a debounce strategy that delays transaction execution until after
|
|
@@ -26,18 +26,18 @@ import type { Transaction } from "../transactions"
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export function debounceStrategy(
|
|
29
|
-
options: DebounceStrategyOptions
|
|
29
|
+
options: DebounceStrategyOptions,
|
|
30
30
|
): DebounceStrategy {
|
|
31
31
|
const debouncer = new LiteDebouncer(
|
|
32
32
|
(callback: () => Transaction) => callback(),
|
|
33
|
-
options
|
|
33
|
+
options,
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
return {
|
|
37
37
|
_type: `debounce`,
|
|
38
38
|
options,
|
|
39
39
|
execute: <T extends object = Record<string, unknown>>(
|
|
40
|
-
fn: () => Transaction<T
|
|
40
|
+
fn: () => Transaction<T>,
|
|
41
41
|
) => {
|
|
42
42
|
debouncer.maybeExecute(fn as () => Transaction)
|
|
43
43
|
},
|
package/src/strategies/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Export all strategy factories
|
|
2
|
-
export { debounceStrategy } from
|
|
3
|
-
export { queueStrategy } from
|
|
4
|
-
export { throttleStrategy } from
|
|
2
|
+
export { debounceStrategy } from './debounceStrategy'
|
|
3
|
+
export { queueStrategy } from './queueStrategy'
|
|
4
|
+
export { throttleStrategy } from './throttleStrategy'
|
|
5
5
|
|
|
6
6
|
// Export strategy types
|
|
7
7
|
export type {
|
|
@@ -14,4 +14,4 @@ export type {
|
|
|
14
14
|
ThrottleStrategy,
|
|
15
15
|
ThrottleStrategyOptions,
|
|
16
16
|
StrategyOptions,
|
|
17
|
-
} from
|
|
17
|
+
} from './types'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LiteQueuer } from
|
|
2
|
-
import type { QueueStrategy, QueueStrategyOptions } from
|
|
3
|
-
import type { Transaction } from
|
|
1
|
+
import { LiteQueuer } from '@tanstack/pacer-lite/lite-queuer'
|
|
2
|
+
import type { QueueStrategy, QueueStrategyOptions } from './types'
|
|
3
|
+
import type { Transaction } from '../transactions'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a queue strategy that processes all mutations in order with proper serialization.
|
|
@@ -71,14 +71,14 @@ export function queueStrategy(options?: QueueStrategyOptions): QueueStrategy {
|
|
|
71
71
|
addItemsTo: options?.addItemsTo ?? `back`, // Default FIFO: add to back
|
|
72
72
|
getItemsFrom: options?.getItemsFrom ?? `front`, // Default FIFO: get from front
|
|
73
73
|
started: true, // Start processing immediately
|
|
74
|
-
}
|
|
74
|
+
},
|
|
75
75
|
)
|
|
76
76
|
|
|
77
77
|
return {
|
|
78
78
|
_type: `queue`,
|
|
79
79
|
options,
|
|
80
80
|
execute: <T extends object = Record<string, unknown>>(
|
|
81
|
-
fn: () => Transaction<T
|
|
81
|
+
fn: () => Transaction<T>,
|
|
82
82
|
) => {
|
|
83
83
|
// Add the transaction-creating function to the queue
|
|
84
84
|
queuer.addItem(fn as () => Transaction)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LiteThrottler } from
|
|
2
|
-
import type { ThrottleStrategy, ThrottleStrategyOptions } from
|
|
3
|
-
import type { Transaction } from
|
|
1
|
+
import { LiteThrottler } from '@tanstack/pacer-lite/lite-throttler'
|
|
2
|
+
import type { ThrottleStrategy, ThrottleStrategyOptions } from './types'
|
|
3
|
+
import type { Transaction } from '../transactions'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a throttle strategy that ensures transactions are evenly spaced
|
|
@@ -46,18 +46,18 @@ import type { Transaction } from "../transactions"
|
|
|
46
46
|
* ```
|
|
47
47
|
*/
|
|
48
48
|
export function throttleStrategy(
|
|
49
|
-
options: ThrottleStrategyOptions
|
|
49
|
+
options: ThrottleStrategyOptions,
|
|
50
50
|
): ThrottleStrategy {
|
|
51
51
|
const throttler = new LiteThrottler(
|
|
52
52
|
(callback: () => Transaction) => callback(),
|
|
53
|
-
options
|
|
53
|
+
options,
|
|
54
54
|
)
|
|
55
55
|
|
|
56
56
|
return {
|
|
57
57
|
_type: `throttle`,
|
|
58
58
|
options,
|
|
59
59
|
execute: <T extends object = Record<string, unknown>>(
|
|
60
|
-
fn: () => Transaction<T
|
|
60
|
+
fn: () => Transaction<T>,
|
|
61
61
|
) => {
|
|
62
62
|
throttler.maybeExecute(fn as () => Transaction)
|
|
63
63
|
},
|
package/src/strategies/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Transaction } from
|
|
1
|
+
import type { Transaction } from '../transactions'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Base strategy interface that all strategy implementations must conform to
|
|
@@ -13,7 +13,7 @@ export interface BaseStrategy<TName extends string = string> {
|
|
|
13
13
|
* @returns The result of the function execution (if applicable)
|
|
14
14
|
*/
|
|
15
15
|
execute: <T extends object = Record<string, unknown>>(
|
|
16
|
-
fn: () => Transaction<T
|
|
16
|
+
fn: () => Transaction<T>,
|
|
17
17
|
) => void | Promise<void>
|
|
18
18
|
|
|
19
19
|
/**
|
package/src/transactions.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { createDeferred } from
|
|
2
|
-
import
|
|
1
|
+
import { createDeferred } from './deferred'
|
|
2
|
+
import './duplicate-instance-check'
|
|
3
3
|
import {
|
|
4
4
|
MissingMutationFunctionError,
|
|
5
5
|
TransactionAlreadyCompletedRollbackError,
|
|
6
6
|
TransactionNotPendingCommitError,
|
|
7
7
|
TransactionNotPendingMutateError,
|
|
8
|
-
} from
|
|
9
|
-
import { transactionScopedScheduler } from
|
|
10
|
-
import type { Deferred } from
|
|
8
|
+
} from './errors'
|
|
9
|
+
import { transactionScopedScheduler } from './scheduler.js'
|
|
10
|
+
import type { Deferred } from './deferred'
|
|
11
11
|
import type {
|
|
12
12
|
MutationFn,
|
|
13
13
|
PendingMutation,
|
|
14
14
|
TransactionConfig,
|
|
15
15
|
TransactionState,
|
|
16
16
|
TransactionWithMutations,
|
|
17
|
-
} from
|
|
17
|
+
} from './types'
|
|
18
18
|
|
|
19
19
|
const transactions: Array<Transaction<any>> = []
|
|
20
20
|
let transactionStack: Array<Transaction<any>> = []
|
|
@@ -41,7 +41,7 @@ let sequenceNumber = 0
|
|
|
41
41
|
*/
|
|
42
42
|
function mergePendingMutations<T extends object>(
|
|
43
43
|
existing: PendingMutation<T>,
|
|
44
|
-
incoming: PendingMutation<T
|
|
44
|
+
incoming: PendingMutation<T>,
|
|
45
45
|
): PendingMutation<T> | null {
|
|
46
46
|
// Truth table implementation
|
|
47
47
|
switch (`${existing.type}-${incoming.type}` as const) {
|
|
@@ -154,7 +154,7 @@ function mergePendingMutations<T extends object>(
|
|
|
154
154
|
* await tx.commit()
|
|
155
155
|
*/
|
|
156
156
|
export function createTransaction<T extends object = Record<string, unknown>>(
|
|
157
|
-
config: TransactionConfig<T
|
|
157
|
+
config: TransactionConfig<T>,
|
|
158
158
|
): Transaction<T> {
|
|
159
159
|
const newTransaction = new Transaction<T>(config)
|
|
160
160
|
transactions.push(newTransaction)
|
|
@@ -327,7 +327,7 @@ class Transaction<T extends object = Record<string, unknown>> {
|
|
|
327
327
|
applyMutations(mutations: Array<PendingMutation<any>>): void {
|
|
328
328
|
for (const newMutation of mutations) {
|
|
329
329
|
const existingIndex = this.mutations.findIndex(
|
|
330
|
-
(m) => m.globalKey === newMutation.globalKey
|
|
330
|
+
(m) => m.globalKey === newMutation.globalKey,
|
|
331
331
|
)
|
|
332
332
|
|
|
333
333
|
if (existingIndex >= 0) {
|