@livestore/react 0.3.0-dev.11 → 0.3.0-dev.5
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/.tsbuildinfo +1 -1
- package/dist/LiveStoreContext.d.ts +3 -5
- package/dist/LiveStoreContext.d.ts.map +1 -1
- package/dist/LiveStoreContext.js +3 -7
- package/dist/LiveStoreContext.js.map +1 -1
- package/dist/LiveStoreProvider.d.ts +1 -2
- package/dist/LiveStoreProvider.d.ts.map +1 -1
- package/dist/LiveStoreProvider.js +20 -5
- package/dist/LiveStoreProvider.js.map +1 -1
- package/dist/__tests__/fixture.d.ts +9 -6
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +7 -6
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/experimental/components/LiveList.d.ts +2 -2
- package/dist/experimental/components/LiveList.d.ts.map +1 -1
- package/dist/experimental/components/LiveList.js +4 -5
- package/dist/experimental/components/LiveList.js.map +1 -1
- package/dist/mod.d.ts +1 -0
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +1 -0
- package/dist/mod.js.map +1 -1
- package/dist/useAtom.d.ts +2 -4
- package/dist/useAtom.d.ts.map +1 -1
- package/dist/useAtom.js +28 -32
- package/dist/useAtom.js.map +1 -1
- package/dist/useQuery.d.ts +3 -26
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +45 -60
- package/dist/useQuery.js.map +1 -1
- package/dist/useQuery.test.js +16 -70
- package/dist/useQuery.test.js.map +1 -1
- package/dist/useRow.d.ts +7 -10
- package/dist/useRow.d.ts.map +1 -1
- package/dist/useRow.js +19 -16
- package/dist/useRow.js.map +1 -1
- package/dist/useRow.test.js +96 -74
- package/dist/useRow.test.js.map +1 -1
- package/dist/useScopedQuery.d.ts +4 -10
- package/dist/useScopedQuery.d.ts.map +1 -1
- package/dist/useScopedQuery.js +52 -97
- package/dist/useScopedQuery.js.map +1 -1
- package/dist/useScopedQuery.test.js +12 -13
- package/dist/useScopedQuery.test.js.map +1 -1
- package/dist/utils/useStateRefWithReactiveInput.d.ts +1 -1
- package/dist/utils/useStateRefWithReactiveInput.d.ts.map +1 -1
- package/dist/utils/useStateRefWithReactiveInput.js.map +1 -1
- package/package.json +17 -18
- package/src/LiveStoreContext.ts +6 -10
- package/src/LiveStoreProvider.tsx +21 -7
- package/src/__snapshots__/useRow.test.tsx.snap +149 -337
- package/src/__tests__/fixture.tsx +10 -7
- package/src/experimental/components/LiveList.tsx +7 -8
- package/src/mod.ts +1 -0
- package/src/useAtom.ts +11 -22
- package/src/useQuery.test.tsx +67 -165
- package/src/useQuery.ts +54 -84
- package/src/useRow.test.tsx +163 -130
- package/src/useRow.ts +35 -32
- package/src/useScopedQuery.test.tsx +96 -0
- package/src/useScopedQuery.ts +142 -0
- package/src/utils/useStateRefWithReactiveInput.ts +1 -1
- package/dist/useRcRef.d.ts +0 -72
- package/dist/useRcRef.d.ts.map +0 -1
- package/dist/useRcRef.js +0 -146
- package/dist/useRcRef.js.map +0 -1
- package/dist/useRcRef.test.d.ts +0 -2
- package/dist/useRcRef.test.d.ts.map +0 -1
- package/dist/useRcRef.test.js +0 -128
- package/dist/useRcRef.test.js.map +0 -1
- package/dist/useRcResource.d.ts +0 -76
- package/dist/useRcResource.d.ts.map +0 -1
- package/dist/useRcResource.js +0 -150
- package/dist/useRcResource.js.map +0 -1
- package/dist/useRcResource.test.d.ts +0 -2
- package/dist/useRcResource.test.d.ts.map +0 -1
- package/dist/useRcResource.test.js +0 -122
- package/dist/useRcResource.test.js.map +0 -1
- package/src/__snapshots__/useQuery.test.tsx.snap +0 -2011
- package/src/useRcResource.test.tsx +0 -167
- package/src/useRcResource.ts +0 -180
package/dist/useQuery.js
CHANGED
|
@@ -3,26 +3,26 @@ import { deepEqual, indent } from '@livestore/utils';
|
|
|
3
3
|
import * as otel from '@opentelemetry/api';
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { useStore } from './LiveStoreContext.js';
|
|
6
|
-
import { useRcResource } from './useRcResource.js';
|
|
7
6
|
import { originalStackLimit } from './utils/stack-info.js';
|
|
8
7
|
import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.js';
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Example:
|
|
13
|
-
* ```tsx
|
|
14
|
-
* const App = () => {
|
|
15
|
-
* const todos = useQuery(queryDb(tables.todos.query.where({ complete: true })))
|
|
16
|
-
* return <div>{todos.map((todo) => <div key={todo.id}>{todo.title}</div>)}</div>
|
|
17
|
-
* }
|
|
18
|
-
* ```
|
|
9
|
+
* NOTE Some folks have suggested to use `React.useSyncExternalStore`, however, it's not doing anything special
|
|
10
|
+
* for what's needed here, so we handle everything manually.
|
|
19
11
|
*/
|
|
20
|
-
export const useQuery = (queryDef, options) => useQueryRef(queryDef, options).valueRef.current;
|
|
21
12
|
/**
|
|
13
|
+
* This is needed because the `React.useMemo` call below, can sometimes be called multiple times 🤷,
|
|
14
|
+
* so we need to "cache" the fact that we've already started a span for this component.
|
|
15
|
+
* The map entry is being removed again in the `React.useEffect` call below.
|
|
22
16
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
const spanAlreadyStartedCache = new Map();
|
|
18
|
+
export const useQuery = (query) => useQueryRef(query).current;
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
export const useQueryRef = (query$, parentOtelContext) => {
|
|
23
|
+
const { store } = useStore();
|
|
24
|
+
React.useDebugValue(`LiveStore:useQuery:${query$.id}:${query$.label}`);
|
|
25
|
+
// console.debug(`LiveStore:useQuery:${query$.id}:${query$.label}`)
|
|
26
26
|
const stackInfo = React.useMemo(() => {
|
|
27
27
|
Error.stackTraceLimit = 10;
|
|
28
28
|
// eslint-disable-next-line unicorn/error-message
|
|
@@ -30,29 +30,23 @@ export const useQueryRef = (queryDef, options) => {
|
|
|
30
30
|
Error.stackTraceLimit = originalStackLimit;
|
|
31
31
|
return extractStackInfoFromStackTrace(stack);
|
|
32
32
|
}, []);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
33
|
+
// The following `React.useMemo` and `React.useEffect` calls are used to start and end a span for the lifetime of this component.
|
|
34
|
+
const { span, otelContext } = React.useMemo(() => {
|
|
35
|
+
const existingSpan = spanAlreadyStartedCache.get(query$);
|
|
36
|
+
if (existingSpan !== undefined)
|
|
37
|
+
return existingSpan;
|
|
38
|
+
const span = store.otel.tracer.startSpan(`LiveStore:useQuery:${query$.label}`, { attributes: { label: query$.label, stackInfo: JSON.stringify(stackInfo) } }, parentOtelContext ?? store.otel.queriesSpanContext);
|
|
36
39
|
const otelContext = otel.trace.setSpan(otel.context.active(), span);
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
},
|
|
40
|
-
// We need to keep the queryRcRef alive a bit longer, so we have a second `useRcResource` below
|
|
41
|
-
// which takes care of disposing the queryRcRef
|
|
42
|
-
() => { });
|
|
43
|
-
const query$ = queryRcRef.value;
|
|
44
|
-
React.useDebugValue(`LiveStore:useQuery:${query$.id}:${query$.label}`);
|
|
45
|
-
// console.debug(`LiveStore:useQuery:${query$.id}:${query$.label}`)
|
|
40
|
+
spanAlreadyStartedCache.set(query$, { span, otelContext });
|
|
41
|
+
return { span, otelContext };
|
|
42
|
+
}, [parentOtelContext, query$, stackInfo, store.otel.queriesSpanContext, store.otel.tracer]);
|
|
46
43
|
const initialResult = React.useMemo(() => {
|
|
47
44
|
try {
|
|
48
|
-
return query$.run({
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
label: `useQuery:initial-run:${query$.label}`,
|
|
54
|
-
stackInfo,
|
|
55
|
-
},
|
|
45
|
+
return query$.run(otelContext, {
|
|
46
|
+
_tag: 'react',
|
|
47
|
+
api: 'useQuery',
|
|
48
|
+
label: query$.label,
|
|
49
|
+
stackInfo,
|
|
56
50
|
});
|
|
57
51
|
}
|
|
58
52
|
catch (cause) {
|
|
@@ -71,36 +65,27 @@ Stack trace:
|
|
|
71
65
|
}, [otelContext, query$, stackInfo]);
|
|
72
66
|
// We know the query has a result by the time we use it; so we can synchronously populate a default state
|
|
73
67
|
const [valueRef, setValue] = useStateRefWithReactiveInput(initialResult);
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
React.useEffect(() => () => {
|
|
69
|
+
spanAlreadyStartedCache.delete(query$);
|
|
70
|
+
span.end();
|
|
71
|
+
}, [query$, span]);
|
|
76
72
|
// Subscribe to future updates for this query
|
|
77
73
|
React.useEffect(() => {
|
|
78
|
-
// TODO double check whether we still need `activeSubscriptions`
|
|
79
74
|
query$.activeSubscriptions.add(stackInfo);
|
|
80
75
|
// Dynamic queries only set their actual label after they've been run the first time,
|
|
81
76
|
// so we're also updating the span name here.
|
|
82
|
-
span.updateName(
|
|
83
|
-
return store.subscribe(query$, {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
label: query$.label,
|
|
96
|
-
otelContext,
|
|
97
|
-
});
|
|
98
|
-
}, [stackInfo, query$, setValue, store, valueRef, otelContext, span, options?.otelSpanName]);
|
|
99
|
-
useRcResource(rcRefKey, () => ({ queryRcRef, span }), ({ queryRcRef, span }) => {
|
|
100
|
-
// console.debug('deref', queryRcRef.value.id, queryRcRef.value.label)
|
|
101
|
-
queryRcRef.deref();
|
|
102
|
-
span.end();
|
|
103
|
-
});
|
|
104
|
-
return { valueRef, queryRcRef };
|
|
77
|
+
span.updateName(`LiveStore:useQuery:${query$.label}`);
|
|
78
|
+
return store.subscribe(query$, (newValue) => {
|
|
79
|
+
// NOTE: we return a reference to the result object within LiveStore;
|
|
80
|
+
// this implies that app code must not mutate the results, or else
|
|
81
|
+
// there may be weird reactivity bugs.
|
|
82
|
+
if (deepEqual(newValue, valueRef.current) === false) {
|
|
83
|
+
setValue(newValue);
|
|
84
|
+
}
|
|
85
|
+
}, () => {
|
|
86
|
+
query$.activeSubscriptions.delete(stackInfo);
|
|
87
|
+
}, { label: query$.label, otelContext });
|
|
88
|
+
}, [stackInfo, query$, setValue, store, valueRef, otelContext, span]);
|
|
89
|
+
return valueRef;
|
|
105
90
|
};
|
|
106
91
|
//# sourceMappingURL=useQuery.js.map
|
package/dist/useQuery.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxF,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAC1C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useQuery.js","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":"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"}
|
package/dist/useQuery.test.js
CHANGED
|
@@ -1,99 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as LiveStore from '@livestore/livestore';
|
|
3
|
-
import { RG } from '@livestore/livestore/internal/testing-utils';
|
|
1
|
+
import { queryDb } from '@livestore/livestore';
|
|
4
2
|
import { Effect, Schema } from '@livestore/utils/effect';
|
|
5
|
-
import {
|
|
6
|
-
import * as ReactTesting from '@testing-library/react';
|
|
3
|
+
import { renderHook } from '@testing-library/react';
|
|
7
4
|
import React from 'react';
|
|
8
|
-
|
|
9
|
-
import * as ReactWindow from 'react-window';
|
|
10
|
-
import { expect } from 'vitest';
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
11
6
|
import { makeTodoMvcReact, tables, todos } from './__tests__/fixture.js';
|
|
12
7
|
import * as LiveStoreReact from './mod.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
__resetUseRcResourceCache();
|
|
18
|
-
});
|
|
19
|
-
Vitest.scopedLive('simple', () => Effect.gen(function* () {
|
|
20
|
-
const { wrapper, store, renderCount } = yield* makeTodoMvcReact({ strictMode });
|
|
8
|
+
describe('useQuery', () => {
|
|
9
|
+
it('simple', () => Effect.gen(function* () {
|
|
10
|
+
const { wrapper, store, makeRenderCount } = yield* makeTodoMvcReact();
|
|
11
|
+
const renderCount = makeRenderCount();
|
|
21
12
|
const allTodos$ = queryDb({ query: `select * from todos`, schema: Schema.Array(tables.todos.schema) });
|
|
22
|
-
const { result } =
|
|
13
|
+
const { result } = renderHook(() => {
|
|
23
14
|
renderCount.inc();
|
|
24
15
|
return LiveStoreReact.useQuery(allTodos$);
|
|
25
16
|
}, { wrapper });
|
|
26
17
|
expect(result.current.length).toBe(0);
|
|
27
18
|
expect(renderCount.val).toBe(1);
|
|
28
|
-
|
|
29
|
-
console.log('before mutation');
|
|
30
|
-
ReactTesting.act(() => store.mutate(todos.insert({ id: 't1', text: 'buy milk', completed: false })));
|
|
31
|
-
console.log('after mutation');
|
|
19
|
+
React.act(() => store.mutate(todos.insert({ id: 't1', text: 'buy milk', completed: false })));
|
|
32
20
|
expect(result.current.length).toBe(1);
|
|
33
21
|
expect(result.current[0].text).toBe('buy milk');
|
|
34
22
|
expect(renderCount.val).toBe(2);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
23
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise));
|
|
24
|
+
it('same `useQuery` hook invoked with different queries', () => Effect.gen(function* () {
|
|
25
|
+
const { wrapper, store, makeRenderCount } = yield* makeTodoMvcReact();
|
|
26
|
+
const renderCount = makeRenderCount();
|
|
39
27
|
const todo1$ = queryDb({ query: `select * from todos where id = 't1'`, schema: Schema.Array(tables.todos.schema) }, { label: 'libraryTracksView1' });
|
|
40
28
|
const todo2$ = queryDb({ query: `select * from todos where id = 't2'`, schema: Schema.Array(tables.todos.schema) }, { label: 'libraryTracksView2' });
|
|
41
29
|
store.mutate(todos.insert({ id: 't1', text: 'buy milk', completed: false }), todos.insert({ id: 't2', text: 'buy eggs', completed: false }));
|
|
42
|
-
const { result, rerender } =
|
|
30
|
+
const { result, rerender } = renderHook((todoId) => {
|
|
43
31
|
renderCount.inc();
|
|
44
32
|
const query$ = React.useMemo(() => (todoId === 't1' ? todo1$ : todo2$), [todoId]);
|
|
45
33
|
return LiveStoreReact.useQuery(query$)[0].text;
|
|
46
34
|
}, { wrapper, initialProps: 't1' });
|
|
47
35
|
expect(result.current).toBe('buy milk');
|
|
48
36
|
expect(renderCount.val).toBe(1);
|
|
49
|
-
|
|
50
|
-
ReactTesting.act(() => store.mutate(todos.update({ where: { id: 't1' }, values: { text: 'buy soy milk' } })));
|
|
37
|
+
React.act(() => store.mutate(todos.update({ where: { id: 't1' }, values: { text: 'buy soy milk' } })));
|
|
51
38
|
expect(result.current).toBe('buy soy milk');
|
|
52
39
|
expect(renderCount.val).toBe(2);
|
|
53
|
-
expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot('2: after first mutation');
|
|
54
40
|
rerender('t2');
|
|
55
41
|
expect(result.current).toBe('buy eggs');
|
|
56
42
|
expect(renderCount.val).toBe(3);
|
|
57
|
-
|
|
58
|
-
}));
|
|
59
|
-
Vitest.scopedLive('filtered dependency query', () => Effect.gen(function* () {
|
|
60
|
-
const { wrapper, store, renderCount } = yield* makeTodoMvcReact({ strictMode });
|
|
61
|
-
const filter$ = makeRef('t1', { label: 'id-filter' });
|
|
62
|
-
const todo$ = queryDb((get) => tables.todos.query.where('id', get(filter$)), { label: 'todo' });
|
|
63
|
-
store.mutate(todos.insert({ id: 't1', text: 'buy milk', completed: false }), todos.insert({ id: 't2', text: 'buy eggs', completed: false }));
|
|
64
|
-
const { result } = ReactTesting.renderHook(() => {
|
|
65
|
-
renderCount.inc();
|
|
66
|
-
return LiveStoreReact.useQuery(todo$)[0].text;
|
|
67
|
-
}, { wrapper });
|
|
68
|
-
expect(result.current).toBe('buy milk');
|
|
69
|
-
expect(renderCount.val).toBe(1);
|
|
70
|
-
expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot();
|
|
71
|
-
ReactTesting.act(() => store.mutate(todos.update({ where: { id: 't1' }, values: { text: 'buy soy milk' } })));
|
|
72
|
-
expect(result.current).toBe('buy soy milk');
|
|
73
|
-
expect(renderCount.val).toBe(2);
|
|
74
|
-
expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot();
|
|
75
|
-
ReactTesting.act(() => store.setRef(filter$, 't2'));
|
|
76
|
-
expect(result.current).toBe('buy eggs');
|
|
77
|
-
expect(renderCount.val).toBe(3);
|
|
78
|
-
expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot();
|
|
79
|
-
}));
|
|
80
|
-
// NOTE this test covers some special react lifecyle paths which I couldn't easily reproduce without react-window
|
|
81
|
-
// it basically causes a "query swap" in the `useMemo` and both a `useEffect` cleanup call.
|
|
82
|
-
// To handle this properly we introduced the `_tag: 'destroyed'` state in the `spanAlreadyStartedCache`.
|
|
83
|
-
Vitest.scopedLive('should work for a list with react-window', () => Effect.gen(function* () {
|
|
84
|
-
const { wrapper } = yield* makeTodoMvcReact({ strictMode });
|
|
85
|
-
const ListWrapper = ({ numItems }) => {
|
|
86
|
-
return (React.createElement(ReactWindow.FixedSizeList, { height: 100, width: 100, itemSize: 10, itemCount: numItems, itemData: Array.from({ length: numItems }, (_, i) => i).reverse() }, ListItem));
|
|
87
|
-
};
|
|
88
|
-
const ListItem = ({ data: ids, index }) => {
|
|
89
|
-
const id = ids[index];
|
|
90
|
-
const res = LiveStoreReact.useQuery(LiveStore.computed(() => id, { label: `ListItem.${id}`, deps: id }));
|
|
91
|
-
return React.createElement("div", { role: "listitem" }, res);
|
|
92
|
-
};
|
|
93
|
-
const renderResult = ReactTesting.render(React.createElement(ListWrapper, { numItems: 1 }), { wrapper });
|
|
94
|
-
expect(renderResult.container.textContent).toBe('0');
|
|
95
|
-
renderResult.rerender(React.createElement(ListWrapper, { numItems: 2 }));
|
|
96
|
-
expect(renderResult.container.textContent).toBe('10');
|
|
97
|
-
}));
|
|
43
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise));
|
|
98
44
|
});
|
|
99
45
|
//# sourceMappingURL=useQuery.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useQuery.test.js","sourceRoot":"","sources":["../src/useQuery.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"useQuery.test.js","sourceRoot":"","sources":["../src/useQuery.test.tsx"],"names":[],"mappings":"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"}
|
package/dist/useRow.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import type { QueryInfo, RowQuery } from '@livestore/common';
|
|
2
2
|
import { SessionIdSymbol } from '@livestore/common';
|
|
3
3
|
import { DbSchema } from '@livestore/common/schema';
|
|
4
|
-
import type { LiveQuery,
|
|
4
|
+
import type { LiveQuery, ReactivityGraph } from '@livestore/livestore';
|
|
5
5
|
export type UseRowResult<TTableDef extends DbSchema.TableDefBase> = [
|
|
6
6
|
row: RowQuery.Result<TTableDef>,
|
|
7
7
|
setRow: StateSetters<TTableDef>,
|
|
8
8
|
query$: LiveQuery<RowQuery.Result<TTableDef>, QueryInfo>
|
|
9
9
|
];
|
|
10
|
+
export type UseRowOptionsBase = {
|
|
11
|
+
reactivityGraph?: ReactivityGraph;
|
|
12
|
+
};
|
|
10
13
|
/**
|
|
11
14
|
* Similar to `React.useState` but returns a tuple of `[row, setRow, query$]` for a given table where ...
|
|
12
15
|
*
|
|
@@ -22,26 +25,20 @@ export declare const useRow: {
|
|
|
22
25
|
deriveMutations: {
|
|
23
26
|
enabled: true;
|
|
24
27
|
};
|
|
25
|
-
}>>(table: TTableDef, options?:
|
|
26
|
-
store?: Store;
|
|
27
|
-
}): UseRowResult<TTableDef>;
|
|
28
|
+
}>>(table: TTableDef, options?: UseRowOptionsBase): UseRowResult<TTableDef>;
|
|
28
29
|
<TTableDef extends DbSchema.TableDef<DbSchema.DefaultSqliteTableDef, DbSchema.TableOptions & {
|
|
29
30
|
isSingleton: false;
|
|
30
31
|
requiredInsertColumnNames: 'id';
|
|
31
32
|
deriveMutations: {
|
|
32
33
|
enabled: true;
|
|
33
34
|
};
|
|
34
|
-
}>>(table: TTableDef, id: string | SessionIdSymbol, options?: Partial<RowQuery.RequiredColumnsOptions<TTableDef>>
|
|
35
|
-
store?: Store;
|
|
36
|
-
}): UseRowResult<TTableDef>;
|
|
35
|
+
}>>(table: TTableDef, id: string | SessionIdSymbol, options?: UseRowOptionsBase & Partial<RowQuery.RequiredColumnsOptions<TTableDef>>): UseRowResult<TTableDef>;
|
|
37
36
|
<TTableDef extends DbSchema.TableDef<DbSchema.DefaultSqliteTableDef, DbSchema.TableOptions & {
|
|
38
37
|
isSingleton: false;
|
|
39
38
|
deriveMutations: {
|
|
40
39
|
enabled: true;
|
|
41
40
|
};
|
|
42
|
-
}>>(table: TTableDef, id: string | SessionIdSymbol, options: RowQuery.RequiredColumnsOptions<TTableDef>
|
|
43
|
-
store?: Store;
|
|
44
|
-
}): UseRowResult<TTableDef>;
|
|
41
|
+
}>>(table: TTableDef, id: string | SessionIdSymbol, options: UseRowOptionsBase & RowQuery.RequiredColumnsOptions<TTableDef>): UseRowResult<TTableDef>;
|
|
45
42
|
};
|
|
46
43
|
export type Dispatch<A> = (action: A) => void;
|
|
47
44
|
export type SetStateAction<S> = S | ((previousValue: S) => S);
|
package/dist/useRow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRow.d.ts","sourceRoot":"","sources":["../src/useRow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEnD,OAAO,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"useRow.d.ts","sourceRoot":"","sources":["../src/useRow.ts"],"names":[],"mappings":"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"}
|
package/dist/useRow.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ReadonlyRecord } from '@livestore/utils/effect';
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
import { useStore } from './LiveStoreContext.js';
|
|
8
8
|
import { useQueryRef } from './useQuery.js';
|
|
9
|
+
import { useMakeScopedQuery } from './useScopedQuery.js';
|
|
9
10
|
/**
|
|
10
11
|
* Similar to `React.useState` but returns a tuple of `[row, setRow, query$]` for a given table where ...
|
|
11
12
|
*
|
|
@@ -19,12 +20,12 @@ export const useRow = (table, idOrOptions, options_) => {
|
|
|
19
20
|
const sqliteTableDef = table.sqliteDef;
|
|
20
21
|
const id = typeof idOrOptions === 'string' || idOrOptions === SessionIdSymbol ? idOrOptions : undefined;
|
|
21
22
|
const options = typeof idOrOptions === 'string' || idOrOptions === SessionIdSymbol ? options_ : idOrOptions;
|
|
22
|
-
const { insertValues } = options ?? {};
|
|
23
|
+
const { insertValues, reactivityGraph } = options ?? {};
|
|
23
24
|
const tableName = table.sqliteDef.name;
|
|
24
25
|
if (DbSchema.tableHasDerivedMutations(table) === false) {
|
|
25
26
|
shouldNeverHappen(`useRow called on table "${tableName}" which does not have 'deriveMutations: true' set`);
|
|
26
27
|
}
|
|
27
|
-
const { store } = useStore(
|
|
28
|
+
const { store } = useStore();
|
|
28
29
|
if (store.schema.tables.has(table.sqliteDef.name) === false &&
|
|
29
30
|
table.sqliteDef.name.startsWith('__livestore') === false) {
|
|
30
31
|
shouldNeverHappen(`Table "${table.sqliteDef.name}" not found in schema`);
|
|
@@ -32,18 +33,20 @@ export const useRow = (table, idOrOptions, options_) => {
|
|
|
32
33
|
// console.debug('useRow', tableName, id)
|
|
33
34
|
const idStr = id === SessionIdSymbol ? 'session' : id;
|
|
34
35
|
const rowQuery = table.query.row;
|
|
35
|
-
const
|
|
36
|
-
? queryDb(rowQuery(), {})
|
|
37
|
-
: queryDb(rowQuery(id, { insertValues: insertValues }), {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
const { query$, otelContext } = useMakeScopedQuery((otelContext) => DbSchema.tableIsSingleton(table)
|
|
37
|
+
? queryDb(rowQuery(), { reactivityGraph, otelContext })
|
|
38
|
+
: queryDb(rowQuery(id, { insertValues: insertValues }), { reactivityGraph, otelContext }), [idStr, tableName], {
|
|
39
|
+
otel: {
|
|
40
|
+
spanName: `LiveStore:useRow:${tableName}${idStr === undefined ? '' : `:${idStr}`}`,
|
|
41
|
+
attributes: { id: idStr },
|
|
42
|
+
},
|
|
41
43
|
});
|
|
44
|
+
const query$Ref = useQueryRef(query$, otelContext);
|
|
42
45
|
const setState = React.useMemo(() => {
|
|
43
46
|
if (table.options.isSingleColumn) {
|
|
44
47
|
return (newValueOrFn) => {
|
|
45
|
-
const newValue = typeof newValueOrFn === 'function' ? newValueOrFn(
|
|
46
|
-
if (
|
|
48
|
+
const newValue = typeof newValueOrFn === 'function' ? newValueOrFn(query$Ref.current) : newValueOrFn;
|
|
49
|
+
if (query$Ref.current === newValue)
|
|
47
50
|
return;
|
|
48
51
|
// NOTE we need to account for the short-hand syntax for single-column+singleton tables
|
|
49
52
|
if (table.options.isSingleton) {
|
|
@@ -60,10 +63,10 @@ export const useRow = (table, idOrOptions, options_) => {
|
|
|
60
63
|
ReadonlyRecord.map(sqliteTableDef.columns, (column, columnName) => (newValueOrFn) => {
|
|
61
64
|
const newValue =
|
|
62
65
|
// @ts-expect-error TODO fix typing
|
|
63
|
-
typeof newValueOrFn === 'function' ? newValueOrFn(
|
|
66
|
+
typeof newValueOrFn === 'function' ? newValueOrFn(query$Ref.current[columnName]) : newValueOrFn;
|
|
64
67
|
// Don't update the state if it's the same as the value already seen in the component
|
|
65
68
|
// @ts-expect-error TODO fix typing
|
|
66
|
-
if (
|
|
69
|
+
if (query$Ref.current[columnName] === newValue)
|
|
67
70
|
return;
|
|
68
71
|
store.mutate(table.update({ where: { id: id ?? 'singleton' }, values: { [columnName]: newValue } }));
|
|
69
72
|
// store.mutate(updateMutationForQueryInfo(query$.queryInfo!, { [columnName]: newValue }))
|
|
@@ -71,12 +74,12 @@ export const useRow = (table, idOrOptions, options_) => {
|
|
|
71
74
|
setState.setMany = (columnValuesOrFn) => {
|
|
72
75
|
const columnValues =
|
|
73
76
|
// @ts-expect-error TODO fix typing
|
|
74
|
-
typeof columnValuesOrFn === 'function' ? columnValuesOrFn(
|
|
77
|
+
typeof columnValuesOrFn === 'function' ? columnValuesOrFn(query$Ref.current) : columnValuesOrFn;
|
|
75
78
|
// TODO use hashing instead
|
|
76
79
|
// Don't update the state if it's the same as the value already seen in the component
|
|
77
80
|
if (
|
|
78
81
|
// @ts-expect-error TODO fix typing
|
|
79
|
-
Object.entries(columnValues).every(([columnName, value]) =>
|
|
82
|
+
Object.entries(columnValues).every(([columnName, value]) => query$Ref.current[columnName] === value)) {
|
|
80
83
|
return;
|
|
81
84
|
}
|
|
82
85
|
store.mutate(table.update({ where: { id: id ?? 'singleton' }, values: columnValues }));
|
|
@@ -84,7 +87,7 @@ export const useRow = (table, idOrOptions, options_) => {
|
|
|
84
87
|
};
|
|
85
88
|
return setState;
|
|
86
89
|
}
|
|
87
|
-
}, [id,
|
|
88
|
-
return [
|
|
90
|
+
}, [id, query$Ref, sqliteTableDef.columns, store, table]);
|
|
91
|
+
return [query$Ref.current, setState, query$];
|
|
89
92
|
};
|
|
90
93
|
//# sourceMappingURL=useRow.js.map
|
package/dist/useRow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRow.js","sourceRoot":"","sources":["../src/useRow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAGnD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"useRow.js","sourceRoot":"","sources":["../src/useRow.ts"],"names":[],"mappings":"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"}
|