@tanstack/vue-db 0.0.129 → 0.1.1

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.
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const useLiveQuery = require("./useLiveQuery.cjs");
4
+ const useLiveInfiniteQuery = require("./useLiveInfiniteQuery.cjs");
4
5
  const db = require("@tanstack/db");
5
6
  exports.useLiveQuery = useLiveQuery.useLiveQuery;
7
+ exports.useLiveInfiniteQuery = useLiveInfiniteQuery.useLiveInfiniteQuery;
6
8
  Object.defineProperty(exports, "createTransaction", {
7
9
  enumerable: true,
8
10
  get: () => db.createTransaction
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
@@ -1,4 +1,5 @@
1
1
  export * from './useLiveQuery.cjs';
2
+ export * from './useLiveInfiniteQuery.cjs';
2
3
  export * from '@tanstack/db';
3
4
  export type { Collection } from '@tanstack/db';
4
5
  export { createTransaction } from '@tanstack/db';
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const vue = require("vue");
4
+ const db = require("@tanstack/db");
5
+ const DEFAULT_GC_TIME_MS = 1;
6
+ function useLiveInfiniteQuery(queryFnOrCollection, config, deps = []) {
7
+ let validatedCollection = null;
8
+ let previousController = null;
9
+ let previousInput = null;
10
+ let previousDependencies = null;
11
+ let previousPageSize = null;
12
+ let previousInitialPageParam = null;
13
+ const controller = vue.computed(() => {
14
+ const dependencies = deps.map((dependency) => vue.toValue(dependency));
15
+ const pageSize = db.normalizeLiveQueryWindowPageSize(config.pageSize);
16
+ const initialPageParam = config.initialPageParam ?? 0;
17
+ const unwrappedInput = typeof queryFnOrCollection === `function` ? queryFnOrCollection : vue.toValue(queryFnOrCollection);
18
+ const input = db.resolveLiveQueryWindowInput(unwrappedInput);
19
+ const dependencyComparison = db.compareLiveQueryWindowDependencies(
20
+ previousDependencies,
21
+ dependencies
22
+ );
23
+ const dependenciesChanged = dependencyComparison.changed;
24
+ const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual;
25
+ const pageShapeChanged = previousPageSize !== pageSize || previousInitialPageParam !== initialPageParam;
26
+ const sameCollection = input.kind === `collection` && previousInput?.kind === `collection` && previousInput.collection === input.collection;
27
+ const canPreservePageCount = db.shouldPreserveLiveQueryWindowPageCount({
28
+ hasPreviousController: previousController !== null,
29
+ previousInputKind: previousInput?.kind,
30
+ inputKind: input.kind,
31
+ sameCollection,
32
+ dependenciesChanged,
33
+ dependenciesStructurallyEqual,
34
+ pageShapeChanged
35
+ });
36
+ const previousPageCount = previousController ? Math.max(1, previousController.getSnapshot().pages.length) : 1;
37
+ const initialPageCount = canPreservePageCount ? previousPageCount : 1;
38
+ previousInput = input;
39
+ previousDependencies = [...dependencies];
40
+ previousPageSize = pageSize;
41
+ previousInitialPageParam = initialPageParam;
42
+ if (input.kind === `collection`) {
43
+ const collection2 = input.collection;
44
+ const warning = db.getLiveQueryWindowCollectionWarning(
45
+ collection2,
46
+ pageSize + 1
47
+ );
48
+ if (validatedCollection !== collection2) {
49
+ validatedCollection = collection2;
50
+ if (warning) console.warn(warning);
51
+ }
52
+ const currentController2 = db.createLiveQueryWindowController(collection2, {
53
+ pageSize,
54
+ initialPageParam,
55
+ initialPageCount
56
+ });
57
+ previousController = currentController2;
58
+ return currentController2;
59
+ }
60
+ const collection = db.createLiveQueryCollection({
61
+ query: input.query.limit(pageSize + 1).offset(0),
62
+ startSync: false,
63
+ gcTime: DEFAULT_GC_TIME_MS
64
+ });
65
+ db.assertLiveQueryWindowManyResult(collection);
66
+ const currentController = db.createLiveQueryWindowController(collection, {
67
+ pageSize,
68
+ initialPageParam,
69
+ initialPageCount
70
+ });
71
+ previousController = currentController;
72
+ return currentController;
73
+ });
74
+ const snapshot = vue.shallowRef(controller.value.getSnapshot());
75
+ vue.watchEffect(
76
+ (onInvalidate) => {
77
+ const currentController = controller.value;
78
+ const updateSnapshot = () => {
79
+ snapshot.value = currentController.getSnapshot();
80
+ };
81
+ updateSnapshot();
82
+ const unsubscribe = currentController.subscribe(updateSnapshot);
83
+ updateSnapshot();
84
+ onInvalidate(() => {
85
+ unsubscribe();
86
+ currentController.dispose();
87
+ });
88
+ },
89
+ { flush: `sync` }
90
+ );
91
+ return {
92
+ state: vue.computed(
93
+ () => snapshot.value.state
94
+ ),
95
+ data: vue.computed(() => snapshot.value.data),
96
+ collection: vue.computed(
97
+ () => snapshot.value.collection
98
+ ),
99
+ status: vue.computed(() => snapshot.value.status),
100
+ isLoading: vue.computed(() => snapshot.value.isLoading),
101
+ isReady: vue.computed(() => snapshot.value.isReady),
102
+ isIdle: vue.computed(() => snapshot.value.isIdle),
103
+ isError: vue.computed(() => snapshot.value.isError),
104
+ isCleanedUp: vue.computed(() => snapshot.value.isCleanedUp),
105
+ pages: vue.computed(
106
+ () => snapshot.value.pages
107
+ ),
108
+ pageParams: vue.computed(() => snapshot.value.pageParams),
109
+ fetchNextPage: () => db.fetchNextLiveQueryWindowPage(controller.value),
110
+ hasNextPage: vue.computed(() => snapshot.value.hasNextPage),
111
+ isFetchingNextPage: vue.computed(() => snapshot.value.isFetchingNextPage),
112
+ error: vue.computed(() => snapshot.value.error)
113
+ };
114
+ }
115
+ exports.useLiveInfiniteQuery = useLiveInfiniteQuery;
116
+ //# sourceMappingURL=useLiveInfiniteQuery.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveInfiniteQuery.cjs","sources":["../../src/useLiveInfiniteQuery.ts"],"sourcesContent":["import { computed, shallowRef, toValue, watchEffect } from 'vue'\nimport {\n assertLiveQueryWindowManyResult,\n compareLiveQueryWindowDependencies,\n createLiveQueryCollection,\n createLiveQueryWindowController,\n fetchNextLiveQueryWindowPage,\n getLiveQueryWindowCollectionWarning,\n normalizeLiveQueryWindowPageSize,\n resolveLiveQueryWindowInput,\n shouldPreserveLiveQueryWindowPageCount,\n} from '@tanstack/db'\nimport type {\n Collection,\n CollectionStatus,\n Context,\n GetResult,\n InferResultType,\n InitialQueryBuilder,\n NonSingleResult,\n QueryBuilder,\n UtilsRecord,\n} from '@tanstack/db'\nimport type { ComputedRef, MaybeRefOrGetter } from 'vue'\n\nconst DEFAULT_GC_TIME_MS = 1\n\ntype InternalCollection = Collection<object, string | number, UtilsRecord>\n\ntype PreviousController = {\n getSnapshot: () => { pages: ReadonlyArray<ReadonlyArray<unknown>> }\n}\n\ntype InfiniteQueryOptions = {\n pageSize?: number\n initialPageParam?: number\n}\n\nexport type LiveInfiniteQueryConfig<TRow> = InfiniteQueryOptions & {\n /**\n * @deprecated Pagination uses the shared controller's peek-ahead strategy.\n * This remains for compatibility with TanStack Query conventions.\n */\n getNextPageParam?: (\n lastPage: Array<TRow>,\n allPages: Array<Array<TRow>>,\n lastPageParam: number,\n allPageParams: Array<number>,\n ) => number | undefined\n}\n\nexport type UseLiveInfiniteQueryConfig<\n TContext extends Context & NonSingleResult,\n> = LiveInfiniteQueryConfig<InferResultType<TContext>[number]>\n\nexport interface UseLiveInfiniteQueryReturn<\n TContext extends Context & NonSingleResult,\n> {\n state: ComputedRef<Map<string | number, GetResult<TContext>>>\n data: ComputedRef<InferResultType<TContext>>\n collection: ComputedRef<\n Collection<GetResult<TContext>, string | number, UtilsRecord>\n >\n status: ComputedRef<CollectionStatus>\n isLoading: ComputedRef<boolean>\n isReady: ComputedRef<boolean>\n isIdle: ComputedRef<boolean>\n isError: ComputedRef<boolean>\n isCleanedUp: ComputedRef<boolean>\n pages: ComputedRef<Array<Array<InferResultType<TContext>[number]>>>\n pageParams: ComputedRef<Array<number>>\n fetchNextPage: () => Promise<void>\n hasNextPage: ComputedRef<boolean>\n isFetchingNextPage: ComputedRef<boolean>\n error: ComputedRef<unknown>\n}\n\nexport interface UseLiveInfiniteQueryReturnWithCollection<\n TResult extends object,\n TKey extends string | number,\n TUtils extends UtilsRecord,\n> {\n state: ComputedRef<Map<TKey, TResult>>\n data: ComputedRef<Array<TResult>>\n collection: ComputedRef<Collection<TResult, TKey, TUtils>>\n status: ComputedRef<CollectionStatus>\n isLoading: ComputedRef<boolean>\n isReady: ComputedRef<boolean>\n isIdle: ComputedRef<boolean>\n isError: ComputedRef<boolean>\n isCleanedUp: ComputedRef<boolean>\n pages: ComputedRef<Array<Array<TResult>>>\n pageParams: ComputedRef<Array<number>>\n fetchNextPage: () => Promise<void>\n hasNextPage: ComputedRef<boolean>\n isFetchingNextPage: ComputedRef<boolean>\n error: ComputedRef<unknown>\n}\n\n/**\n * Create a Vue-native reactive view over the shared live-query window\n * controller. The query must include an `orderBy` clause.\n */\nexport function useLiveInfiniteQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends UtilsRecord,\n>(\n liveQueryCollection: MaybeRefOrGetter<\n Collection<TResult, TKey, TUtils> & NonSingleResult\n >,\n config: LiveInfiniteQueryConfig<TResult>,\n): UseLiveInfiniteQueryReturnWithCollection<TResult, TKey, TUtils>\n\nexport function useLiveInfiniteQuery<\n TContext extends Context & NonSingleResult,\n>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n config: UseLiveInfiniteQueryConfig<TContext>,\n deps?: Array<MaybeRefOrGetter<unknown>>,\n): UseLiveInfiniteQueryReturn<TContext>\n\nexport function useLiveInfiniteQuery<\n TContext extends Context & NonSingleResult,\n>(\n queryFnOrCollection: unknown,\n config: InfiniteQueryOptions,\n deps: Array<MaybeRefOrGetter<unknown>> = [],\n): UseLiveInfiniteQueryReturn<TContext> {\n let validatedCollection: InternalCollection | null = null\n let previousController: PreviousController | null = null\n let previousInput: ReturnType<\n typeof resolveLiveQueryWindowInput<TContext>\n > | null = null\n let previousDependencies: Array<unknown> | null = null\n let previousPageSize: number | null = null\n let previousInitialPageParam: number | null = null\n\n const controller = computed(() => {\n const dependencies = deps.map((dependency) => toValue(dependency))\n\n const pageSize = normalizeLiveQueryWindowPageSize(config.pageSize)\n const initialPageParam = config.initialPageParam ?? 0\n const unwrappedInput =\n typeof queryFnOrCollection === `function`\n ? queryFnOrCollection\n : toValue(queryFnOrCollection)\n const input = resolveLiveQueryWindowInput<TContext>(unwrappedInput)\n const dependencyComparison = compareLiveQueryWindowDependencies(\n previousDependencies,\n dependencies,\n )\n const dependenciesChanged = dependencyComparison.changed\n const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual\n const pageShapeChanged =\n previousPageSize !== pageSize ||\n previousInitialPageParam !== initialPageParam\n const sameCollection =\n input.kind === `collection` &&\n previousInput?.kind === `collection` &&\n previousInput.collection === input.collection\n const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({\n hasPreviousController: previousController !== null,\n previousInputKind: previousInput?.kind,\n inputKind: input.kind,\n sameCollection,\n dependenciesChanged,\n dependenciesStructurallyEqual,\n pageShapeChanged,\n })\n const previousPageCount = previousController\n ? Math.max(1, previousController.getSnapshot().pages.length)\n : 1\n const initialPageCount = canPreservePageCount ? previousPageCount : 1\n\n previousInput = input\n previousDependencies = [...dependencies]\n previousPageSize = pageSize\n previousInitialPageParam = initialPageParam\n\n if (input.kind === `collection`) {\n const collection = input.collection\n const warning = getLiveQueryWindowCollectionWarning(\n collection,\n pageSize + 1,\n )\n\n if (validatedCollection !== collection) {\n validatedCollection = collection\n if (warning) console.warn(warning)\n }\n\n const currentController = createLiveQueryWindowController(collection, {\n pageSize,\n initialPageParam,\n initialPageCount,\n })\n previousController = currentController\n return currentController\n }\n\n const collection = createLiveQueryCollection({\n query: input.query.limit(pageSize + 1).offset(0),\n startSync: false,\n gcTime: DEFAULT_GC_TIME_MS,\n })\n assertLiveQueryWindowManyResult(collection)\n const currentController = createLiveQueryWindowController(collection, {\n pageSize,\n initialPageParam,\n initialPageCount,\n })\n previousController = currentController\n return currentController\n })\n\n const snapshot = shallowRef(controller.value.getSnapshot())\n\n watchEffect(\n (onInvalidate) => {\n const currentController = controller.value\n const updateSnapshot = () => {\n snapshot.value = currentController.getSnapshot()\n }\n\n updateSnapshot()\n const unsubscribe = currentController.subscribe(updateSnapshot)\n updateSnapshot()\n\n onInvalidate(() => {\n unsubscribe()\n currentController.dispose()\n })\n },\n { flush: `sync` },\n )\n\n return {\n state: computed(\n () => snapshot.value.state as Map<string | number, GetResult<TContext>>,\n ),\n data: computed(() => snapshot.value.data as InferResultType<TContext>),\n collection: computed(\n () =>\n snapshot.value.collection as Collection<\n GetResult<TContext>,\n string | number,\n UtilsRecord\n >,\n ),\n status: computed(() => snapshot.value.status as CollectionStatus),\n isLoading: computed(() => snapshot.value.isLoading),\n isReady: computed(() => snapshot.value.isReady),\n isIdle: computed(() => snapshot.value.isIdle),\n isError: computed(() => snapshot.value.isError),\n isCleanedUp: computed(() => snapshot.value.isCleanedUp),\n pages: computed(\n () =>\n snapshot.value.pages as Array<Array<InferResultType<TContext>[number]>>,\n ),\n pageParams: computed(() => snapshot.value.pageParams as Array<number>),\n fetchNextPage: () => fetchNextLiveQueryWindowPage(controller.value),\n hasNextPage: computed(() => snapshot.value.hasNextPage),\n isFetchingNextPage: computed(() => snapshot.value.isFetchingNextPage),\n error: computed(() => snapshot.value.error),\n }\n}\n"],"names":["computed","toValue","normalizeLiveQueryWindowPageSize","resolveLiveQueryWindowInput","compareLiveQueryWindowDependencies","shouldPreserveLiveQueryWindowPageCount","collection","getLiveQueryWindowCollectionWarning","currentController","createLiveQueryWindowController","createLiveQueryCollection","assertLiveQueryWindowManyResult","shallowRef","watchEffect","fetchNextLiveQueryWindowPage"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { Collection, CollectionStatus, Context, GetResult, InferResultType, InitialQueryBuilder, NonSingleResult, QueryBuilder, UtilsRecord } from '@tanstack/db';
2
+ import { ComputedRef, MaybeRefOrGetter } from 'vue';
3
+ type InfiniteQueryOptions = {
4
+ pageSize?: number;
5
+ initialPageParam?: number;
6
+ };
7
+ export type LiveInfiniteQueryConfig<TRow> = InfiniteQueryOptions & {
8
+ /**
9
+ * @deprecated Pagination uses the shared controller's peek-ahead strategy.
10
+ * This remains for compatibility with TanStack Query conventions.
11
+ */
12
+ getNextPageParam?: (lastPage: Array<TRow>, allPages: Array<Array<TRow>>, lastPageParam: number, allPageParams: Array<number>) => number | undefined;
13
+ };
14
+ export type UseLiveInfiniteQueryConfig<TContext extends Context & NonSingleResult> = LiveInfiniteQueryConfig<InferResultType<TContext>[number]>;
15
+ export interface UseLiveInfiniteQueryReturn<TContext extends Context & NonSingleResult> {
16
+ state: ComputedRef<Map<string | number, GetResult<TContext>>>;
17
+ data: ComputedRef<InferResultType<TContext>>;
18
+ collection: ComputedRef<Collection<GetResult<TContext>, string | number, UtilsRecord>>;
19
+ status: ComputedRef<CollectionStatus>;
20
+ isLoading: ComputedRef<boolean>;
21
+ isReady: ComputedRef<boolean>;
22
+ isIdle: ComputedRef<boolean>;
23
+ isError: ComputedRef<boolean>;
24
+ isCleanedUp: ComputedRef<boolean>;
25
+ pages: ComputedRef<Array<Array<InferResultType<TContext>[number]>>>;
26
+ pageParams: ComputedRef<Array<number>>;
27
+ fetchNextPage: () => Promise<void>;
28
+ hasNextPage: ComputedRef<boolean>;
29
+ isFetchingNextPage: ComputedRef<boolean>;
30
+ error: ComputedRef<unknown>;
31
+ }
32
+ export interface UseLiveInfiniteQueryReturnWithCollection<TResult extends object, TKey extends string | number, TUtils extends UtilsRecord> {
33
+ state: ComputedRef<Map<TKey, TResult>>;
34
+ data: ComputedRef<Array<TResult>>;
35
+ collection: ComputedRef<Collection<TResult, TKey, TUtils>>;
36
+ status: ComputedRef<CollectionStatus>;
37
+ isLoading: ComputedRef<boolean>;
38
+ isReady: ComputedRef<boolean>;
39
+ isIdle: ComputedRef<boolean>;
40
+ isError: ComputedRef<boolean>;
41
+ isCleanedUp: ComputedRef<boolean>;
42
+ pages: ComputedRef<Array<Array<TResult>>>;
43
+ pageParams: ComputedRef<Array<number>>;
44
+ fetchNextPage: () => Promise<void>;
45
+ hasNextPage: ComputedRef<boolean>;
46
+ isFetchingNextPage: ComputedRef<boolean>;
47
+ error: ComputedRef<unknown>;
48
+ }
49
+ /**
50
+ * Create a Vue-native reactive view over the shared live-query window
51
+ * controller. The query must include an `orderBy` clause.
52
+ */
53
+ export declare function useLiveInfiniteQuery<TResult extends object, TKey extends string | number, TUtils extends UtilsRecord>(liveQueryCollection: MaybeRefOrGetter<Collection<TResult, TKey, TUtils> & NonSingleResult>, config: LiveInfiniteQueryConfig<TResult>): UseLiveInfiniteQueryReturnWithCollection<TResult, TKey, TUtils>;
54
+ export declare function useLiveInfiniteQuery<TContext extends Context & NonSingleResult>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>, config: UseLiveInfiniteQueryConfig<TContext>, deps?: Array<MaybeRefOrGetter<unknown>>): UseLiveInfiniteQueryReturn<TContext>;
55
+ export {};
@@ -1,4 +1,5 @@
1
1
  export * from './useLiveQuery.js';
2
+ export * from './useLiveInfiniteQuery.js';
2
3
  export * from '@tanstack/db';
3
4
  export type { Collection } from '@tanstack/db';
4
5
  export { createTransaction } from '@tanstack/db';
package/dist/esm/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { useLiveQuery } from "./useLiveQuery.js";
2
+ import { useLiveInfiniteQuery } from "./useLiveInfiniteQuery.js";
2
3
  export * from "@tanstack/db";
3
4
  import { createTransaction } from "@tanstack/db";
4
5
  export {
5
6
  createTransaction,
7
+ useLiveInfiniteQuery,
6
8
  useLiveQuery
7
9
  };
8
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,55 @@
1
+ import { Collection, CollectionStatus, Context, GetResult, InferResultType, InitialQueryBuilder, NonSingleResult, QueryBuilder, UtilsRecord } from '@tanstack/db';
2
+ import { ComputedRef, MaybeRefOrGetter } from 'vue';
3
+ type InfiniteQueryOptions = {
4
+ pageSize?: number;
5
+ initialPageParam?: number;
6
+ };
7
+ export type LiveInfiniteQueryConfig<TRow> = InfiniteQueryOptions & {
8
+ /**
9
+ * @deprecated Pagination uses the shared controller's peek-ahead strategy.
10
+ * This remains for compatibility with TanStack Query conventions.
11
+ */
12
+ getNextPageParam?: (lastPage: Array<TRow>, allPages: Array<Array<TRow>>, lastPageParam: number, allPageParams: Array<number>) => number | undefined;
13
+ };
14
+ export type UseLiveInfiniteQueryConfig<TContext extends Context & NonSingleResult> = LiveInfiniteQueryConfig<InferResultType<TContext>[number]>;
15
+ export interface UseLiveInfiniteQueryReturn<TContext extends Context & NonSingleResult> {
16
+ state: ComputedRef<Map<string | number, GetResult<TContext>>>;
17
+ data: ComputedRef<InferResultType<TContext>>;
18
+ collection: ComputedRef<Collection<GetResult<TContext>, string | number, UtilsRecord>>;
19
+ status: ComputedRef<CollectionStatus>;
20
+ isLoading: ComputedRef<boolean>;
21
+ isReady: ComputedRef<boolean>;
22
+ isIdle: ComputedRef<boolean>;
23
+ isError: ComputedRef<boolean>;
24
+ isCleanedUp: ComputedRef<boolean>;
25
+ pages: ComputedRef<Array<Array<InferResultType<TContext>[number]>>>;
26
+ pageParams: ComputedRef<Array<number>>;
27
+ fetchNextPage: () => Promise<void>;
28
+ hasNextPage: ComputedRef<boolean>;
29
+ isFetchingNextPage: ComputedRef<boolean>;
30
+ error: ComputedRef<unknown>;
31
+ }
32
+ export interface UseLiveInfiniteQueryReturnWithCollection<TResult extends object, TKey extends string | number, TUtils extends UtilsRecord> {
33
+ state: ComputedRef<Map<TKey, TResult>>;
34
+ data: ComputedRef<Array<TResult>>;
35
+ collection: ComputedRef<Collection<TResult, TKey, TUtils>>;
36
+ status: ComputedRef<CollectionStatus>;
37
+ isLoading: ComputedRef<boolean>;
38
+ isReady: ComputedRef<boolean>;
39
+ isIdle: ComputedRef<boolean>;
40
+ isError: ComputedRef<boolean>;
41
+ isCleanedUp: ComputedRef<boolean>;
42
+ pages: ComputedRef<Array<Array<TResult>>>;
43
+ pageParams: ComputedRef<Array<number>>;
44
+ fetchNextPage: () => Promise<void>;
45
+ hasNextPage: ComputedRef<boolean>;
46
+ isFetchingNextPage: ComputedRef<boolean>;
47
+ error: ComputedRef<unknown>;
48
+ }
49
+ /**
50
+ * Create a Vue-native reactive view over the shared live-query window
51
+ * controller. The query must include an `orderBy` clause.
52
+ */
53
+ export declare function useLiveInfiniteQuery<TResult extends object, TKey extends string | number, TUtils extends UtilsRecord>(liveQueryCollection: MaybeRefOrGetter<Collection<TResult, TKey, TUtils> & NonSingleResult>, config: LiveInfiniteQueryConfig<TResult>): UseLiveInfiniteQueryReturnWithCollection<TResult, TKey, TUtils>;
54
+ export declare function useLiveInfiniteQuery<TContext extends Context & NonSingleResult>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>, config: UseLiveInfiniteQueryConfig<TContext>, deps?: Array<MaybeRefOrGetter<unknown>>): UseLiveInfiniteQueryReturn<TContext>;
55
+ export {};
@@ -0,0 +1,116 @@
1
+ import { computed, toValue, shallowRef, watchEffect } from "vue";
2
+ import { normalizeLiveQueryWindowPageSize, resolveLiveQueryWindowInput, compareLiveQueryWindowDependencies, shouldPreserveLiveQueryWindowPageCount, getLiveQueryWindowCollectionWarning, createLiveQueryWindowController, createLiveQueryCollection, assertLiveQueryWindowManyResult, fetchNextLiveQueryWindowPage } from "@tanstack/db";
3
+ const DEFAULT_GC_TIME_MS = 1;
4
+ function useLiveInfiniteQuery(queryFnOrCollection, config, deps = []) {
5
+ let validatedCollection = null;
6
+ let previousController = null;
7
+ let previousInput = null;
8
+ let previousDependencies = null;
9
+ let previousPageSize = null;
10
+ let previousInitialPageParam = null;
11
+ const controller = computed(() => {
12
+ const dependencies = deps.map((dependency) => toValue(dependency));
13
+ const pageSize = normalizeLiveQueryWindowPageSize(config.pageSize);
14
+ const initialPageParam = config.initialPageParam ?? 0;
15
+ const unwrappedInput = typeof queryFnOrCollection === `function` ? queryFnOrCollection : toValue(queryFnOrCollection);
16
+ const input = resolveLiveQueryWindowInput(unwrappedInput);
17
+ const dependencyComparison = compareLiveQueryWindowDependencies(
18
+ previousDependencies,
19
+ dependencies
20
+ );
21
+ const dependenciesChanged = dependencyComparison.changed;
22
+ const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual;
23
+ const pageShapeChanged = previousPageSize !== pageSize || previousInitialPageParam !== initialPageParam;
24
+ const sameCollection = input.kind === `collection` && previousInput?.kind === `collection` && previousInput.collection === input.collection;
25
+ const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({
26
+ hasPreviousController: previousController !== null,
27
+ previousInputKind: previousInput?.kind,
28
+ inputKind: input.kind,
29
+ sameCollection,
30
+ dependenciesChanged,
31
+ dependenciesStructurallyEqual,
32
+ pageShapeChanged
33
+ });
34
+ const previousPageCount = previousController ? Math.max(1, previousController.getSnapshot().pages.length) : 1;
35
+ const initialPageCount = canPreservePageCount ? previousPageCount : 1;
36
+ previousInput = input;
37
+ previousDependencies = [...dependencies];
38
+ previousPageSize = pageSize;
39
+ previousInitialPageParam = initialPageParam;
40
+ if (input.kind === `collection`) {
41
+ const collection2 = input.collection;
42
+ const warning = getLiveQueryWindowCollectionWarning(
43
+ collection2,
44
+ pageSize + 1
45
+ );
46
+ if (validatedCollection !== collection2) {
47
+ validatedCollection = collection2;
48
+ if (warning) console.warn(warning);
49
+ }
50
+ const currentController2 = createLiveQueryWindowController(collection2, {
51
+ pageSize,
52
+ initialPageParam,
53
+ initialPageCount
54
+ });
55
+ previousController = currentController2;
56
+ return currentController2;
57
+ }
58
+ const collection = createLiveQueryCollection({
59
+ query: input.query.limit(pageSize + 1).offset(0),
60
+ startSync: false,
61
+ gcTime: DEFAULT_GC_TIME_MS
62
+ });
63
+ assertLiveQueryWindowManyResult(collection);
64
+ const currentController = createLiveQueryWindowController(collection, {
65
+ pageSize,
66
+ initialPageParam,
67
+ initialPageCount
68
+ });
69
+ previousController = currentController;
70
+ return currentController;
71
+ });
72
+ const snapshot = shallowRef(controller.value.getSnapshot());
73
+ watchEffect(
74
+ (onInvalidate) => {
75
+ const currentController = controller.value;
76
+ const updateSnapshot = () => {
77
+ snapshot.value = currentController.getSnapshot();
78
+ };
79
+ updateSnapshot();
80
+ const unsubscribe = currentController.subscribe(updateSnapshot);
81
+ updateSnapshot();
82
+ onInvalidate(() => {
83
+ unsubscribe();
84
+ currentController.dispose();
85
+ });
86
+ },
87
+ { flush: `sync` }
88
+ );
89
+ return {
90
+ state: computed(
91
+ () => snapshot.value.state
92
+ ),
93
+ data: computed(() => snapshot.value.data),
94
+ collection: computed(
95
+ () => snapshot.value.collection
96
+ ),
97
+ status: computed(() => snapshot.value.status),
98
+ isLoading: computed(() => snapshot.value.isLoading),
99
+ isReady: computed(() => snapshot.value.isReady),
100
+ isIdle: computed(() => snapshot.value.isIdle),
101
+ isError: computed(() => snapshot.value.isError),
102
+ isCleanedUp: computed(() => snapshot.value.isCleanedUp),
103
+ pages: computed(
104
+ () => snapshot.value.pages
105
+ ),
106
+ pageParams: computed(() => snapshot.value.pageParams),
107
+ fetchNextPage: () => fetchNextLiveQueryWindowPage(controller.value),
108
+ hasNextPage: computed(() => snapshot.value.hasNextPage),
109
+ isFetchingNextPage: computed(() => snapshot.value.isFetchingNextPage),
110
+ error: computed(() => snapshot.value.error)
111
+ };
112
+ }
113
+ export {
114
+ useLiveInfiniteQuery
115
+ };
116
+ //# sourceMappingURL=useLiveInfiniteQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveInfiniteQuery.js","sources":["../../src/useLiveInfiniteQuery.ts"],"sourcesContent":["import { computed, shallowRef, toValue, watchEffect } from 'vue'\nimport {\n assertLiveQueryWindowManyResult,\n compareLiveQueryWindowDependencies,\n createLiveQueryCollection,\n createLiveQueryWindowController,\n fetchNextLiveQueryWindowPage,\n getLiveQueryWindowCollectionWarning,\n normalizeLiveQueryWindowPageSize,\n resolveLiveQueryWindowInput,\n shouldPreserveLiveQueryWindowPageCount,\n} from '@tanstack/db'\nimport type {\n Collection,\n CollectionStatus,\n Context,\n GetResult,\n InferResultType,\n InitialQueryBuilder,\n NonSingleResult,\n QueryBuilder,\n UtilsRecord,\n} from '@tanstack/db'\nimport type { ComputedRef, MaybeRefOrGetter } from 'vue'\n\nconst DEFAULT_GC_TIME_MS = 1\n\ntype InternalCollection = Collection<object, string | number, UtilsRecord>\n\ntype PreviousController = {\n getSnapshot: () => { pages: ReadonlyArray<ReadonlyArray<unknown>> }\n}\n\ntype InfiniteQueryOptions = {\n pageSize?: number\n initialPageParam?: number\n}\n\nexport type LiveInfiniteQueryConfig<TRow> = InfiniteQueryOptions & {\n /**\n * @deprecated Pagination uses the shared controller's peek-ahead strategy.\n * This remains for compatibility with TanStack Query conventions.\n */\n getNextPageParam?: (\n lastPage: Array<TRow>,\n allPages: Array<Array<TRow>>,\n lastPageParam: number,\n allPageParams: Array<number>,\n ) => number | undefined\n}\n\nexport type UseLiveInfiniteQueryConfig<\n TContext extends Context & NonSingleResult,\n> = LiveInfiniteQueryConfig<InferResultType<TContext>[number]>\n\nexport interface UseLiveInfiniteQueryReturn<\n TContext extends Context & NonSingleResult,\n> {\n state: ComputedRef<Map<string | number, GetResult<TContext>>>\n data: ComputedRef<InferResultType<TContext>>\n collection: ComputedRef<\n Collection<GetResult<TContext>, string | number, UtilsRecord>\n >\n status: ComputedRef<CollectionStatus>\n isLoading: ComputedRef<boolean>\n isReady: ComputedRef<boolean>\n isIdle: ComputedRef<boolean>\n isError: ComputedRef<boolean>\n isCleanedUp: ComputedRef<boolean>\n pages: ComputedRef<Array<Array<InferResultType<TContext>[number]>>>\n pageParams: ComputedRef<Array<number>>\n fetchNextPage: () => Promise<void>\n hasNextPage: ComputedRef<boolean>\n isFetchingNextPage: ComputedRef<boolean>\n error: ComputedRef<unknown>\n}\n\nexport interface UseLiveInfiniteQueryReturnWithCollection<\n TResult extends object,\n TKey extends string | number,\n TUtils extends UtilsRecord,\n> {\n state: ComputedRef<Map<TKey, TResult>>\n data: ComputedRef<Array<TResult>>\n collection: ComputedRef<Collection<TResult, TKey, TUtils>>\n status: ComputedRef<CollectionStatus>\n isLoading: ComputedRef<boolean>\n isReady: ComputedRef<boolean>\n isIdle: ComputedRef<boolean>\n isError: ComputedRef<boolean>\n isCleanedUp: ComputedRef<boolean>\n pages: ComputedRef<Array<Array<TResult>>>\n pageParams: ComputedRef<Array<number>>\n fetchNextPage: () => Promise<void>\n hasNextPage: ComputedRef<boolean>\n isFetchingNextPage: ComputedRef<boolean>\n error: ComputedRef<unknown>\n}\n\n/**\n * Create a Vue-native reactive view over the shared live-query window\n * controller. The query must include an `orderBy` clause.\n */\nexport function useLiveInfiniteQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends UtilsRecord,\n>(\n liveQueryCollection: MaybeRefOrGetter<\n Collection<TResult, TKey, TUtils> & NonSingleResult\n >,\n config: LiveInfiniteQueryConfig<TResult>,\n): UseLiveInfiniteQueryReturnWithCollection<TResult, TKey, TUtils>\n\nexport function useLiveInfiniteQuery<\n TContext extends Context & NonSingleResult,\n>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,\n config: UseLiveInfiniteQueryConfig<TContext>,\n deps?: Array<MaybeRefOrGetter<unknown>>,\n): UseLiveInfiniteQueryReturn<TContext>\n\nexport function useLiveInfiniteQuery<\n TContext extends Context & NonSingleResult,\n>(\n queryFnOrCollection: unknown,\n config: InfiniteQueryOptions,\n deps: Array<MaybeRefOrGetter<unknown>> = [],\n): UseLiveInfiniteQueryReturn<TContext> {\n let validatedCollection: InternalCollection | null = null\n let previousController: PreviousController | null = null\n let previousInput: ReturnType<\n typeof resolveLiveQueryWindowInput<TContext>\n > | null = null\n let previousDependencies: Array<unknown> | null = null\n let previousPageSize: number | null = null\n let previousInitialPageParam: number | null = null\n\n const controller = computed(() => {\n const dependencies = deps.map((dependency) => toValue(dependency))\n\n const pageSize = normalizeLiveQueryWindowPageSize(config.pageSize)\n const initialPageParam = config.initialPageParam ?? 0\n const unwrappedInput =\n typeof queryFnOrCollection === `function`\n ? queryFnOrCollection\n : toValue(queryFnOrCollection)\n const input = resolveLiveQueryWindowInput<TContext>(unwrappedInput)\n const dependencyComparison = compareLiveQueryWindowDependencies(\n previousDependencies,\n dependencies,\n )\n const dependenciesChanged = dependencyComparison.changed\n const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual\n const pageShapeChanged =\n previousPageSize !== pageSize ||\n previousInitialPageParam !== initialPageParam\n const sameCollection =\n input.kind === `collection` &&\n previousInput?.kind === `collection` &&\n previousInput.collection === input.collection\n const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({\n hasPreviousController: previousController !== null,\n previousInputKind: previousInput?.kind,\n inputKind: input.kind,\n sameCollection,\n dependenciesChanged,\n dependenciesStructurallyEqual,\n pageShapeChanged,\n })\n const previousPageCount = previousController\n ? Math.max(1, previousController.getSnapshot().pages.length)\n : 1\n const initialPageCount = canPreservePageCount ? previousPageCount : 1\n\n previousInput = input\n previousDependencies = [...dependencies]\n previousPageSize = pageSize\n previousInitialPageParam = initialPageParam\n\n if (input.kind === `collection`) {\n const collection = input.collection\n const warning = getLiveQueryWindowCollectionWarning(\n collection,\n pageSize + 1,\n )\n\n if (validatedCollection !== collection) {\n validatedCollection = collection\n if (warning) console.warn(warning)\n }\n\n const currentController = createLiveQueryWindowController(collection, {\n pageSize,\n initialPageParam,\n initialPageCount,\n })\n previousController = currentController\n return currentController\n }\n\n const collection = createLiveQueryCollection({\n query: input.query.limit(pageSize + 1).offset(0),\n startSync: false,\n gcTime: DEFAULT_GC_TIME_MS,\n })\n assertLiveQueryWindowManyResult(collection)\n const currentController = createLiveQueryWindowController(collection, {\n pageSize,\n initialPageParam,\n initialPageCount,\n })\n previousController = currentController\n return currentController\n })\n\n const snapshot = shallowRef(controller.value.getSnapshot())\n\n watchEffect(\n (onInvalidate) => {\n const currentController = controller.value\n const updateSnapshot = () => {\n snapshot.value = currentController.getSnapshot()\n }\n\n updateSnapshot()\n const unsubscribe = currentController.subscribe(updateSnapshot)\n updateSnapshot()\n\n onInvalidate(() => {\n unsubscribe()\n currentController.dispose()\n })\n },\n { flush: `sync` },\n )\n\n return {\n state: computed(\n () => snapshot.value.state as Map<string | number, GetResult<TContext>>,\n ),\n data: computed(() => snapshot.value.data as InferResultType<TContext>),\n collection: computed(\n () =>\n snapshot.value.collection as Collection<\n GetResult<TContext>,\n string | number,\n UtilsRecord\n >,\n ),\n status: computed(() => snapshot.value.status as CollectionStatus),\n isLoading: computed(() => snapshot.value.isLoading),\n isReady: computed(() => snapshot.value.isReady),\n isIdle: computed(() => snapshot.value.isIdle),\n isError: computed(() => snapshot.value.isError),\n isCleanedUp: computed(() => snapshot.value.isCleanedUp),\n pages: computed(\n () =>\n snapshot.value.pages as Array<Array<InferResultType<TContext>[number]>>,\n ),\n pageParams: computed(() => snapshot.value.pageParams as Array<number>),\n fetchNextPage: () => fetchNextLiveQueryWindowPage(controller.value),\n hasNextPage: computed(() => snapshot.value.hasNextPage),\n isFetchingNextPage: computed(() => snapshot.value.isFetchingNextPage),\n error: computed(() => snapshot.value.error),\n }\n}\n"],"names":["collection","currentController"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/vue-db",
3
- "version": "0.0.129",
3
+ "version": "0.1.1",
4
4
  "description": "Vue integration for @tanstack/db",
5
5
  "author": "Kyle Mathews",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "skills"
41
41
  ],
42
42
  "dependencies": {
43
- "@tanstack/db": "0.7.0"
43
+ "@tanstack/db": "0.7.2"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "vue": ">=3.3.0"
@@ -10,7 +10,7 @@ description: >
10
10
  type: framework
11
11
  library: db
12
12
  framework: vue
13
- library_version: '0.6.0'
13
+ library_version: '0.6.17'
14
14
  requires:
15
15
  - db-core
16
16
  sources:
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  // Re-export all public APIs
2
2
  export * from './useLiveQuery'
3
+ export * from './useLiveInfiniteQuery'
3
4
 
4
5
  // Re-export everything from @tanstack/db
5
6
  export * from '@tanstack/db'
@@ -0,0 +1,267 @@
1
+ import { computed, shallowRef, toValue, watchEffect } from 'vue'
2
+ import {
3
+ assertLiveQueryWindowManyResult,
4
+ compareLiveQueryWindowDependencies,
5
+ createLiveQueryCollection,
6
+ createLiveQueryWindowController,
7
+ fetchNextLiveQueryWindowPage,
8
+ getLiveQueryWindowCollectionWarning,
9
+ normalizeLiveQueryWindowPageSize,
10
+ resolveLiveQueryWindowInput,
11
+ shouldPreserveLiveQueryWindowPageCount,
12
+ } from '@tanstack/db'
13
+ import type {
14
+ Collection,
15
+ CollectionStatus,
16
+ Context,
17
+ GetResult,
18
+ InferResultType,
19
+ InitialQueryBuilder,
20
+ NonSingleResult,
21
+ QueryBuilder,
22
+ UtilsRecord,
23
+ } from '@tanstack/db'
24
+ import type { ComputedRef, MaybeRefOrGetter } from 'vue'
25
+
26
+ const DEFAULT_GC_TIME_MS = 1
27
+
28
+ type InternalCollection = Collection<object, string | number, UtilsRecord>
29
+
30
+ type PreviousController = {
31
+ getSnapshot: () => { pages: ReadonlyArray<ReadonlyArray<unknown>> }
32
+ }
33
+
34
+ type InfiniteQueryOptions = {
35
+ pageSize?: number
36
+ initialPageParam?: number
37
+ }
38
+
39
+ export type LiveInfiniteQueryConfig<TRow> = InfiniteQueryOptions & {
40
+ /**
41
+ * @deprecated Pagination uses the shared controller's peek-ahead strategy.
42
+ * This remains for compatibility with TanStack Query conventions.
43
+ */
44
+ getNextPageParam?: (
45
+ lastPage: Array<TRow>,
46
+ allPages: Array<Array<TRow>>,
47
+ lastPageParam: number,
48
+ allPageParams: Array<number>,
49
+ ) => number | undefined
50
+ }
51
+
52
+ export type UseLiveInfiniteQueryConfig<
53
+ TContext extends Context & NonSingleResult,
54
+ > = LiveInfiniteQueryConfig<InferResultType<TContext>[number]>
55
+
56
+ export interface UseLiveInfiniteQueryReturn<
57
+ TContext extends Context & NonSingleResult,
58
+ > {
59
+ state: ComputedRef<Map<string | number, GetResult<TContext>>>
60
+ data: ComputedRef<InferResultType<TContext>>
61
+ collection: ComputedRef<
62
+ Collection<GetResult<TContext>, string | number, UtilsRecord>
63
+ >
64
+ status: ComputedRef<CollectionStatus>
65
+ isLoading: ComputedRef<boolean>
66
+ isReady: ComputedRef<boolean>
67
+ isIdle: ComputedRef<boolean>
68
+ isError: ComputedRef<boolean>
69
+ isCleanedUp: ComputedRef<boolean>
70
+ pages: ComputedRef<Array<Array<InferResultType<TContext>[number]>>>
71
+ pageParams: ComputedRef<Array<number>>
72
+ fetchNextPage: () => Promise<void>
73
+ hasNextPage: ComputedRef<boolean>
74
+ isFetchingNextPage: ComputedRef<boolean>
75
+ error: ComputedRef<unknown>
76
+ }
77
+
78
+ export interface UseLiveInfiniteQueryReturnWithCollection<
79
+ TResult extends object,
80
+ TKey extends string | number,
81
+ TUtils extends UtilsRecord,
82
+ > {
83
+ state: ComputedRef<Map<TKey, TResult>>
84
+ data: ComputedRef<Array<TResult>>
85
+ collection: ComputedRef<Collection<TResult, TKey, TUtils>>
86
+ status: ComputedRef<CollectionStatus>
87
+ isLoading: ComputedRef<boolean>
88
+ isReady: ComputedRef<boolean>
89
+ isIdle: ComputedRef<boolean>
90
+ isError: ComputedRef<boolean>
91
+ isCleanedUp: ComputedRef<boolean>
92
+ pages: ComputedRef<Array<Array<TResult>>>
93
+ pageParams: ComputedRef<Array<number>>
94
+ fetchNextPage: () => Promise<void>
95
+ hasNextPage: ComputedRef<boolean>
96
+ isFetchingNextPage: ComputedRef<boolean>
97
+ error: ComputedRef<unknown>
98
+ }
99
+
100
+ /**
101
+ * Create a Vue-native reactive view over the shared live-query window
102
+ * controller. The query must include an `orderBy` clause.
103
+ */
104
+ export function useLiveInfiniteQuery<
105
+ TResult extends object,
106
+ TKey extends string | number,
107
+ TUtils extends UtilsRecord,
108
+ >(
109
+ liveQueryCollection: MaybeRefOrGetter<
110
+ Collection<TResult, TKey, TUtils> & NonSingleResult
111
+ >,
112
+ config: LiveInfiniteQueryConfig<TResult>,
113
+ ): UseLiveInfiniteQueryReturnWithCollection<TResult, TKey, TUtils>
114
+
115
+ export function useLiveInfiniteQuery<
116
+ TContext extends Context & NonSingleResult,
117
+ >(
118
+ queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>,
119
+ config: UseLiveInfiniteQueryConfig<TContext>,
120
+ deps?: Array<MaybeRefOrGetter<unknown>>,
121
+ ): UseLiveInfiniteQueryReturn<TContext>
122
+
123
+ export function useLiveInfiniteQuery<
124
+ TContext extends Context & NonSingleResult,
125
+ >(
126
+ queryFnOrCollection: unknown,
127
+ config: InfiniteQueryOptions,
128
+ deps: Array<MaybeRefOrGetter<unknown>> = [],
129
+ ): UseLiveInfiniteQueryReturn<TContext> {
130
+ let validatedCollection: InternalCollection | null = null
131
+ let previousController: PreviousController | null = null
132
+ let previousInput: ReturnType<
133
+ typeof resolveLiveQueryWindowInput<TContext>
134
+ > | null = null
135
+ let previousDependencies: Array<unknown> | null = null
136
+ let previousPageSize: number | null = null
137
+ let previousInitialPageParam: number | null = null
138
+
139
+ const controller = computed(() => {
140
+ const dependencies = deps.map((dependency) => toValue(dependency))
141
+
142
+ const pageSize = normalizeLiveQueryWindowPageSize(config.pageSize)
143
+ const initialPageParam = config.initialPageParam ?? 0
144
+ const unwrappedInput =
145
+ typeof queryFnOrCollection === `function`
146
+ ? queryFnOrCollection
147
+ : toValue(queryFnOrCollection)
148
+ const input = resolveLiveQueryWindowInput<TContext>(unwrappedInput)
149
+ const dependencyComparison = compareLiveQueryWindowDependencies(
150
+ previousDependencies,
151
+ dependencies,
152
+ )
153
+ const dependenciesChanged = dependencyComparison.changed
154
+ const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual
155
+ const pageShapeChanged =
156
+ previousPageSize !== pageSize ||
157
+ previousInitialPageParam !== initialPageParam
158
+ const sameCollection =
159
+ input.kind === `collection` &&
160
+ previousInput?.kind === `collection` &&
161
+ previousInput.collection === input.collection
162
+ const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({
163
+ hasPreviousController: previousController !== null,
164
+ previousInputKind: previousInput?.kind,
165
+ inputKind: input.kind,
166
+ sameCollection,
167
+ dependenciesChanged,
168
+ dependenciesStructurallyEqual,
169
+ pageShapeChanged,
170
+ })
171
+ const previousPageCount = previousController
172
+ ? Math.max(1, previousController.getSnapshot().pages.length)
173
+ : 1
174
+ const initialPageCount = canPreservePageCount ? previousPageCount : 1
175
+
176
+ previousInput = input
177
+ previousDependencies = [...dependencies]
178
+ previousPageSize = pageSize
179
+ previousInitialPageParam = initialPageParam
180
+
181
+ if (input.kind === `collection`) {
182
+ const collection = input.collection
183
+ const warning = getLiveQueryWindowCollectionWarning(
184
+ collection,
185
+ pageSize + 1,
186
+ )
187
+
188
+ if (validatedCollection !== collection) {
189
+ validatedCollection = collection
190
+ if (warning) console.warn(warning)
191
+ }
192
+
193
+ const currentController = createLiveQueryWindowController(collection, {
194
+ pageSize,
195
+ initialPageParam,
196
+ initialPageCount,
197
+ })
198
+ previousController = currentController
199
+ return currentController
200
+ }
201
+
202
+ const collection = createLiveQueryCollection({
203
+ query: input.query.limit(pageSize + 1).offset(0),
204
+ startSync: false,
205
+ gcTime: DEFAULT_GC_TIME_MS,
206
+ })
207
+ assertLiveQueryWindowManyResult(collection)
208
+ const currentController = createLiveQueryWindowController(collection, {
209
+ pageSize,
210
+ initialPageParam,
211
+ initialPageCount,
212
+ })
213
+ previousController = currentController
214
+ return currentController
215
+ })
216
+
217
+ const snapshot = shallowRef(controller.value.getSnapshot())
218
+
219
+ watchEffect(
220
+ (onInvalidate) => {
221
+ const currentController = controller.value
222
+ const updateSnapshot = () => {
223
+ snapshot.value = currentController.getSnapshot()
224
+ }
225
+
226
+ updateSnapshot()
227
+ const unsubscribe = currentController.subscribe(updateSnapshot)
228
+ updateSnapshot()
229
+
230
+ onInvalidate(() => {
231
+ unsubscribe()
232
+ currentController.dispose()
233
+ })
234
+ },
235
+ { flush: `sync` },
236
+ )
237
+
238
+ return {
239
+ state: computed(
240
+ () => snapshot.value.state as Map<string | number, GetResult<TContext>>,
241
+ ),
242
+ data: computed(() => snapshot.value.data as InferResultType<TContext>),
243
+ collection: computed(
244
+ () =>
245
+ snapshot.value.collection as Collection<
246
+ GetResult<TContext>,
247
+ string | number,
248
+ UtilsRecord
249
+ >,
250
+ ),
251
+ status: computed(() => snapshot.value.status as CollectionStatus),
252
+ isLoading: computed(() => snapshot.value.isLoading),
253
+ isReady: computed(() => snapshot.value.isReady),
254
+ isIdle: computed(() => snapshot.value.isIdle),
255
+ isError: computed(() => snapshot.value.isError),
256
+ isCleanedUp: computed(() => snapshot.value.isCleanedUp),
257
+ pages: computed(
258
+ () =>
259
+ snapshot.value.pages as Array<Array<InferResultType<TContext>[number]>>,
260
+ ),
261
+ pageParams: computed(() => snapshot.value.pageParams as Array<number>),
262
+ fetchNextPage: () => fetchNextLiveQueryWindowPage(controller.value),
263
+ hasNextPage: computed(() => snapshot.value.hasNextPage),
264
+ isFetchingNextPage: computed(() => snapshot.value.isFetchingNextPage),
265
+ error: computed(() => snapshot.value.error),
266
+ }
267
+ }