@tanstack/solid-db 0.0.27 → 0.0.28
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/LICENSE +21 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/useLiveQuery.d.ts +166 -0
- package/dist/esm/useLiveQuery.js +96 -0
- package/dist/esm/useLiveQuery.js.map +1 -0
- package/package.json +6 -7
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Kyle Mathews
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { ReactiveMap } from '@solid-primitives/map';
|
|
2
|
+
import { Accessor } from 'solid-js';
|
|
3
|
+
import { Collection, CollectionStatus, Context, GetResult, InitialQueryBuilder, LiveQueryCollectionConfig, QueryBuilder } from '@tanstack/db';
|
|
4
|
+
/**
|
|
5
|
+
* Create a live query using a query function
|
|
6
|
+
* @param queryFn - Query function that defines what data to fetch
|
|
7
|
+
* @returns Object with reactive data, state, and status information
|
|
8
|
+
* @example
|
|
9
|
+
* // Basic query with object syntax
|
|
10
|
+
* const todosQuery = useLiveQuery((q) =>
|
|
11
|
+
* q.from({ todos: todosCollection })
|
|
12
|
+
* .where(({ todos }) => eq(todos.completed, false))
|
|
13
|
+
* .select(({ todos }) => ({ id: todos.id, text: todos.text }))
|
|
14
|
+
* )
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // With dependencies that trigger re-execution
|
|
18
|
+
* const todosQuery = useLiveQuery(
|
|
19
|
+
* (q) => q.from({ todos: todosCollection })
|
|
20
|
+
* .where(({ todos }) => gt(todos.priority, minPriority())),
|
|
21
|
+
* )
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // Join pattern
|
|
25
|
+
* const personIssues = useLiveQuery((q) =>
|
|
26
|
+
* q.from({ issues: issueCollection })
|
|
27
|
+
* .join({ persons: personCollection }, ({ issues, persons }) =>
|
|
28
|
+
* eq(issues.userId, persons.id)
|
|
29
|
+
* )
|
|
30
|
+
* .select(({ issues, persons }) => ({
|
|
31
|
+
* id: issues.id,
|
|
32
|
+
* title: issues.title,
|
|
33
|
+
* userName: persons.name
|
|
34
|
+
* }))
|
|
35
|
+
* )
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // Handle loading and error states
|
|
39
|
+
* const todosQuery = useLiveQuery((q) =>
|
|
40
|
+
* q.from({ todos: todoCollection })
|
|
41
|
+
* )
|
|
42
|
+
*
|
|
43
|
+
* return (
|
|
44
|
+
* <Switch>
|
|
45
|
+
* <Match when={todosQuery.isLoading()}>
|
|
46
|
+
* <div>Loading...</div>
|
|
47
|
+
* </Match>
|
|
48
|
+
* <Match when={todosQuery.isError()}>
|
|
49
|
+
* <div>Error: {todosQuery.status()}</div>
|
|
50
|
+
* </Match>
|
|
51
|
+
* <Match when={todosQuery.isReady()}>
|
|
52
|
+
* <For each={todosQuery.data()}>
|
|
53
|
+
* {(todo) => <li key={todo.id}>{todo.text}</li>}
|
|
54
|
+
* </For>
|
|
55
|
+
* </Match>
|
|
56
|
+
* </Switch>
|
|
57
|
+
* )
|
|
58
|
+
*/
|
|
59
|
+
export declare function useLiveQuery<TContext extends Context>(queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>): {
|
|
60
|
+
state: ReactiveMap<string | number, GetResult<TContext>>;
|
|
61
|
+
data: Array<GetResult<TContext>>;
|
|
62
|
+
collection: Accessor<Collection<GetResult<TContext>, string | number, {}>>;
|
|
63
|
+
status: Accessor<CollectionStatus>;
|
|
64
|
+
isLoading: Accessor<boolean>;
|
|
65
|
+
isReady: Accessor<boolean>;
|
|
66
|
+
isIdle: Accessor<boolean>;
|
|
67
|
+
isError: Accessor<boolean>;
|
|
68
|
+
isCleanedUp: Accessor<boolean>;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Create a live query using configuration object
|
|
72
|
+
* @param config - Configuration object with query and options
|
|
73
|
+
* @returns Object with reactive data, state, and status information
|
|
74
|
+
* @example
|
|
75
|
+
* // Basic config object usage
|
|
76
|
+
* const todosQuery = useLiveQuery(() => ({
|
|
77
|
+
* query: (q) => q.from({ todos: todosCollection }),
|
|
78
|
+
* gcTime: 60000
|
|
79
|
+
* }))
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // With query builder and options
|
|
83
|
+
* const queryBuilder = new Query()
|
|
84
|
+
* .from({ persons: collection })
|
|
85
|
+
* .where(({ persons }) => gt(persons.age, 30))
|
|
86
|
+
* .select(({ persons }) => ({ id: persons.id, name: persons.name }))
|
|
87
|
+
*
|
|
88
|
+
* const personsQuery = useLiveQuery(() => ({ query: queryBuilder }))
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* // Handle all states uniformly
|
|
92
|
+
* const itemsQuery = useLiveQuery(() => ({
|
|
93
|
+
* query: (q) => q.from({ items: itemCollection })
|
|
94
|
+
* }))
|
|
95
|
+
*
|
|
96
|
+
* return (
|
|
97
|
+
* <Switch fallback={<div>{itemsQuery.data.length} items loaded</div>}>
|
|
98
|
+
* <Match when={itemsQuery.isLoading()}>
|
|
99
|
+
* <div>Loading...</div>
|
|
100
|
+
* </Match>
|
|
101
|
+
* <Match when={itemsQuery.isError()}>
|
|
102
|
+
* <div>Something went wrong</div>
|
|
103
|
+
* </Match>
|
|
104
|
+
* <Match when={!itemsQuery.isReady()}>
|
|
105
|
+
* <div>Preparing...</div>
|
|
106
|
+
* </Match>
|
|
107
|
+
* </Switch>
|
|
108
|
+
* )
|
|
109
|
+
*/
|
|
110
|
+
export declare function useLiveQuery<TContext extends Context>(config: Accessor<LiveQueryCollectionConfig<TContext>>): {
|
|
111
|
+
state: ReactiveMap<string | number, GetResult<TContext>>;
|
|
112
|
+
data: Array<GetResult<TContext>>;
|
|
113
|
+
collection: Accessor<Collection<GetResult<TContext>, string | number, {}>>;
|
|
114
|
+
status: Accessor<CollectionStatus>;
|
|
115
|
+
isLoading: Accessor<boolean>;
|
|
116
|
+
isReady: Accessor<boolean>;
|
|
117
|
+
isIdle: Accessor<boolean>;
|
|
118
|
+
isError: Accessor<boolean>;
|
|
119
|
+
isCleanedUp: Accessor<boolean>;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Subscribe to an existing live query collection
|
|
123
|
+
* @param liveQueryCollection - Pre-created live query collection to subscribe to
|
|
124
|
+
* @returns Object with reactive data, state, and status information
|
|
125
|
+
* @example
|
|
126
|
+
* // Using pre-created live query collection
|
|
127
|
+
* const myLiveQuery = createLiveQueryCollection((q) =>
|
|
128
|
+
* q.from({ todos: todosCollection }).where(({ todos }) => eq(todos.active, true))
|
|
129
|
+
* )
|
|
130
|
+
* const todosQuery = useLiveQuery(() => myLiveQuery)
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* // Access collection methods directly
|
|
134
|
+
* const existingQuery = useLiveQuery(() => existingCollection)
|
|
135
|
+
*
|
|
136
|
+
* // Use collection for mutations
|
|
137
|
+
* const handleToggle = (id) => {
|
|
138
|
+
* existingQuery.collection().update(id, draft => { draft.completed = !draft.completed })
|
|
139
|
+
* }
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* // Handle states consistently
|
|
143
|
+
* const sharedQuery = useLiveQuery(() => sharedCollection)
|
|
144
|
+
*
|
|
145
|
+
* return (
|
|
146
|
+
* <Switch fallback={<div><For each={sharedQuery.data()}>{(item) => <Item key={item.id} {...item} />}</For></div>}>
|
|
147
|
+
* <Match when={sharedQuery.isLoading()}>
|
|
148
|
+
* <div>Loading...</div>
|
|
149
|
+
* </Match>
|
|
150
|
+
* <Match when={sharedQuery.isError()}>
|
|
151
|
+
* <div>Error loading data</div>
|
|
152
|
+
* </Match>
|
|
153
|
+
* </Switch>
|
|
154
|
+
* )
|
|
155
|
+
*/
|
|
156
|
+
export declare function useLiveQuery<TResult extends object, TKey extends string | number, TUtils extends Record<string, any>>(liveQueryCollection: Accessor<Collection<TResult, TKey, TUtils>>): {
|
|
157
|
+
state: ReactiveMap<TKey, TResult>;
|
|
158
|
+
data: Array<TResult>;
|
|
159
|
+
collection: Accessor<Collection<TResult, TKey, TUtils>>;
|
|
160
|
+
status: Accessor<CollectionStatus>;
|
|
161
|
+
isLoading: Accessor<boolean>;
|
|
162
|
+
isReady: Accessor<boolean>;
|
|
163
|
+
isIdle: Accessor<boolean>;
|
|
164
|
+
isError: Accessor<boolean>;
|
|
165
|
+
isCleanedUp: Accessor<boolean>;
|
|
166
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createMemo, createSignal, createComputed, batch, createResource, onCleanup } from "solid-js";
|
|
2
|
+
import { ReactiveMap } from "@solid-primitives/map";
|
|
3
|
+
import { createLiveQueryCollection, CollectionImpl } from "@tanstack/db";
|
|
4
|
+
import { createStore, reconcile } from "solid-js/store";
|
|
5
|
+
function useLiveQuery(configOrQueryOrCollection) {
|
|
6
|
+
const collection = createMemo(
|
|
7
|
+
() => {
|
|
8
|
+
if (configOrQueryOrCollection.length === 1) {
|
|
9
|
+
return createLiveQueryCollection({
|
|
10
|
+
query: configOrQueryOrCollection,
|
|
11
|
+
startSync: true
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const innerCollection = configOrQueryOrCollection();
|
|
15
|
+
if (innerCollection instanceof CollectionImpl) {
|
|
16
|
+
innerCollection.startSyncImmediate();
|
|
17
|
+
return innerCollection;
|
|
18
|
+
}
|
|
19
|
+
return createLiveQueryCollection({
|
|
20
|
+
...innerCollection,
|
|
21
|
+
startSync: true
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
void 0,
|
|
25
|
+
{ name: `TanstackDBCollectionMemo` }
|
|
26
|
+
);
|
|
27
|
+
const state = new ReactiveMap();
|
|
28
|
+
const [data, setData] = createStore([], {
|
|
29
|
+
name: `TanstackDBData`
|
|
30
|
+
});
|
|
31
|
+
const [status, setStatus] = createSignal(collection().status, {
|
|
32
|
+
name: `TanstackDBStatus`
|
|
33
|
+
});
|
|
34
|
+
const syncDataFromCollection = (currentCollection) => {
|
|
35
|
+
setData(
|
|
36
|
+
(prev) => reconcile(Array.from(currentCollection.values()))(prev).filter(Boolean)
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
let currentUnsubscribe = null;
|
|
40
|
+
createComputed(
|
|
41
|
+
() => {
|
|
42
|
+
const currentCollection = collection();
|
|
43
|
+
setStatus(currentCollection.status);
|
|
44
|
+
state.clear();
|
|
45
|
+
for (const [key, value] of currentCollection.entries()) {
|
|
46
|
+
state.set(key, value);
|
|
47
|
+
}
|
|
48
|
+
syncDataFromCollection(currentCollection);
|
|
49
|
+
currentUnsubscribe = currentCollection.subscribeChanges(
|
|
50
|
+
(changes) => {
|
|
51
|
+
batch(() => {
|
|
52
|
+
for (const change of changes) {
|
|
53
|
+
switch (change.type) {
|
|
54
|
+
case `insert`:
|
|
55
|
+
case `update`:
|
|
56
|
+
state.set(change.key, change.value);
|
|
57
|
+
break;
|
|
58
|
+
case `delete`:
|
|
59
|
+
state.delete(change.key);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
syncDataFromCollection(currentCollection);
|
|
65
|
+
setStatus(currentCollection.status);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
if (currentCollection.status === `idle`) {
|
|
69
|
+
createResource(() => currentCollection.preload());
|
|
70
|
+
}
|
|
71
|
+
onCleanup(() => {
|
|
72
|
+
if (currentUnsubscribe) {
|
|
73
|
+
currentUnsubscribe();
|
|
74
|
+
currentUnsubscribe = null;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
void 0,
|
|
79
|
+
{ name: `TanstackDBSyncComputed` }
|
|
80
|
+
);
|
|
81
|
+
return {
|
|
82
|
+
state,
|
|
83
|
+
data,
|
|
84
|
+
collection,
|
|
85
|
+
status,
|
|
86
|
+
isLoading: () => status() === `loading` || status() === `initialCommit`,
|
|
87
|
+
isReady: () => status() === `ready`,
|
|
88
|
+
isIdle: () => status() === `idle`,
|
|
89
|
+
isError: () => status() === `error`,
|
|
90
|
+
isCleanedUp: () => status() === `cleaned-up`
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
useLiveQuery
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=useLiveQuery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLiveQuery.js","sources":["../../src/useLiveQuery.ts"],"sourcesContent":["import {\n batch,\n createComputed,\n createMemo,\n createResource,\n createSignal,\n onCleanup,\n} from \"solid-js\"\nimport { ReactiveMap } from \"@solid-primitives/map\"\nimport { CollectionImpl, createLiveQueryCollection } from \"@tanstack/db\"\nimport { createStore, reconcile } from \"solid-js/store\"\nimport type { Accessor } from \"solid-js\"\nimport type {\n ChangeMessage,\n Collection,\n CollectionStatus,\n Context,\n GetResult,\n InitialQueryBuilder,\n LiveQueryCollectionConfig,\n QueryBuilder,\n} from \"@tanstack/db\"\n\n/**\n * Create a live query using a query function\n * @param queryFn - Query function that defines what data to fetch\n * @returns Object with reactive data, state, and status information\n * @example\n * // Basic query with object syntax\n * const todosQuery = useLiveQuery((q) =>\n * q.from({ todos: todosCollection })\n * .where(({ todos }) => eq(todos.completed, false))\n * .select(({ todos }) => ({ id: todos.id, text: todos.text }))\n * )\n *\n * @example\n * // With dependencies that trigger re-execution\n * const todosQuery = useLiveQuery(\n * (q) => q.from({ todos: todosCollection })\n * .where(({ todos }) => gt(todos.priority, minPriority())),\n * )\n *\n * @example\n * // Join pattern\n * const personIssues = useLiveQuery((q) =>\n * q.from({ issues: issueCollection })\n * .join({ persons: personCollection }, ({ issues, persons }) =>\n * eq(issues.userId, persons.id)\n * )\n * .select(({ issues, persons }) => ({\n * id: issues.id,\n * title: issues.title,\n * userName: persons.name\n * }))\n * )\n *\n * @example\n * // Handle loading and error states\n * const todosQuery = useLiveQuery((q) =>\n * q.from({ todos: todoCollection })\n * )\n *\n * return (\n * <Switch>\n * <Match when={todosQuery.isLoading()}>\n * <div>Loading...</div>\n * </Match>\n * <Match when={todosQuery.isError()}>\n * <div>Error: {todosQuery.status()}</div>\n * </Match>\n * <Match when={todosQuery.isReady()}>\n * <For each={todosQuery.data()}>\n * {(todo) => <li key={todo.id}>{todo.text}</li>}\n * </For>\n * </Match>\n * </Switch>\n * )\n */\n// Overload 1: Accept just the query function\nexport function useLiveQuery<TContext extends Context>(\n queryFn: (q: InitialQueryBuilder) => QueryBuilder<TContext>\n): {\n state: ReactiveMap<string | number, GetResult<TContext>>\n data: Array<GetResult<TContext>>\n collection: Accessor<Collection<GetResult<TContext>, string | number, {}>>\n status: Accessor<CollectionStatus>\n isLoading: Accessor<boolean>\n isReady: Accessor<boolean>\n isIdle: Accessor<boolean>\n isError: Accessor<boolean>\n isCleanedUp: Accessor<boolean>\n}\n\n/**\n * Create a live query using configuration object\n * @param config - Configuration object with query and options\n * @returns Object with reactive data, state, and status information\n * @example\n * // Basic config object usage\n * const todosQuery = useLiveQuery(() => ({\n * query: (q) => q.from({ todos: todosCollection }),\n * gcTime: 60000\n * }))\n *\n * @example\n * // With query builder and options\n * const queryBuilder = new Query()\n * .from({ persons: collection })\n * .where(({ persons }) => gt(persons.age, 30))\n * .select(({ persons }) => ({ id: persons.id, name: persons.name }))\n *\n * const personsQuery = useLiveQuery(() => ({ query: queryBuilder }))\n *\n * @example\n * // Handle all states uniformly\n * const itemsQuery = useLiveQuery(() => ({\n * query: (q) => q.from({ items: itemCollection })\n * }))\n *\n * return (\n * <Switch fallback={<div>{itemsQuery.data.length} items loaded</div>}>\n * <Match when={itemsQuery.isLoading()}>\n * <div>Loading...</div>\n * </Match>\n * <Match when={itemsQuery.isError()}>\n * <div>Something went wrong</div>\n * </Match>\n * <Match when={!itemsQuery.isReady()}>\n * <div>Preparing...</div>\n * </Match>\n * </Switch>\n * )\n */\n// Overload 2: Accept config object\nexport function useLiveQuery<TContext extends Context>(\n config: Accessor<LiveQueryCollectionConfig<TContext>>\n): {\n state: ReactiveMap<string | number, GetResult<TContext>>\n data: Array<GetResult<TContext>>\n collection: Accessor<Collection<GetResult<TContext>, string | number, {}>>\n status: Accessor<CollectionStatus>\n isLoading: Accessor<boolean>\n isReady: Accessor<boolean>\n isIdle: Accessor<boolean>\n isError: Accessor<boolean>\n isCleanedUp: Accessor<boolean>\n}\n\n/**\n * Subscribe to an existing live query collection\n * @param liveQueryCollection - Pre-created live query collection to subscribe to\n * @returns Object with reactive data, state, and status information\n * @example\n * // Using pre-created live query collection\n * const myLiveQuery = createLiveQueryCollection((q) =>\n * q.from({ todos: todosCollection }).where(({ todos }) => eq(todos.active, true))\n * )\n * const todosQuery = useLiveQuery(() => myLiveQuery)\n *\n * @example\n * // Access collection methods directly\n * const existingQuery = useLiveQuery(() => existingCollection)\n *\n * // Use collection for mutations\n * const handleToggle = (id) => {\n * existingQuery.collection().update(id, draft => { draft.completed = !draft.completed })\n * }\n *\n * @example\n * // Handle states consistently\n * const sharedQuery = useLiveQuery(() => sharedCollection)\n *\n * return (\n * <Switch fallback={<div><For each={sharedQuery.data()}>{(item) => <Item key={item.id} {...item} />}</For></div>}>\n * <Match when={sharedQuery.isLoading()}>\n * <div>Loading...</div>\n * </Match>\n * <Match when={sharedQuery.isError()}>\n * <div>Error loading data</div>\n * </Match>\n * </Switch>\n * )\n */\n// Overload 3: Accept pre-created live query collection\nexport function useLiveQuery<\n TResult extends object,\n TKey extends string | number,\n TUtils extends Record<string, any>,\n>(\n liveQueryCollection: Accessor<Collection<TResult, TKey, TUtils>>\n): {\n state: ReactiveMap<TKey, TResult>\n data: Array<TResult>\n collection: Accessor<Collection<TResult, TKey, TUtils>>\n status: Accessor<CollectionStatus>\n isLoading: Accessor<boolean>\n isReady: Accessor<boolean>\n isIdle: Accessor<boolean>\n isError: Accessor<boolean>\n isCleanedUp: Accessor<boolean>\n}\n\n// Implementation - use function overloads to infer the actual collection type\nexport function useLiveQuery(\n configOrQueryOrCollection: (queryFn?: any) => any\n) {\n const collection = createMemo(\n () => {\n if (configOrQueryOrCollection.length === 1) {\n return createLiveQueryCollection({\n query: configOrQueryOrCollection,\n startSync: true,\n })\n }\n\n const innerCollection = configOrQueryOrCollection()\n if (innerCollection instanceof CollectionImpl) {\n innerCollection.startSyncImmediate()\n return innerCollection as Collection\n }\n\n return createLiveQueryCollection({\n ...innerCollection,\n startSync: true,\n })\n },\n undefined,\n { name: `TanstackDBCollectionMemo` }\n )\n\n // Reactive state that gets updated granularly through change events\n const state = new ReactiveMap<string | number, any>()\n\n // Reactive data array that maintains sorted order\n const [data, setData] = createStore<Array<any>>([], {\n name: `TanstackDBData`,\n })\n\n // Track collection status reactively\n const [status, setStatus] = createSignal(collection().status, {\n name: `TanstackDBStatus`,\n })\n\n // Helper to sync data array from collection in correct order\n const syncDataFromCollection = (\n currentCollection: Collection<any, any, any>\n ) => {\n setData((prev) =>\n reconcile(Array.from(currentCollection.values()))(prev).filter(Boolean)\n )\n }\n\n // Track current unsubscribe function\n let currentUnsubscribe: (() => void) | null = null\n\n createComputed(\n () => {\n const currentCollection = collection()\n\n // Update status ref whenever the effect runs\n setStatus(currentCollection.status)\n\n // Initialize state with current collection data\n state.clear()\n for (const [key, value] of currentCollection.entries()) {\n state.set(key, value)\n }\n\n // Initialize data array in correct order\n syncDataFromCollection(currentCollection)\n\n // Subscribe to collection changes with granular updates\n currentUnsubscribe = currentCollection.subscribeChanges(\n (changes: Array<ChangeMessage<any>>) => {\n // Apply each change individually to the reactive state\n batch(() => {\n for (const change of changes) {\n switch (change.type) {\n case `insert`:\n case `update`:\n state.set(change.key, change.value)\n break\n case `delete`:\n state.delete(change.key)\n break\n }\n }\n })\n\n // Update the data array to maintain sorted order\n syncDataFromCollection(currentCollection)\n\n // Update status ref on every change\n setStatus(currentCollection.status)\n }\n )\n\n // Preload collection data if not already started\n if (currentCollection.status === `idle`) {\n createResource(() => currentCollection.preload())\n }\n\n // Cleanup when computed is invalidated\n onCleanup(() => {\n if (currentUnsubscribe) {\n currentUnsubscribe()\n currentUnsubscribe = null\n }\n })\n },\n undefined,\n { name: `TanstackDBSyncComputed` }\n )\n\n return {\n state,\n data,\n collection,\n status,\n isLoading: () => status() === `loading` || status() === `initialCommit`,\n isReady: () => status() === `ready`,\n isIdle: () => status() === `idle`,\n isError: () => status() === `error`,\n isCleanedUp: () => status() === `cleaned-up`,\n }\n}\n"],"names":[],"mappings":";;;;AA2MO,SAAS,aACd,2BACA;AACA,QAAM,aAAa;AAAA,IACjB,MAAM;AACJ,UAAI,0BAA0B,WAAW,GAAG;AAC1C,eAAO,0BAA0B;AAAA,UAC/B,OAAO;AAAA,UACP,WAAW;AAAA,QAAA,CACZ;AAAA,MACH;AAEA,YAAM,kBAAkB,0BAAA;AACxB,UAAI,2BAA2B,gBAAgB;AAC7C,wBAAgB,mBAAA;AAChB,eAAO;AAAA,MACT;AAEA,aAAO,0BAA0B;AAAA,QAC/B,GAAG;AAAA,QACH,WAAW;AAAA,MAAA,CACZ;AAAA,IACH;AAAA,IACA;AAAA,IACA,EAAE,MAAM,2BAAA;AAAA,EAA2B;AAIrC,QAAM,QAAQ,IAAI,YAAA;AAGlB,QAAM,CAAC,MAAM,OAAO,IAAI,YAAwB,CAAA,GAAI;AAAA,IAClD,MAAM;AAAA,EAAA,CACP;AAGD,QAAM,CAAC,QAAQ,SAAS,IAAI,aAAa,WAAA,EAAa,QAAQ;AAAA,IAC5D,MAAM;AAAA,EAAA,CACP;AAGD,QAAM,yBAAyB,CAC7B,sBACG;AACH;AAAA,MAAQ,CAAC,SACP,UAAU,MAAM,KAAK,kBAAkB,OAAA,CAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,OAAO;AAAA,IAAA;AAAA,EAE1E;AAGA,MAAI,qBAA0C;AAE9C;AAAA,IACE,MAAM;AACJ,YAAM,oBAAoB,WAAA;AAG1B,gBAAU,kBAAkB,MAAM;AAGlC,YAAM,MAAA;AACN,iBAAW,CAAC,KAAK,KAAK,KAAK,kBAAkB,WAAW;AACtD,cAAM,IAAI,KAAK,KAAK;AAAA,MACtB;AAGA,6BAAuB,iBAAiB;AAGxC,2BAAqB,kBAAkB;AAAA,QACrC,CAAC,YAAuC;AAEtC,gBAAM,MAAM;AACV,uBAAW,UAAU,SAAS;AAC5B,sBAAQ,OAAO,MAAA;AAAA,gBACb,KAAK;AAAA,gBACL,KAAK;AACH,wBAAM,IAAI,OAAO,KAAK,OAAO,KAAK;AAClC;AAAA,gBACF,KAAK;AACH,wBAAM,OAAO,OAAO,GAAG;AACvB;AAAA,cAAA;AAAA,YAEN;AAAA,UACF,CAAC;AAGD,iCAAuB,iBAAiB;AAGxC,oBAAU,kBAAkB,MAAM;AAAA,QACpC;AAAA,MAAA;AAIF,UAAI,kBAAkB,WAAW,QAAQ;AACvC,uBAAe,MAAM,kBAAkB,SAAS;AAAA,MAClD;AAGA,gBAAU,MAAM;AACd,YAAI,oBAAoB;AACtB,6BAAA;AACA,+BAAqB;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA;AAAA,IACA,EAAE,MAAM,yBAAA;AAAA,EAAyB;AAGnC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,MAAM,aAAa,aAAa,aAAa;AAAA,IACxD,SAAS,MAAM,aAAa;AAAA,IAC5B,QAAQ,MAAM,aAAa;AAAA,IAC3B,SAAS,MAAM,aAAa;AAAA,IAC5B,aAAa,MAAM,OAAA,MAAa;AAAA,EAAA;AAEpC;"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/solid-db",
|
|
3
3
|
"description": "Solid integration for @tanstack/db",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.28",
|
|
5
5
|
"author": "Kyle Mathews",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -15,10 +15,9 @@
|
|
|
15
15
|
"solid",
|
|
16
16
|
"typescript"
|
|
17
17
|
],
|
|
18
|
-
"packageManager": "pnpm@10.6.3",
|
|
19
18
|
"dependencies": {
|
|
20
19
|
"@solid-primitives/map": "^0.7.2",
|
|
21
|
-
"@tanstack/db": "
|
|
20
|
+
"@tanstack/db": "0.0.32"
|
|
22
21
|
},
|
|
23
22
|
"devDependencies": {
|
|
24
23
|
"@electric-sql/client": "1.0.0",
|
|
@@ -47,13 +46,13 @@
|
|
|
47
46
|
"peerDependencies": {
|
|
48
47
|
"solid-js": ">=1.9.0"
|
|
49
48
|
},
|
|
49
|
+
"sideEffects": false,
|
|
50
|
+
"type": "module",
|
|
51
|
+
"types": "dist/esm/index.d.ts",
|
|
50
52
|
"scripts": {
|
|
51
53
|
"build": "vite build",
|
|
52
54
|
"dev": "vite build --watch",
|
|
53
55
|
"test": "vitest --run",
|
|
54
56
|
"lint": "eslint . --fix"
|
|
55
|
-
}
|
|
56
|
-
"sideEffects": false,
|
|
57
|
-
"type": "module",
|
|
58
|
-
"types": "dist/esm/index.d.ts"
|
|
57
|
+
}
|
|
59
58
|
}
|