@tanstack/db 0.5.2 → 0.5.4
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/README.md +10 -10
- package/dist/cjs/collection/index.d.cts +1 -1
- package/dist/cjs/collection/mutations.d.cts +2 -2
- package/dist/cjs/collection/sync.cjs +5 -0
- package/dist/cjs/collection/sync.cjs.map +1 -1
- package/dist/cjs/errors.cjs +8 -0
- package/dist/cjs/errors.cjs.map +1 -1
- package/dist/cjs/errors.d.cts +3 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/query/builder/index.cjs +18 -2
- package/dist/cjs/query/builder/index.cjs.map +1 -1
- package/dist/cjs/query/compiler/expressions.cjs +6 -44
- package/dist/cjs/query/compiler/expressions.cjs.map +1 -1
- package/dist/cjs/query/compiler/expressions.d.cts +15 -21
- package/dist/cjs/query/live/collection-subscriber.cjs +4 -14
- package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
- package/dist/cjs/query/optimizer.cjs +6 -9
- package/dist/cjs/query/optimizer.cjs.map +1 -1
- package/dist/cjs/strategies/debounceStrategy.cjs +4 -4
- package/dist/cjs/strategies/debounceStrategy.cjs.map +1 -1
- package/dist/cjs/strategies/queueStrategy.cjs +10 -8
- package/dist/cjs/strategies/queueStrategy.cjs.map +1 -1
- package/dist/cjs/strategies/throttleStrategy.cjs +4 -4
- package/dist/cjs/strategies/throttleStrategy.cjs.map +1 -1
- package/dist/cjs/types.d.cts +20 -1
- package/dist/esm/collection/index.d.ts +1 -1
- package/dist/esm/collection/mutations.d.ts +2 -2
- package/dist/esm/collection/sync.js +5 -0
- package/dist/esm/collection/sync.js.map +1 -1
- package/dist/esm/errors.d.ts +3 -0
- package/dist/esm/errors.js +8 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/query/builder/index.js +19 -3
- package/dist/esm/query/builder/index.js.map +1 -1
- package/dist/esm/query/compiler/expressions.d.ts +15 -21
- package/dist/esm/query/compiler/expressions.js +6 -44
- package/dist/esm/query/compiler/expressions.js.map +1 -1
- package/dist/esm/query/live/collection-subscriber.js +5 -15
- package/dist/esm/query/live/collection-subscriber.js.map +1 -1
- package/dist/esm/query/optimizer.js +1 -4
- package/dist/esm/query/optimizer.js.map +1 -1
- package/dist/esm/strategies/debounceStrategy.js +2 -2
- package/dist/esm/strategies/debounceStrategy.js.map +1 -1
- package/dist/esm/strategies/queueStrategy.js +10 -8
- package/dist/esm/strategies/queueStrategy.js.map +1 -1
- package/dist/esm/strategies/throttleStrategy.js +2 -2
- package/dist/esm/strategies/throttleStrategy.js.map +1 -1
- package/dist/esm/types.d.ts +20 -1
- package/package.json +2 -2
- package/src/collection/sync.ts +10 -0
- package/src/errors.ts +9 -0
- package/src/query/builder/index.ts +28 -2
- package/src/query/compiler/expressions.ts +18 -66
- package/src/query/live/collection-subscriber.ts +6 -18
- package/src/query/optimizer.ts +1 -6
- package/src/strategies/debounceStrategy.ts +2 -2
- package/src/strategies/queueStrategy.ts +22 -9
- package/src/strategies/throttleStrategy.ts +2 -2
- package/src/types.ts +20 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { MultiSet } from "@tanstack/db-ivm"
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
normalizeExpressionPaths,
|
|
4
|
+
normalizeOrderByPaths,
|
|
5
5
|
} from "../compiler/expressions.js"
|
|
6
|
-
import { WhereClauseConversionError } from "../../errors.js"
|
|
7
6
|
import type { MultiSetArray, RootStreamBuilder } from "@tanstack/db-ivm"
|
|
8
7
|
import type { Collection } from "../../collection/index.js"
|
|
9
8
|
import type { ChangeMessage } from "../../types.js"
|
|
@@ -41,13 +40,8 @@ export class CollectionSubscriber<
|
|
|
41
40
|
const whereClause = this.getWhereClauseForAlias()
|
|
42
41
|
|
|
43
42
|
if (whereClause) {
|
|
44
|
-
const whereExpression =
|
|
45
|
-
|
|
46
|
-
if (whereExpression) {
|
|
47
|
-
return this.subscribeToChanges(whereExpression)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
throw new WhereClauseConversionError(this.collectionId, this.alias)
|
|
43
|
+
const whereExpression = normalizeExpressionPaths(whereClause, this.alias)
|
|
44
|
+
return this.subscribeToChanges(whereExpression)
|
|
51
45
|
}
|
|
52
46
|
|
|
53
47
|
return this.subscribeToChanges()
|
|
@@ -199,10 +193,7 @@ export class CollectionSubscriber<
|
|
|
199
193
|
subscription.setOrderByIndex(index)
|
|
200
194
|
|
|
201
195
|
// Normalize the orderBy clauses such that the references are relative to the collection
|
|
202
|
-
const normalizedOrderBy =
|
|
203
|
-
orderBy,
|
|
204
|
-
this.alias
|
|
205
|
-
)
|
|
196
|
+
const normalizedOrderBy = normalizeOrderByPaths(orderBy, this.alias)
|
|
206
197
|
|
|
207
198
|
// Load the first `offset + limit` values from the index
|
|
208
199
|
// i.e. the K items from the collection that fall into the requested range: [offset, offset + limit[
|
|
@@ -289,10 +280,7 @@ export class CollectionSubscriber<
|
|
|
289
280
|
: biggestSentRow
|
|
290
281
|
|
|
291
282
|
// Normalize the orderBy clauses such that the references are relative to the collection
|
|
292
|
-
const normalizedOrderBy =
|
|
293
|
-
orderBy,
|
|
294
|
-
this.alias
|
|
295
|
-
)
|
|
283
|
+
const normalizedOrderBy = normalizeOrderByPaths(orderBy, this.alias)
|
|
296
284
|
|
|
297
285
|
// Take the `n` items after the biggest sent value
|
|
298
286
|
subscription.requestLimitedSnapshot({
|
package/src/query/optimizer.ts
CHANGED
|
@@ -131,7 +131,6 @@ import {
|
|
|
131
131
|
getWhereExpression,
|
|
132
132
|
isResidualWhere,
|
|
133
133
|
} from "./ir.js"
|
|
134
|
-
import { isConvertibleToCollectionFilter } from "./compiler/expressions.js"
|
|
135
134
|
import type { BasicExpression, From, QueryIR, Select, Where } from "./ir.js"
|
|
136
135
|
|
|
137
136
|
/**
|
|
@@ -248,14 +247,10 @@ function extractSourceWhereClauses(
|
|
|
248
247
|
const groupedClauses = groupWhereClauses(analyzedClauses)
|
|
249
248
|
|
|
250
249
|
// Only include single-source clauses that reference collections directly
|
|
251
|
-
// and can be converted to BasicExpression format for collection indexes
|
|
252
250
|
for (const [sourceAlias, whereClause] of groupedClauses.singleSource) {
|
|
253
251
|
// Check if this source alias corresponds to a collection reference
|
|
254
252
|
if (isCollectionReference(query, sourceAlias)) {
|
|
255
|
-
|
|
256
|
-
if (isConvertibleToCollectionFilter(whereClause)) {
|
|
257
|
-
sourceWhereClauses.set(sourceAlias, whereClause)
|
|
258
|
-
}
|
|
253
|
+
sourceWhereClauses.set(sourceAlias, whereClause)
|
|
259
254
|
}
|
|
260
255
|
}
|
|
261
256
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LiteDebouncer } from "@tanstack/pacer-lite/lite-debouncer"
|
|
2
2
|
import type { DebounceStrategy, DebounceStrategyOptions } from "./types"
|
|
3
3
|
import type { Transaction } from "../transactions"
|
|
4
4
|
|
|
@@ -28,7 +28,7 @@ import type { Transaction } from "../transactions"
|
|
|
28
28
|
export function debounceStrategy(
|
|
29
29
|
options: DebounceStrategyOptions
|
|
30
30
|
): DebounceStrategy {
|
|
31
|
-
const debouncer = new
|
|
31
|
+
const debouncer = new LiteDebouncer(
|
|
32
32
|
(callback: () => Transaction) => callback(),
|
|
33
33
|
options
|
|
34
34
|
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LiteQueuer } from "@tanstack/pacer-lite/lite-queuer"
|
|
2
2
|
import type { QueueStrategy, QueueStrategyOptions } from "./types"
|
|
3
3
|
import type { Transaction } from "../transactions"
|
|
4
4
|
|
|
@@ -44,16 +44,29 @@ import type { Transaction } from "../transactions"
|
|
|
44
44
|
* ```
|
|
45
45
|
*/
|
|
46
46
|
export function queueStrategy(options?: QueueStrategyOptions): QueueStrategy {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
// Manual promise chaining to ensure async serialization
|
|
48
|
+
// LiteQueuer (unlike AsyncQueuer from @tanstack/pacer) lacks built-in async queue
|
|
49
|
+
// primitives and concurrency control. We compensate by manually chaining promises
|
|
50
|
+
// to ensure each transaction completes before the next one starts.
|
|
51
|
+
let processingChain = Promise.resolve()
|
|
52
|
+
|
|
53
|
+
const queuer = new LiteQueuer<() => Transaction>(
|
|
54
|
+
(fn) => {
|
|
55
|
+
// Chain each transaction to the previous one's completion
|
|
56
|
+
processingChain = processingChain
|
|
57
|
+
.then(async () => {
|
|
58
|
+
const transaction = fn()
|
|
59
|
+
// Wait for the transaction to be persisted before processing next item
|
|
60
|
+
await transaction.isPersisted.promise
|
|
61
|
+
})
|
|
62
|
+
.catch(() => {
|
|
63
|
+
// Errors are handled via transaction.isPersisted.promise and surfaced there.
|
|
64
|
+
// This catch prevents unhandled promise rejections from breaking the chain,
|
|
65
|
+
// ensuring subsequent transactions can still execute even if one fails.
|
|
66
|
+
})
|
|
53
67
|
},
|
|
54
68
|
{
|
|
55
|
-
|
|
56
|
-
wait: options?.wait,
|
|
69
|
+
wait: options?.wait ?? 0,
|
|
57
70
|
maxSize: options?.maxSize,
|
|
58
71
|
addItemsTo: options?.addItemsTo ?? `back`, // Default FIFO: add to back
|
|
59
72
|
getItemsFrom: options?.getItemsFrom ?? `front`, // Default FIFO: get from front
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LiteThrottler } from "@tanstack/pacer-lite/lite-throttler"
|
|
2
2
|
import type { ThrottleStrategy, ThrottleStrategyOptions } from "./types"
|
|
3
3
|
import type { Transaction } from "../transactions"
|
|
4
4
|
|
|
@@ -48,7 +48,7 @@ import type { Transaction } from "../transactions"
|
|
|
48
48
|
export function throttleStrategy(
|
|
49
49
|
options: ThrottleStrategyOptions
|
|
50
50
|
): ThrottleStrategy {
|
|
51
|
-
const throttler = new
|
|
51
|
+
const throttler = new LiteThrottler(
|
|
52
52
|
(callback: () => Transaction) => callback(),
|
|
53
53
|
options
|
|
54
54
|
)
|
package/src/types.ts
CHANGED
|
@@ -139,7 +139,26 @@ export type NonEmptyArray<T> = [T, ...Array<T>]
|
|
|
139
139
|
export type TransactionWithMutations<
|
|
140
140
|
T extends object = Record<string, unknown>,
|
|
141
141
|
TOperation extends OperationType = OperationType,
|
|
142
|
-
> = Transaction<T
|
|
142
|
+
> = Omit<Transaction<T>, `mutations`> & {
|
|
143
|
+
/**
|
|
144
|
+
* We must omit the `mutations` property from `Transaction<T>` before intersecting
|
|
145
|
+
* because TypeScript intersects property types when the same property appears on
|
|
146
|
+
* both sides of an intersection.
|
|
147
|
+
*
|
|
148
|
+
* Without `Omit`:
|
|
149
|
+
* - `Transaction<T>` has `mutations: Array<PendingMutation<T>>`
|
|
150
|
+
* - The intersection would create: `Array<PendingMutation<T>> & NonEmptyArray<PendingMutation<T, TOperation>>`
|
|
151
|
+
* - When mapping over this array, TypeScript widens `TOperation` from the specific literal
|
|
152
|
+
* (e.g., `"delete"`) to the union `OperationType` (`"insert" | "update" | "delete"`)
|
|
153
|
+
* - This causes `PendingMutation<T, OperationType>` to evaluate the conditional type
|
|
154
|
+
* `original: TOperation extends 'insert' ? {} : T` as `{} | T` instead of just `T`
|
|
155
|
+
*
|
|
156
|
+
* With `Omit`:
|
|
157
|
+
* - We remove `mutations` from `Transaction<T>` first
|
|
158
|
+
* - Then add back `mutations: NonEmptyArray<PendingMutation<T, TOperation>>`
|
|
159
|
+
* - TypeScript can properly narrow `TOperation` to the specific literal type
|
|
160
|
+
* - This ensures `mutation.original` is correctly typed as `T` (not `{} | T`) when mapping
|
|
161
|
+
*/
|
|
143
162
|
mutations: NonEmptyArray<PendingMutation<T, TOperation>>
|
|
144
163
|
}
|
|
145
164
|
|