@tanstack/query-db-collection 1.0.6 → 1.0.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/src/query.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { QueryObserver, hashKey } from "@tanstack/query-core"
2
- import { deepEquals } from "@tanstack/db"
1
+ import { QueryObserver, hashKey } from '@tanstack/query-core'
2
+ import { deepEquals } from '@tanstack/db'
3
3
  import {
4
4
  GetKeyRequiredError,
5
5
  QueryClientRequiredError,
6
6
  QueryFnRequiredError,
7
7
  QueryKeyRequiredError,
8
- } from "./errors"
9
- import { createWriteUtils } from "./manual-sync"
10
- import { serializeLoadSubsetOptions } from "./serialization"
8
+ } from './errors'
9
+ import { createWriteUtils } from './manual-sync'
10
+ import { serializeLoadSubsetOptions } from './serialization'
11
11
  import type {
12
12
  BaseCollectionConfig,
13
13
  ChangeMessage,
@@ -18,7 +18,7 @@ import type {
18
18
  SyncConfig,
19
19
  UpdateMutationFnParams,
20
20
  UtilsRecord,
21
- } from "@tanstack/db"
21
+ } from '@tanstack/db'
22
22
  import type {
23
23
  FetchStatus,
24
24
  QueryClient,
@@ -26,11 +26,11 @@ import type {
26
26
  QueryKey,
27
27
  QueryObserverOptions,
28
28
  QueryObserverResult,
29
- } from "@tanstack/query-core"
30
- import type { StandardSchemaV1 } from "@standard-schema/spec"
29
+ } from '@tanstack/query-core'
30
+ import type { StandardSchemaV1 } from '@standard-schema/spec'
31
31
 
32
32
  // Re-export for external use
33
- export type { SyncOperation } from "./manual-sync"
33
+ export type { SyncOperation } from './manual-sync'
34
34
 
35
35
  // Schema output type inference helper (matches electric.ts pattern)
36
36
  type InferSchemaOutput<T> = T extends StandardSchemaV1
@@ -60,7 +60,7 @@ type TQueryKeyBuilder<TQueryKey> = (opts: LoadSubsetOptions) => TQueryKey
60
60
  export interface QueryCollectionConfig<
61
61
  T extends object = object,
62
62
  TQueryFn extends (context: QueryFunctionContext<any>) => Promise<any> = (
63
- context: QueryFunctionContext<any>
63
+ context: QueryFunctionContext<any>,
64
64
  ) => Promise<any>,
65
65
  TError = unknown,
66
66
  TQueryKey extends QueryKey = QueryKey,
@@ -72,7 +72,7 @@ export interface QueryCollectionConfig<
72
72
  queryKey: TQueryKey | TQueryKeyBuilder<TQueryKey>
73
73
  /** Function that fetches data from the server. Must return the complete collection state */
74
74
  queryFn: TQueryFn extends (
75
- context: QueryFunctionContext<TQueryKey>
75
+ context: QueryFunctionContext<TQueryKey>,
76
76
  ) => Promise<Array<any>>
77
77
  ? (context: QueryFunctionContext<TQueryKey>) => Promise<Array<T>>
78
78
  : TQueryFn
@@ -232,7 +232,7 @@ class QueryCollectionUtilsImpl {
232
232
  constructor(
233
233
  state: QueryCollectionState,
234
234
  refetch: RefetchFn,
235
- writeUtils: ReturnType<typeof createWriteUtils>
235
+ writeUtils: ReturnType<typeof createWriteUtils>,
236
236
  ) {
237
237
  this.state = state
238
238
  this.refetchFn = refetch
@@ -270,21 +270,21 @@ class QueryCollectionUtilsImpl {
270
270
  public get isFetching() {
271
271
  // check if any observer is fetching
272
272
  return Array.from(this.state.observers.values()).some(
273
- (observer) => observer.getCurrentResult().isFetching
273
+ (observer) => observer.getCurrentResult().isFetching,
274
274
  )
275
275
  }
276
276
 
277
277
  public get isRefetching() {
278
278
  // check if any observer is refetching
279
279
  return Array.from(this.state.observers.values()).some(
280
- (observer) => observer.getCurrentResult().isRefetching
280
+ (observer) => observer.getCurrentResult().isRefetching,
281
281
  )
282
282
  }
283
283
 
284
284
  public get isLoading() {
285
285
  // check if any observer is loading
286
286
  return Array.from(this.state.observers.values()).some(
287
- (observer) => observer.getCurrentResult().isLoading
287
+ (observer) => observer.getCurrentResult().isLoading,
288
288
  )
289
289
  }
290
290
 
@@ -293,14 +293,14 @@ class QueryCollectionUtilsImpl {
293
293
  return Math.max(
294
294
  0,
295
295
  ...Array.from(this.state.observers.values()).map(
296
- (observer) => observer.getCurrentResult().dataUpdatedAt
297
- )
296
+ (observer) => observer.getCurrentResult().dataUpdatedAt,
297
+ ),
298
298
  )
299
299
  }
300
300
 
301
301
  public get fetchStatus(): Array<FetchStatus> {
302
302
  return Array.from(this.state.observers.values()).map(
303
- (observer) => observer.getCurrentResult().fetchStatus
303
+ (observer) => observer.getCurrentResult().fetchStatus,
304
304
  )
305
305
  }
306
306
  }
@@ -409,7 +409,7 @@ export function queryCollectionOptions<
409
409
  > & {
410
410
  schema: T
411
411
  select: (data: TQueryData) => Array<InferSchemaInput<T>>
412
- }
412
+ },
413
413
  ): CollectionConfig<
414
414
  InferSchemaOutput<T>,
415
415
  TKey,
@@ -429,7 +429,7 @@ export function queryCollectionOptions<
429
429
  export function queryCollectionOptions<
430
430
  T extends object,
431
431
  TQueryFn extends (context: QueryFunctionContext<any>) => Promise<any> = (
432
- context: QueryFunctionContext<any>
432
+ context: QueryFunctionContext<any>,
433
433
  ) => Promise<any>,
434
434
  TError = unknown,
435
435
  TQueryKey extends QueryKey = QueryKey,
@@ -447,7 +447,7 @@ export function queryCollectionOptions<
447
447
  > & {
448
448
  schema?: never // prohibit schema
449
449
  select: (data: TQueryData) => Array<T>
450
- }
450
+ },
451
451
  ): CollectionConfig<
452
452
  T,
453
453
  TKey,
@@ -468,7 +468,7 @@ export function queryCollectionOptions<
468
468
  config: QueryCollectionConfig<
469
469
  InferSchemaOutput<T>,
470
470
  (
471
- context: QueryFunctionContext<any>
471
+ context: QueryFunctionContext<any>,
472
472
  ) => Promise<Array<InferSchemaOutput<T>>>,
473
473
  TError,
474
474
  TQueryKey,
@@ -476,7 +476,7 @@ export function queryCollectionOptions<
476
476
  T
477
477
  > & {
478
478
  schema: T
479
- }
479
+ },
480
480
  ): CollectionConfig<
481
481
  InferSchemaOutput<T>,
482
482
  TKey,
@@ -507,7 +507,7 @@ export function queryCollectionOptions<
507
507
  TKey
508
508
  > & {
509
509
  schema?: never // prohibit schema
510
- }
510
+ },
511
511
  ): CollectionConfig<
512
512
  T,
513
513
  TKey,
@@ -519,7 +519,7 @@ export function queryCollectionOptions<
519
519
  }
520
520
 
521
521
  export function queryCollectionOptions(
522
- config: QueryCollectionConfig<Record<string, unknown>>
522
+ config: QueryCollectionConfig<Record<string, unknown>>,
523
523
  ): CollectionConfig<
524
524
  Record<string, unknown>,
525
525
  string | number,
@@ -663,7 +663,7 @@ export function queryCollectionOptions(
663
663
 
664
664
  const createQueryFromOpts = (
665
665
  opts: LoadSubsetOptions = {},
666
- queryFunction: typeof queryFn = queryFn
666
+ queryFunction: typeof queryFn = queryFn,
667
667
  ): true | Promise<void> => {
668
668
  // Generate key using common function
669
669
  const key = generateQueryKeyFromOptions(opts)
@@ -675,7 +675,7 @@ export function queryCollectionOptions(
675
675
  // Increment reference count since another consumer is using this observer
676
676
  queryRefCounts.set(
677
677
  hashedQueryKey,
678
- (queryRefCounts.get(hashedQueryKey) || 0) + 1
678
+ (queryRefCounts.get(hashedQueryKey) || 0) + 1,
679
679
  )
680
680
 
681
681
  // Get the current result and return based on its state
@@ -739,7 +739,7 @@ export function queryCollectionOptions(
739
739
  // Increment reference count for this query
740
740
  queryRefCounts.set(
741
741
  hashedQueryKey,
742
- (queryRefCounts.get(hashedQueryKey) || 0) + 1
742
+ (queryRefCounts.get(hashedQueryKey) || 0) + 1,
743
743
  )
744
744
 
745
745
  // Create a promise that resolves when the query result is first available
@@ -790,7 +790,7 @@ export function queryCollectionOptions(
790
790
  }
791
791
 
792
792
  const currentSyncedItems: Map<string | number, any> = new Map(
793
- collection._state.syncedData.entries()
793
+ collection._state.syncedData.entries(),
794
794
  )
795
795
  const newItemsMap = new Map<string | number, any>()
796
796
  newItemsArray.forEach((item) => {
@@ -833,7 +833,7 @@ export function queryCollectionOptions(
833
833
 
834
834
  console.error(
835
835
  `[QueryCollection] Error observing query ${String(queryKey)}:`,
836
- result.error
836
+ result.error,
837
837
  )
838
838
 
839
839
  // Mark collection as ready even on error to avoid blocking apps
@@ -849,7 +849,7 @@ export function queryCollectionOptions(
849
849
 
850
850
  const subscribeToQuery = (
851
851
  observer: QueryObserver<Array<any>, any, Array<any>, Array<any>, any>,
852
- hashedQueryKey: string
852
+ hashedQueryKey: string,
853
853
  ) => {
854
854
  if (!isSubscribed(hashedQueryKey)) {
855
855
  const cachedQueryKey = hashToQueryKey.get(hashedQueryKey)!
@@ -889,7 +889,7 @@ export function queryCollectionOptions(
889
889
  } else if (subscriberCount === 0) {
890
890
  unsubscribeFromQueries()
891
891
  }
892
- }
892
+ },
893
893
  )
894
894
 
895
895
  // If syncMode is eager, create the initial query without any predicates
@@ -989,7 +989,7 @@ export function queryCollectionOptions(
989
989
  if (refcount > 0) {
990
990
  console.warn(
991
991
  `[cleanupQueryIfIdle] Invariant violation: refcount=${refcount} but no listeners. Cleaning up to prevent leak.`,
992
- { hashedQueryKey }
992
+ { hashedQueryKey },
993
993
  )
994
994
  }
995
995
 
@@ -1040,7 +1040,7 @@ export function queryCollectionOptions(
1040
1040
  allQueryKeys.map(async (qKey) => {
1041
1041
  await queryClient.cancelQueries({ queryKey: qKey, exact: true })
1042
1042
  queryClient.removeQueries({ queryKey: qKey, exact: true })
1043
- })
1043
+ }),
1044
1044
  )
1045
1045
  }
1046
1046
 
@@ -1162,7 +1162,7 @@ export function queryCollectionOptions(
1162
1162
 
1163
1163
  // Create write utils using the manual-sync module
1164
1164
  const writeUtils = createWriteUtils<any, string | number, any>(
1165
- () => writeContext
1165
+ () => writeContext,
1166
1166
  )
1167
1167
 
1168
1168
  // Create wrapper handlers for direct persistence operations that handle refetching
@@ -1,11 +1,13 @@
1
- import type { IR, LoadSubsetOptions } from "@tanstack/db"
1
+ import type { IR, LoadSubsetOptions } from '@tanstack/db'
2
2
 
3
3
  /**
4
- * Serializes LoadSubsetOptions into a stable, hashable format for query keys
4
+ * Serializes LoadSubsetOptions into a stable, hashable format for query keys.
5
+ * Includes where, orderBy, limit, and offset for pagination support.
6
+ * Note: cursor expressions are not serialized as they are backend-specific.
5
7
  * @internal
6
8
  */
7
9
  export function serializeLoadSubsetOptions(
8
- options: LoadSubsetOptions | undefined
10
+ options: LoadSubsetOptions | undefined,
9
11
  ): string | undefined {
10
12
  if (!options) {
11
13
  return undefined
@@ -43,6 +45,11 @@ export function serializeLoadSubsetOptions(
43
45
  result.limit = options.limit
44
46
  }
45
47
 
48
+ // Include offset for pagination support
49
+ if (options.offset !== undefined) {
50
+ result.offset = options.offset
51
+ }
52
+
46
53
  return Object.keys(result).length === 0 ? undefined : JSON.stringify(result)
47
54
  }
48
55
 
@@ -120,7 +127,7 @@ function serializeValue(value: unknown): unknown {
120
127
  Object.entries(value as Record<string, unknown>).map(([key, val]) => [
121
128
  key,
122
129
  serializeValue(val),
123
- ])
130
+ ]),
124
131
  )
125
132
  }
126
133