@tanstack/svelte-db 0.2.0 → 0.2.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,85 +1,72 @@
|
|
|
1
|
-
import { createLiveQueryCollection, createLiveQueryWindowController,
|
|
2
|
-
import { untrack } from 'svelte';
|
|
3
|
-
const DEFAULT_PAGE_SIZE = 20;
|
|
1
|
+
import { assertLiveQueryWindowManyResult, compareLiveQueryWindowDependencies, createLiveQueryCollection, createLiveQueryWindowController, fetchNextLiveQueryWindowPage, getLiveQueryWindowCollectionWarning, normalizeLiveQueryWindowPageSize, resolveLiveQueryWindowInput, shouldPreserveLiveQueryWindowPageCount, } from '@tanstack/db';
|
|
2
|
+
import { tick, untrack } from 'svelte';
|
|
4
3
|
const DEFAULT_GC_TIME_MS = 1;
|
|
5
|
-
function hasSetWindow(collection) {
|
|
6
|
-
return typeof collection.utils.setWindow === `function`;
|
|
7
|
-
}
|
|
8
|
-
function normalizePageSize(pageSize) {
|
|
9
|
-
if (pageSize === undefined ||
|
|
10
|
-
!Number.isSafeInteger(pageSize) ||
|
|
11
|
-
pageSize <= 0) {
|
|
12
|
-
return DEFAULT_PAGE_SIZE;
|
|
13
|
-
}
|
|
14
|
-
return pageSize;
|
|
15
|
-
}
|
|
16
|
-
function resolveInput(input) {
|
|
17
|
-
if (isCollection(input)) {
|
|
18
|
-
return { kind: `collection`, collection: input };
|
|
19
|
-
}
|
|
20
|
-
if (typeof input !== `function`) {
|
|
21
|
-
throw new Error(`useLiveInfiniteQuery: First argument must be either a pre-created live query collection or a query function. ` +
|
|
22
|
-
`Received: ${typeof input}`);
|
|
23
|
-
}
|
|
24
|
-
// A zero-argument function can be a reactive collection getter. Query
|
|
25
|
-
// callbacks conventionally accept the builder, so avoid probing those.
|
|
26
|
-
if (input.length === 0) {
|
|
27
|
-
try {
|
|
28
|
-
const collection = input();
|
|
29
|
-
if (isCollection(collection)) {
|
|
30
|
-
return { kind: `collection`, collection };
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// Query callbacks that close over their builder can still have arity 0.
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
kind: `query`,
|
|
39
|
-
query: input,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
4
|
export function useLiveInfiniteQuery(queryFnOrCollection, config, deps = []) {
|
|
43
5
|
let validatedCollection = null;
|
|
44
|
-
|
|
6
|
+
let previousController = null;
|
|
7
|
+
let previousInput = null;
|
|
8
|
+
let previousDependencies = null;
|
|
9
|
+
let previousPageSize = null;
|
|
10
|
+
let previousInitialPageParam = null;
|
|
11
|
+
const pageSize = $derived(normalizeLiveQueryWindowPageSize(config.pageSize));
|
|
45
12
|
const initialPageParam = $derived(config.initialPageParam ?? 0);
|
|
46
13
|
const controller = $derived.by(() => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
14
|
+
const dependencies = deps.map((dependency) => dependency());
|
|
15
|
+
const input = resolveLiveQueryWindowInput(queryFnOrCollection);
|
|
16
|
+
const dependencyComparison = compareLiveQueryWindowDependencies(previousDependencies, dependencies);
|
|
17
|
+
const dependenciesChanged = dependencyComparison.changed;
|
|
18
|
+
const dependenciesStructurallyEqual = dependencyComparison.structurallyEqual;
|
|
19
|
+
const pageShapeChanged = previousPageSize !== pageSize ||
|
|
20
|
+
previousInitialPageParam !== initialPageParam;
|
|
21
|
+
const sameCollection = input.kind === `collection` &&
|
|
22
|
+
previousInput?.kind === `collection` &&
|
|
23
|
+
previousInput.collection === input.collection;
|
|
24
|
+
const canPreservePageCount = shouldPreserveLiveQueryWindowPageCount({
|
|
25
|
+
hasPreviousController: previousController !== null,
|
|
26
|
+
previousInputKind: previousInput?.kind,
|
|
27
|
+
inputKind: input.kind,
|
|
28
|
+
sameCollection,
|
|
29
|
+
dependenciesChanged,
|
|
30
|
+
dependenciesStructurallyEqual,
|
|
31
|
+
pageShapeChanged,
|
|
32
|
+
});
|
|
33
|
+
const previousPageCount = previousController
|
|
34
|
+
? Math.max(1, previousController.getSnapshot().pages.length)
|
|
35
|
+
: 1;
|
|
36
|
+
const initialPageCount = canPreservePageCount ? previousPageCount : 1;
|
|
37
|
+
previousInput = input;
|
|
38
|
+
previousDependencies = [...dependencies];
|
|
39
|
+
previousPageSize = pageSize;
|
|
40
|
+
previousInitialPageParam = initialPageParam;
|
|
50
41
|
if (input.kind === `collection`) {
|
|
51
42
|
const collection = input.collection;
|
|
52
|
-
|
|
53
|
-
throw new Error(`useLiveInfiniteQuery: Pre-created live query collection must have an orderBy clause for infinite pagination to work. ` +
|
|
54
|
-
`Please add .orderBy() to your createLiveQueryCollection query.`);
|
|
55
|
-
}
|
|
43
|
+
const warning = getLiveQueryWindowCollectionWarning(collection, pageSize + 1);
|
|
56
44
|
if (validatedCollection !== collection) {
|
|
57
45
|
validatedCollection = collection;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (currentWindow &&
|
|
61
|
-
(currentWindow.offset !== 0 || currentWindow.limit !== expectedLimit)) {
|
|
62
|
-
console.warn(`useLiveInfiniteQuery: Pre-created collection has window {offset: ${currentWindow.offset}, limit: ${currentWindow.limit}} ` +
|
|
63
|
-
`but the hook expects {offset: 0, limit: ${expectedLimit}}. Adjusting window now.`);
|
|
64
|
-
}
|
|
46
|
+
if (warning)
|
|
47
|
+
console.warn(warning);
|
|
65
48
|
}
|
|
66
|
-
|
|
49
|
+
const currentController = createLiveQueryWindowController(collection, {
|
|
67
50
|
pageSize,
|
|
68
51
|
initialPageParam,
|
|
52
|
+
initialPageCount,
|
|
69
53
|
});
|
|
54
|
+
previousController = currentController;
|
|
55
|
+
return currentController;
|
|
70
56
|
}
|
|
71
57
|
const collection = createLiveQueryCollection({
|
|
72
|
-
query: (
|
|
73
|
-
.query(q)
|
|
74
|
-
.limit(pageSize + 1)
|
|
75
|
-
.offset(0),
|
|
58
|
+
query: input.query.limit(pageSize + 1).offset(0),
|
|
76
59
|
startSync: false,
|
|
77
60
|
gcTime: DEFAULT_GC_TIME_MS,
|
|
78
61
|
});
|
|
79
|
-
|
|
62
|
+
assertLiveQueryWindowManyResult(collection);
|
|
63
|
+
const currentController = createLiveQueryWindowController(collection, {
|
|
80
64
|
pageSize,
|
|
81
65
|
initialPageParam,
|
|
66
|
+
initialPageCount,
|
|
82
67
|
});
|
|
68
|
+
previousController = currentController;
|
|
69
|
+
return currentController;
|
|
83
70
|
});
|
|
84
71
|
let snapshot = $state.raw(untrack(() => controller.getSnapshot()));
|
|
85
72
|
$effect(() => {
|
|
@@ -94,7 +81,13 @@ export function useLiveInfiniteQuery(queryFnOrCollection, config, deps = []) {
|
|
|
94
81
|
currentController.dispose();
|
|
95
82
|
};
|
|
96
83
|
});
|
|
97
|
-
const fetchNextPage = () =>
|
|
84
|
+
const fetchNextPage = async () => {
|
|
85
|
+
// A dependency can invalidate the derived controller before Svelte runs the
|
|
86
|
+
// effect that subscribes it. Queue the imperative call until that handoff
|
|
87
|
+
// has completed so it cannot target an inactive controller.
|
|
88
|
+
await tick();
|
|
89
|
+
await fetchNextLiveQueryWindowPage(controller);
|
|
90
|
+
};
|
|
98
91
|
return {
|
|
99
92
|
get state() {
|
|
100
93
|
return snapshot.state;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/svelte-db",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Svelte integration for @tanstack/db",
|
|
5
5
|
"author": "Kyle Mathews",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"skills"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@tanstack/db": "0.7.
|
|
38
|
+
"@tanstack/db": "0.7.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"svelte": "^5.0.0"
|