@tanstack/db 0.4.5 → 0.4.7
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/collection/change-events.cjs +1 -1
- package/dist/cjs/collection/change-events.cjs.map +1 -1
- package/dist/cjs/collection/change-events.d.cts +1 -1
- package/dist/cjs/collection/index.cjs +11 -0
- package/dist/cjs/collection/index.cjs.map +1 -1
- package/dist/cjs/collection/index.d.cts +8 -1
- package/dist/cjs/collection/lifecycle.cjs +4 -1
- package/dist/cjs/collection/lifecycle.cjs.map +1 -1
- package/dist/cjs/collection/mutations.cjs +4 -4
- package/dist/cjs/collection/mutations.cjs.map +1 -1
- package/dist/cjs/collection/subscription.cjs +21 -1
- package/dist/cjs/collection/subscription.cjs.map +1 -1
- package/dist/cjs/collection/subscription.d.cts +4 -3
- package/dist/cjs/collection/sync.cjs +94 -71
- package/dist/cjs/collection/sync.cjs.map +1 -1
- package/dist/cjs/collection/sync.d.cts +9 -1
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -0
- package/dist/cjs/indexes/auto-index.cjs +4 -1
- package/dist/cjs/indexes/auto-index.cjs.map +1 -1
- package/dist/cjs/local-only.cjs +21 -2
- package/dist/cjs/local-only.cjs.map +1 -1
- package/dist/cjs/local-only.d.cts +64 -7
- package/dist/cjs/local-storage.cjs +71 -3
- package/dist/cjs/local-storage.cjs.map +1 -1
- package/dist/cjs/local-storage.d.cts +55 -2
- package/dist/cjs/query/compiler/expressions.cjs +19 -0
- package/dist/cjs/query/compiler/expressions.cjs.map +1 -1
- package/dist/cjs/query/compiler/expressions.d.cts +2 -1
- package/dist/cjs/query/compiler/order-by.cjs +2 -1
- package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
- package/dist/cjs/query/compiler/order-by.d.cts +2 -1
- package/dist/cjs/query/live/collection-subscriber.cjs +18 -8
- package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
- package/dist/cjs/query/live/collection-subscriber.d.cts +1 -0
- package/dist/cjs/types.d.cts +11 -1
- package/dist/esm/collection/change-events.d.ts +1 -1
- package/dist/esm/collection/change-events.js +1 -1
- package/dist/esm/collection/change-events.js.map +1 -1
- package/dist/esm/collection/index.d.ts +8 -1
- package/dist/esm/collection/index.js +11 -0
- package/dist/esm/collection/index.js.map +1 -1
- package/dist/esm/collection/lifecycle.js +4 -1
- package/dist/esm/collection/lifecycle.js.map +1 -1
- package/dist/esm/collection/mutations.js +4 -4
- package/dist/esm/collection/mutations.js.map +1 -1
- package/dist/esm/collection/subscription.d.ts +4 -3
- package/dist/esm/collection/subscription.js +22 -2
- package/dist/esm/collection/subscription.js.map +1 -1
- package/dist/esm/collection/sync.d.ts +9 -1
- package/dist/esm/collection/sync.js +94 -71
- package/dist/esm/collection/sync.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/indexes/auto-index.js +4 -1
- package/dist/esm/indexes/auto-index.js.map +1 -1
- package/dist/esm/local-only.d.ts +64 -7
- package/dist/esm/local-only.js +21 -2
- package/dist/esm/local-only.js.map +1 -1
- package/dist/esm/local-storage.d.ts +55 -2
- package/dist/esm/local-storage.js +72 -4
- package/dist/esm/local-storage.js.map +1 -1
- package/dist/esm/query/compiler/expressions.d.ts +2 -1
- package/dist/esm/query/compiler/expressions.js +19 -0
- package/dist/esm/query/compiler/expressions.js.map +1 -1
- package/dist/esm/query/compiler/order-by.d.ts +2 -1
- package/dist/esm/query/compiler/order-by.js +2 -1
- package/dist/esm/query/compiler/order-by.js.map +1 -1
- package/dist/esm/query/live/collection-subscriber.d.ts +1 -0
- package/dist/esm/query/live/collection-subscriber.js +19 -9
- package/dist/esm/query/live/collection-subscriber.js.map +1 -1
- package/dist/esm/types.d.ts +11 -1
- package/package.json +1 -1
- package/src/collection/change-events.ts +5 -2
- package/src/collection/index.ts +13 -0
- package/src/collection/lifecycle.ts +4 -1
- package/src/collection/mutations.ts +8 -4
- package/src/collection/subscription.ts +34 -4
- package/src/collection/sync.ts +147 -110
- package/src/index.ts +5 -0
- package/src/indexes/auto-index.ts +4 -1
- package/src/local-only.ts +119 -30
- package/src/local-storage.ts +170 -5
- package/src/query/compiler/expressions.ts +26 -1
- package/src/query/compiler/order-by.ts +3 -1
- package/src/query/live/collection-subscriber.ts +31 -10
- package/src/types.ts +13 -1
package/src/local-storage.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
DeleteMutationFnParams,
|
|
13
13
|
InferSchemaOutput,
|
|
14
14
|
InsertMutationFnParams,
|
|
15
|
+
PendingMutation,
|
|
15
16
|
SyncConfig,
|
|
16
17
|
UpdateMutationFnParams,
|
|
17
18
|
UtilsRecord,
|
|
@@ -90,6 +91,26 @@ export type GetStorageSizeFn = () => number
|
|
|
90
91
|
export interface LocalStorageCollectionUtils extends UtilsRecord {
|
|
91
92
|
clearStorage: ClearStorageFn
|
|
92
93
|
getStorageSize: GetStorageSizeFn
|
|
94
|
+
/**
|
|
95
|
+
* Accepts mutations from a transaction that belong to this collection and persists them to localStorage.
|
|
96
|
+
* This should be called in your transaction's mutationFn to persist local-storage data.
|
|
97
|
+
*
|
|
98
|
+
* @param transaction - The transaction containing mutations to accept
|
|
99
|
+
* @example
|
|
100
|
+
* const localSettings = createCollection(localStorageCollectionOptions({...}))
|
|
101
|
+
*
|
|
102
|
+
* const tx = createTransaction({
|
|
103
|
+
* mutationFn: async ({ transaction }) => {
|
|
104
|
+
* // Make API call first
|
|
105
|
+
* await api.save(...)
|
|
106
|
+
* // Then persist local-storage mutations after success
|
|
107
|
+
* localSettings.utils.acceptMutations(transaction)
|
|
108
|
+
* }
|
|
109
|
+
* })
|
|
110
|
+
*/
|
|
111
|
+
acceptMutations: (transaction: {
|
|
112
|
+
mutations: Array<PendingMutation<Record<string, unknown>>>
|
|
113
|
+
}) => void
|
|
93
114
|
}
|
|
94
115
|
|
|
95
116
|
/**
|
|
@@ -123,11 +144,17 @@ function generateUuid(): string {
|
|
|
123
144
|
* This function creates a collection that persists data to localStorage/sessionStorage
|
|
124
145
|
* and synchronizes changes across browser tabs using storage events.
|
|
125
146
|
*
|
|
147
|
+
* **Using with Manual Transactions:**
|
|
148
|
+
*
|
|
149
|
+
* For manual transactions, you must call `utils.acceptMutations()` in your transaction's `mutationFn`
|
|
150
|
+
* to persist changes made during `tx.mutate()`. This is necessary because local-storage collections
|
|
151
|
+
* don't participate in the standard mutation handler flow for manual transactions.
|
|
152
|
+
*
|
|
126
153
|
* @template TExplicit - The explicit type of items in the collection (highest priority)
|
|
127
154
|
* @template TSchema - The schema type for validation and type inference (second priority)
|
|
128
155
|
* @template TFallback - The fallback type if no explicit or schema type is provided
|
|
129
156
|
* @param config - Configuration options for the localStorage collection
|
|
130
|
-
* @returns Collection options with utilities including clearStorage and
|
|
157
|
+
* @returns Collection options with utilities including clearStorage, getStorageSize, and acceptMutations
|
|
131
158
|
*
|
|
132
159
|
* @example
|
|
133
160
|
* // Basic localStorage collection
|
|
@@ -159,6 +186,33 @@ function generateUuid(): string {
|
|
|
159
186
|
* },
|
|
160
187
|
* })
|
|
161
188
|
* )
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* // Using with manual transactions
|
|
192
|
+
* const localSettings = createCollection(
|
|
193
|
+
* localStorageCollectionOptions({
|
|
194
|
+
* storageKey: 'user-settings',
|
|
195
|
+
* getKey: (item) => item.id,
|
|
196
|
+
* })
|
|
197
|
+
* )
|
|
198
|
+
*
|
|
199
|
+
* const tx = createTransaction({
|
|
200
|
+
* mutationFn: async ({ transaction }) => {
|
|
201
|
+
* // Use settings data in API call
|
|
202
|
+
* const settingsMutations = transaction.mutations.filter(m => m.collection === localSettings)
|
|
203
|
+
* await api.updateUserProfile({ settings: settingsMutations[0]?.modified })
|
|
204
|
+
*
|
|
205
|
+
* // Persist local-storage mutations after API success
|
|
206
|
+
* localSettings.utils.acceptMutations(transaction)
|
|
207
|
+
* }
|
|
208
|
+
* })
|
|
209
|
+
*
|
|
210
|
+
* tx.mutate(() => {
|
|
211
|
+
* localSettings.insert({ id: 'theme', value: 'dark' })
|
|
212
|
+
* apiCollection.insert({ id: 2, data: 'profile data' })
|
|
213
|
+
* })
|
|
214
|
+
*
|
|
215
|
+
* await tx.commit()
|
|
162
216
|
*/
|
|
163
217
|
|
|
164
218
|
// Overload for when schema is provided
|
|
@@ -397,6 +451,76 @@ export function localStorageCollectionOptions(
|
|
|
397
451
|
// Default id to a pattern based on storage key if not provided
|
|
398
452
|
const collectionId = id ?? `local-collection:${config.storageKey}`
|
|
399
453
|
|
|
454
|
+
/**
|
|
455
|
+
* Accepts mutations from a transaction that belong to this collection and persists them to storage
|
|
456
|
+
*/
|
|
457
|
+
const acceptMutations = (transaction: {
|
|
458
|
+
mutations: Array<PendingMutation<Record<string, unknown>>>
|
|
459
|
+
}) => {
|
|
460
|
+
// Filter mutations that belong to this collection
|
|
461
|
+
// Use collection ID for filtering if collection reference isn't available yet
|
|
462
|
+
const collectionMutations = transaction.mutations.filter((m) => {
|
|
463
|
+
// Try to match by collection reference first
|
|
464
|
+
if (sync.collection && m.collection === sync.collection) {
|
|
465
|
+
return true
|
|
466
|
+
}
|
|
467
|
+
// Fall back to matching by collection ID
|
|
468
|
+
return m.collection.id === collectionId
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
if (collectionMutations.length === 0) {
|
|
472
|
+
return
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Validate all mutations can be serialized before modifying storage
|
|
476
|
+
for (const mutation of collectionMutations) {
|
|
477
|
+
switch (mutation.type) {
|
|
478
|
+
case `insert`:
|
|
479
|
+
case `update`:
|
|
480
|
+
validateJsonSerializable(mutation.modified, mutation.type)
|
|
481
|
+
break
|
|
482
|
+
case `delete`:
|
|
483
|
+
validateJsonSerializable(mutation.original, mutation.type)
|
|
484
|
+
break
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Load current data from storage
|
|
489
|
+
const currentData = loadFromStorage<Record<string, unknown>>(
|
|
490
|
+
config.storageKey,
|
|
491
|
+
storage
|
|
492
|
+
)
|
|
493
|
+
|
|
494
|
+
// Apply each mutation
|
|
495
|
+
for (const mutation of collectionMutations) {
|
|
496
|
+
// Use the engine's pre-computed key to avoid key derivation issues
|
|
497
|
+
const key = mutation.key
|
|
498
|
+
|
|
499
|
+
switch (mutation.type) {
|
|
500
|
+
case `insert`:
|
|
501
|
+
case `update`: {
|
|
502
|
+
const storedItem: StoredItem<Record<string, unknown>> = {
|
|
503
|
+
versionKey: generateUuid(),
|
|
504
|
+
data: mutation.modified,
|
|
505
|
+
}
|
|
506
|
+
currentData.set(key, storedItem)
|
|
507
|
+
break
|
|
508
|
+
}
|
|
509
|
+
case `delete`: {
|
|
510
|
+
currentData.delete(key)
|
|
511
|
+
break
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Save to storage
|
|
517
|
+
saveToStorage(currentData)
|
|
518
|
+
|
|
519
|
+
// Confirm the mutations in the collection to move them from optimistic to synced state
|
|
520
|
+
// This writes them through the sync interface to make them "synced" instead of "optimistic"
|
|
521
|
+
sync.confirmOperationsSync(collectionMutations)
|
|
522
|
+
}
|
|
523
|
+
|
|
400
524
|
return {
|
|
401
525
|
...restConfig,
|
|
402
526
|
id: collectionId,
|
|
@@ -407,6 +531,7 @@ export function localStorageCollectionOptions(
|
|
|
407
531
|
utils: {
|
|
408
532
|
clearStorage,
|
|
409
533
|
getStorageSize,
|
|
534
|
+
acceptMutations,
|
|
410
535
|
},
|
|
411
536
|
}
|
|
412
537
|
}
|
|
@@ -480,8 +605,13 @@ function createLocalStorageSync<T extends object>(
|
|
|
480
605
|
storageEventApi: StorageEventApi,
|
|
481
606
|
_getKey: (item: T) => string | number,
|
|
482
607
|
lastKnownData: Map<string | number, StoredItem<T>>
|
|
483
|
-
): SyncConfig<T> & {
|
|
608
|
+
): SyncConfig<T> & {
|
|
609
|
+
manualTrigger?: () => void
|
|
610
|
+
collection: any
|
|
611
|
+
confirmOperationsSync: (mutations: Array<any>) => void
|
|
612
|
+
} {
|
|
484
613
|
let syncParams: Parameters<SyncConfig<T>[`sync`]>[0] | null = null
|
|
614
|
+
let collection: any = null
|
|
485
615
|
|
|
486
616
|
/**
|
|
487
617
|
* Compare two Maps to find differences using version keys
|
|
@@ -556,12 +686,16 @@ function createLocalStorageSync<T extends object>(
|
|
|
556
686
|
}
|
|
557
687
|
}
|
|
558
688
|
|
|
559
|
-
const syncConfig: SyncConfig<T> & {
|
|
689
|
+
const syncConfig: SyncConfig<T> & {
|
|
690
|
+
manualTrigger?: () => void
|
|
691
|
+
collection: any
|
|
692
|
+
} = {
|
|
560
693
|
sync: (params: Parameters<SyncConfig<T>[`sync`]>[0]) => {
|
|
561
694
|
const { begin, write, commit, markReady } = params
|
|
562
695
|
|
|
563
|
-
// Store sync params for later use
|
|
696
|
+
// Store sync params and collection for later use
|
|
564
697
|
syncParams = params
|
|
698
|
+
collection = params.collection
|
|
565
699
|
|
|
566
700
|
// Initial load
|
|
567
701
|
const initialData = loadFromStorage<T>(storageKey, storage)
|
|
@@ -613,7 +747,38 @@ function createLocalStorageSync<T extends object>(
|
|
|
613
747
|
|
|
614
748
|
// Manual trigger function for local updates
|
|
615
749
|
manualTrigger: processStorageChanges,
|
|
750
|
+
|
|
751
|
+
// Collection instance reference
|
|
752
|
+
collection,
|
|
616
753
|
}
|
|
617
754
|
|
|
618
|
-
|
|
755
|
+
/**
|
|
756
|
+
* Confirms mutations by writing them through the sync interface
|
|
757
|
+
* This moves mutations from optimistic to synced state
|
|
758
|
+
* @param mutations - Array of mutation objects to confirm
|
|
759
|
+
*/
|
|
760
|
+
const confirmOperationsSync = (mutations: Array<any>) => {
|
|
761
|
+
if (!syncParams) {
|
|
762
|
+
// Sync not initialized yet, mutations will be handled on next sync
|
|
763
|
+
return
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const { begin, write, commit } = syncParams
|
|
767
|
+
|
|
768
|
+
// Write the mutations through sync to confirm them
|
|
769
|
+
begin()
|
|
770
|
+
mutations.forEach((mutation: any) => {
|
|
771
|
+
write({
|
|
772
|
+
type: mutation.type,
|
|
773
|
+
value:
|
|
774
|
+
mutation.type === `delete` ? mutation.original : mutation.modified,
|
|
775
|
+
})
|
|
776
|
+
})
|
|
777
|
+
commit()
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return {
|
|
781
|
+
...syncConfig,
|
|
782
|
+
confirmOperationsSync,
|
|
783
|
+
}
|
|
619
784
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Func, PropRef, Value } from "../ir.js"
|
|
2
|
-
import type { BasicExpression } from "../ir.js"
|
|
2
|
+
import type { BasicExpression, OrderBy } from "../ir.js"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Functions supported by the collection index system.
|
|
@@ -90,3 +90,28 @@ export function convertToBasicExpression(
|
|
|
90
90
|
return new Func(whereClause.name, args)
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
|
|
94
|
+
export function convertOrderByToBasicExpression(
|
|
95
|
+
orderBy: OrderBy,
|
|
96
|
+
collectionAlias: string
|
|
97
|
+
): OrderBy {
|
|
98
|
+
const normalizedOrderBy = orderBy.map((clause) => {
|
|
99
|
+
const basicExp = convertToBasicExpression(
|
|
100
|
+
clause.expression,
|
|
101
|
+
collectionAlias
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if (!basicExp) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Failed to convert orderBy expression to a basic expression: ${clause.expression}`
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
...clause,
|
|
112
|
+
expression: basicExp,
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
return normalizedOrderBy
|
|
117
|
+
}
|
|
@@ -6,13 +6,14 @@ import { findIndexForField } from "../../utils/index-optimization.js"
|
|
|
6
6
|
import { compileExpression } from "./evaluators.js"
|
|
7
7
|
import { replaceAggregatesByRefs } from "./group-by.js"
|
|
8
8
|
import type { CompiledSingleRowExpression } from "./evaluators.js"
|
|
9
|
-
import type { OrderByClause, QueryIR, Select } from "../ir.js"
|
|
9
|
+
import type { OrderBy, OrderByClause, QueryIR, Select } from "../ir.js"
|
|
10
10
|
import type { NamespacedAndKeyedStream, NamespacedRow } from "../../types.js"
|
|
11
11
|
import type { IStreamBuilder, KeyValue } from "@tanstack/db-ivm"
|
|
12
12
|
import type { IndexInterface } from "../../indexes/base-index.js"
|
|
13
13
|
import type { Collection } from "../../collection/index.js"
|
|
14
14
|
|
|
15
15
|
export type OrderByOptimizationInfo = {
|
|
16
|
+
orderBy: OrderBy
|
|
16
17
|
offset: number
|
|
17
18
|
limit: number
|
|
18
19
|
comparator: (
|
|
@@ -160,6 +161,7 @@ export function processOrderBy(
|
|
|
160
161
|
comparator,
|
|
161
162
|
valueExtractorForRawRow,
|
|
162
163
|
index,
|
|
164
|
+
orderBy: orderByClause,
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
optimizableOrderByCollections[followRefCollection.id] =
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { MultiSet } from "@tanstack/db-ivm"
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
convertOrderByToBasicExpression,
|
|
4
|
+
convertToBasicExpression,
|
|
5
|
+
} from "../compiler/expressions.js"
|
|
3
6
|
import type { FullSyncState } from "./types.js"
|
|
4
7
|
import type { MultiSetArray, RootStreamBuilder } from "@tanstack/db-ivm"
|
|
5
8
|
import type { Collection } from "../../collection/index.js"
|
|
@@ -16,26 +19,29 @@ export class CollectionSubscriber<
|
|
|
16
19
|
// Keep track of the biggest value we've sent so far (needed for orderBy optimization)
|
|
17
20
|
private biggest: any = undefined
|
|
18
21
|
|
|
22
|
+
private collectionAlias: string
|
|
23
|
+
|
|
19
24
|
constructor(
|
|
20
25
|
private collectionId: string,
|
|
21
26
|
private collection: Collection,
|
|
22
27
|
private config: Parameters<SyncConfig<TResult>[`sync`]>[0],
|
|
23
28
|
private syncState: FullSyncState,
|
|
24
29
|
private collectionConfigBuilder: CollectionConfigBuilder<TContext, TResult>
|
|
25
|
-
) {
|
|
26
|
-
|
|
27
|
-
subscribe(): CollectionSubscription {
|
|
28
|
-
const collectionAlias = findCollectionAlias(
|
|
30
|
+
) {
|
|
31
|
+
this.collectionAlias = findCollectionAlias(
|
|
29
32
|
this.collectionId,
|
|
30
33
|
this.collectionConfigBuilder.query
|
|
31
|
-
)
|
|
32
|
-
|
|
34
|
+
)!
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
subscribe(): CollectionSubscription {
|
|
38
|
+
const whereClause = this.getWhereClauseFromAlias(this.collectionAlias)
|
|
33
39
|
|
|
34
40
|
if (whereClause) {
|
|
35
41
|
// Convert WHERE clause to BasicExpression format for collection subscription
|
|
36
42
|
const whereExpression = convertToBasicExpression(
|
|
37
43
|
whereClause,
|
|
38
|
-
collectionAlias
|
|
44
|
+
this.collectionAlias
|
|
39
45
|
)
|
|
40
46
|
|
|
41
47
|
if (whereExpression) {
|
|
@@ -128,7 +134,7 @@ export class CollectionSubscriber<
|
|
|
128
134
|
private subscribeToOrderedChanges(
|
|
129
135
|
whereExpression: BasicExpression<boolean> | undefined
|
|
130
136
|
) {
|
|
131
|
-
const { offset, limit, comparator, dataNeeded, index } =
|
|
137
|
+
const { orderBy, offset, limit, comparator, dataNeeded, index } =
|
|
132
138
|
this.collectionConfigBuilder.optimizableOrderByCollections[
|
|
133
139
|
this.collectionId
|
|
134
140
|
]!
|
|
@@ -164,10 +170,17 @@ export class CollectionSubscriber<
|
|
|
164
170
|
|
|
165
171
|
subscription.setOrderByIndex(index)
|
|
166
172
|
|
|
173
|
+
// Normalize the orderBy clauses such that the references are relative to the collection
|
|
174
|
+
const normalizedOrderBy = convertOrderByToBasicExpression(
|
|
175
|
+
orderBy,
|
|
176
|
+
this.collectionAlias
|
|
177
|
+
)
|
|
178
|
+
|
|
167
179
|
// Load the first `offset + limit` values from the index
|
|
168
180
|
// i.e. the K items from the collection that fall into the requested range: [offset, offset + limit[
|
|
169
181
|
subscription.requestLimitedSnapshot({
|
|
170
182
|
limit: offset + limit,
|
|
183
|
+
orderBy: normalizedOrderBy,
|
|
171
184
|
})
|
|
172
185
|
|
|
173
186
|
return subscription
|
|
@@ -225,7 +238,7 @@ export class CollectionSubscriber<
|
|
|
225
238
|
// Loads the next `n` items from the collection
|
|
226
239
|
// starting from the biggest item it has sent
|
|
227
240
|
private loadNextItems(n: number, subscription: CollectionSubscription) {
|
|
228
|
-
const { valueExtractorForRawRow } =
|
|
241
|
+
const { orderBy, valueExtractorForRawRow } =
|
|
229
242
|
this.collectionConfigBuilder.optimizableOrderByCollections[
|
|
230
243
|
this.collectionId
|
|
231
244
|
]!
|
|
@@ -233,8 +246,16 @@ export class CollectionSubscriber<
|
|
|
233
246
|
const biggestSentValue = biggestSentRow
|
|
234
247
|
? valueExtractorForRawRow(biggestSentRow)
|
|
235
248
|
: biggestSentRow
|
|
249
|
+
|
|
250
|
+
// Normalize the orderBy clauses such that the references are relative to the collection
|
|
251
|
+
const normalizedOrderBy = convertOrderByToBasicExpression(
|
|
252
|
+
orderBy,
|
|
253
|
+
this.collectionAlias
|
|
254
|
+
)
|
|
255
|
+
|
|
236
256
|
// Take the `n` items after the biggest sent value
|
|
237
257
|
subscription.requestLimitedSnapshot({
|
|
258
|
+
orderBy: normalizedOrderBy,
|
|
238
259
|
limit: n,
|
|
239
260
|
minValue: biggestSentValue,
|
|
240
261
|
})
|
package/src/types.ts
CHANGED
|
@@ -150,6 +150,18 @@ export type Row<TExtensions = never> = Record<string, Value<TExtensions>>
|
|
|
150
150
|
|
|
151
151
|
export type OperationType = `insert` | `update` | `delete`
|
|
152
152
|
|
|
153
|
+
export type OnLoadMoreOptions = {
|
|
154
|
+
where?: BasicExpression<boolean>
|
|
155
|
+
orderBy?: OrderBy
|
|
156
|
+
limit?: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type CleanupFn = () => void
|
|
160
|
+
|
|
161
|
+
export type SyncConfigRes = {
|
|
162
|
+
cleanup?: CleanupFn
|
|
163
|
+
onLoadMore?: (options: OnLoadMoreOptions) => void | Promise<void>
|
|
164
|
+
}
|
|
153
165
|
export interface SyncConfig<
|
|
154
166
|
T extends object = Record<string, unknown>,
|
|
155
167
|
TKey extends string | number = string | number,
|
|
@@ -161,7 +173,7 @@ export interface SyncConfig<
|
|
|
161
173
|
commit: () => void
|
|
162
174
|
markReady: () => void
|
|
163
175
|
truncate: () => void
|
|
164
|
-
}) => void
|
|
176
|
+
}) => void | CleanupFn | SyncConfigRes
|
|
165
177
|
|
|
166
178
|
/**
|
|
167
179
|
* Get the sync metadata for insert operations
|