@livestore/livestore 0.0.56-dev.2 → 0.0.56
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/SynchronousDatabaseWrapper.d.ts.map +1 -1
- package/dist/SynchronousDatabaseWrapper.js +6 -15
- package/dist/SynchronousDatabaseWrapper.js.map +1 -1
- package/dist/__tests__/react/fixture.d.ts +3 -4
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +7 -5
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +4 -24
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +2 -1
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react/LiveStoreContext.d.ts +1 -2
- package/dist/react/LiveStoreContext.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +5 -13
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js +25 -12
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/LiveStoreProvider.test.js +1 -1
- package/dist/react/LiveStoreProvider.test.js.map +1 -1
- package/dist/react/useQuery.test.js +7 -7
- package/dist/react/useQuery.test.js.map +1 -1
- package/dist/react/useRow.test.js +52 -46
- package/dist/react/useRow.test.js.map +1 -1
- package/dist/react/useTemporaryQuery.test.js +4 -4
- package/dist/react/useTemporaryQuery.test.js.map +1 -1
- package/dist/reactiveQueries/sql.test.js +34 -33
- package/dist/reactiveQueries/sql.test.js.map +1 -1
- package/dist/store-context.d.ts +26 -0
- package/dist/store-context.d.ts.map +1 -0
- package/dist/store-context.js +6 -0
- package/dist/store-context.js.map +1 -0
- package/dist/store-devtools.d.ts +1 -1
- package/dist/store-devtools.d.ts.map +1 -1
- package/dist/store-devtools.js +5 -0
- package/dist/store-devtools.js.map +1 -1
- package/dist/store.d.ts +8 -23
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +30 -35
- package/dist/store.js.map +1 -1
- package/package.json +5 -5
- package/src/SynchronousDatabaseWrapper.ts +7 -15
- package/src/__tests__/react/fixture.tsx +53 -50
- package/src/effect/LiveStore.ts +5 -34
- package/src/index.ts +2 -10
- package/src/react/LiveStoreProvider.test.tsx +1 -1
- package/src/react/LiveStoreProvider.tsx +37 -19
- package/src/react/useQuery.test.tsx +53 -51
- package/src/react/useRow.test.tsx +237 -224
- package/src/react/useTemporaryQuery.test.tsx +46 -45
- package/src/reactiveQueries/sql.test.ts +36 -33
- package/src/store-context.ts +23 -0
- package/src/store-devtools.ts +8 -0
- package/src/store.ts +55 -59
- package/vitest.config.js +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
|
1
|
+
import { Effect, ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
|
2
2
|
import * as otel from '@opentelemetry/api'
|
|
3
3
|
import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
4
4
|
import { render, renderHook } from '@testing-library/react'
|
|
@@ -13,242 +13,252 @@ import type { StackInfo } from './utils/stack-info.js'
|
|
|
13
13
|
|
|
14
14
|
// NOTE running tests concurrently doesn't work with the default global db graph
|
|
15
15
|
describe.concurrent('useRow', () => {
|
|
16
|
-
it('should update the data based on component key',
|
|
17
|
-
|
|
16
|
+
it('should update the data based on component key', () =>
|
|
17
|
+
Effect.gen(function* () {
|
|
18
|
+
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount } = yield* makeTodoMvc({
|
|
19
|
+
useGlobalReactivityGraph: false,
|
|
20
|
+
})
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const renderCount = makeRenderCount()
|
|
22
|
+
const renderCount = makeRenderCount()
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const { result, rerender } = renderHook(
|
|
25
|
+
(userId: string) => {
|
|
26
|
+
renderCount.inc()
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
29
|
+
return { state, setState }
|
|
30
|
+
},
|
|
31
|
+
{ wrapper, initialProps: 'u1' },
|
|
32
|
+
)
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
expect(result.current.state.id).toBe('u1')
|
|
35
|
+
expect(result.current.state.username).toBe('')
|
|
36
|
+
expect(renderCount.val).toBe(1)
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
React.act(() =>
|
|
39
|
+
store.mutate(
|
|
40
|
+
LiveStore.rawSqlMutation({
|
|
41
|
+
sql: LiveStore.sql`INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')`,
|
|
42
|
+
}),
|
|
43
|
+
),
|
|
44
|
+
)
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
rerender('u2')
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
expect(result.current.state.id).toBe('u2')
|
|
49
|
+
expect(result.current.state.username).toBe('username_u2')
|
|
50
|
+
expect(renderCount.val).toBe(2)
|
|
51
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
51
52
|
|
|
52
53
|
// TODO add a test that makes sure React doesn't re-render when a setter is used to set the same value
|
|
53
54
|
|
|
54
|
-
it('should update the data reactively - via setState',
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
it('should update the data reactively - via setState', () =>
|
|
56
|
+
Effect.gen(function* () {
|
|
57
|
+
const { wrapper, AppComponentSchema, reactivityGraph, makeRenderCount } = yield* makeTodoMvc({
|
|
58
|
+
useGlobalReactivityGraph: false,
|
|
59
|
+
})
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const { result } = renderHook(
|
|
62
|
-
(userId: string) => {
|
|
63
|
-
renderCount.inc()
|
|
61
|
+
const renderCount = makeRenderCount()
|
|
64
62
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{ wrapper, initialProps: 'u1' },
|
|
69
|
-
)
|
|
63
|
+
const { result } = renderHook(
|
|
64
|
+
(userId: string) => {
|
|
65
|
+
renderCount.inc()
|
|
70
66
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
68
|
+
return { state, setState }
|
|
69
|
+
},
|
|
70
|
+
{ wrapper, initialProps: 'u1' },
|
|
71
|
+
)
|
|
74
72
|
|
|
75
|
-
|
|
73
|
+
expect(result.current.state.id).toBe('u1')
|
|
74
|
+
expect(result.current.state.username).toBe('')
|
|
75
|
+
expect(renderCount.val).toBe(1)
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
expect(result.current.state.username).toBe('username_u1_hello')
|
|
79
|
-
expect(renderCount.val).toBe(2)
|
|
80
|
-
})
|
|
77
|
+
React.act(() => result.current.setState.username('username_u1_hello'))
|
|
81
78
|
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
expect(result.current.state.id).toBe('u1')
|
|
80
|
+
expect(result.current.state.username).toBe('username_u1_hello')
|
|
81
|
+
expect(renderCount.val).toBe(2)
|
|
82
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
84
83
|
|
|
85
|
-
|
|
84
|
+
it('should update the data reactively - via raw store mutation', () =>
|
|
85
|
+
Effect.gen(function* () {
|
|
86
|
+
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount } = yield* makeTodoMvc({
|
|
87
|
+
useGlobalReactivityGraph: false,
|
|
88
|
+
})
|
|
86
89
|
|
|
87
|
-
|
|
90
|
+
const renderCount = makeRenderCount()
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
const { result } = renderHook(
|
|
93
|
+
(userId: string) => {
|
|
94
|
+
renderCount.inc()
|
|
92
95
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
97
|
+
return { state, setState }
|
|
98
|
+
},
|
|
99
|
+
{ wrapper, initialProps: 'u1' },
|
|
100
|
+
)
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
expect(result.current.state.id).toBe('u1')
|
|
103
|
+
expect(result.current.state.username).toBe('')
|
|
104
|
+
expect(renderCount.val).toBe(1)
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
expect(result.current.state.id).toBe('u1')
|
|
112
|
-
expect(result.current.state.username).toBe('username_u1_hello')
|
|
113
|
-
expect(renderCount.val).toBe(2)
|
|
114
|
-
})
|
|
106
|
+
React.act(() =>
|
|
107
|
+
store.mutate(
|
|
108
|
+
LiveStore.rawSqlMutation({
|
|
109
|
+
sql: LiveStore.sql`UPDATE UserInfo SET username = 'username_u1_hello' WHERE id = 'u1';`,
|
|
110
|
+
}),
|
|
111
|
+
),
|
|
112
|
+
)
|
|
115
113
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
expect(result.current.state.id).toBe('u1')
|
|
115
|
+
expect(result.current.state.username).toBe('username_u1_hello')
|
|
116
|
+
expect(renderCount.val).toBe(2)
|
|
117
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
118
|
+
|
|
119
|
+
it('should work for a larger app', () =>
|
|
120
|
+
Effect.gen(function* () {
|
|
121
|
+
const { wrapper, store, reactivityGraph, makeRenderCount, AppRouterSchema } = yield* makeTodoMvc({
|
|
122
|
+
useGlobalReactivityGraph: false,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const allTodos$ = LiveStore.querySQL(`select * from todos`, {
|
|
126
|
+
label: 'allTodos',
|
|
127
|
+
schema: Schema.Array(tables.todos.schema),
|
|
128
|
+
reactivityGraph,
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
const appRouterRenderCount = makeRenderCount()
|
|
132
|
+
let globalSetState: LiveStoreReact.StateSetters<typeof AppRouterSchema> | undefined
|
|
133
|
+
const AppRouter: React.FC = () => {
|
|
134
|
+
appRouterRenderCount.inc()
|
|
135
|
+
|
|
136
|
+
const [state, setState] = LiveStoreReact.useRow(AppRouterSchema, { reactivityGraph })
|
|
137
|
+
|
|
138
|
+
globalSetState = setState
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div>
|
|
142
|
+
<TasksList setTaskId={setState.currentTaskId} />
|
|
143
|
+
<div role="current-id">Current Task Id: {state.currentTaskId ?? '-'}</div>
|
|
144
|
+
{state.currentTaskId ? <TaskDetails id={state.currentTaskId} /> : <div>Click on a task to see details</div>}
|
|
145
|
+
</div>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
119
148
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
149
|
+
const TasksList: React.FC<{ setTaskId: (_: string) => void }> = ({ setTaskId }) => {
|
|
150
|
+
const allTodos = LiveStoreReact.useQuery(allTodos$)
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<div>
|
|
154
|
+
{allTodos.map((_) => (
|
|
155
|
+
<div key={_.id} onClick={() => setTaskId(_.id)}>
|
|
156
|
+
{_.id}
|
|
157
|
+
</div>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
125
162
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
163
|
+
const TaskDetails: React.FC<{ id: string }> = ({ id }) => {
|
|
164
|
+
const [todo] = LiveStoreReact.useRow(todos, id, { reactivityGraph })
|
|
165
|
+
return <div role="content">{JSON.stringify(todo)}</div>
|
|
166
|
+
}
|
|
130
167
|
|
|
131
|
-
const
|
|
168
|
+
const renderResult = render(<AppRouter />, { wrapper })
|
|
132
169
|
|
|
133
|
-
|
|
170
|
+
expect(appRouterRenderCount.val).toBe(1)
|
|
134
171
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const TasksList: React.FC<{ setTaskId: (_: string) => void }> = ({ setTaskId }) => {
|
|
145
|
-
const allTodos = LiveStoreReact.useQuery(allTodos$)
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<div>
|
|
149
|
-
{allTodos.map((_) => (
|
|
150
|
-
<div key={_.id} onClick={() => setTaskId(_.id)}>
|
|
151
|
-
{_.id}
|
|
152
|
-
</div>
|
|
153
|
-
))}
|
|
154
|
-
</div>
|
|
172
|
+
React.act(() =>
|
|
173
|
+
store.mutate(
|
|
174
|
+
LiveStore.rawSqlMutation({
|
|
175
|
+
sql: LiveStore.sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)`,
|
|
176
|
+
}),
|
|
177
|
+
),
|
|
155
178
|
)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const TaskDetails: React.FC<{ id: string }> = ({ id }) => {
|
|
159
|
-
const [todo] = LiveStoreReact.useRow(todos, id, { reactivityGraph })
|
|
160
|
-
return <div role="content">{JSON.stringify(todo)}</div>
|
|
161
|
-
}
|
|
162
179
|
|
|
163
|
-
|
|
180
|
+
expect(appRouterRenderCount.val).toBe(1)
|
|
181
|
+
expect(renderResult.getByRole('current-id').innerHTML).toMatchInlineSnapshot('"Current Task Id: -"')
|
|
164
182
|
|
|
165
|
-
|
|
183
|
+
React.act(() => globalSetState!.currentTaskId('t1'))
|
|
166
184
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}),
|
|
172
|
-
),
|
|
173
|
-
)
|
|
185
|
+
expect(appRouterRenderCount.val).toBe(2)
|
|
186
|
+
expect(renderResult.getByRole('content').innerHTML).toMatchInlineSnapshot(
|
|
187
|
+
`"{"completed":false,"id":"t1","text":"buy milk"}"`,
|
|
188
|
+
)
|
|
174
189
|
|
|
175
|
-
|
|
176
|
-
expect(renderResult.getByRole('current-id').innerHTML).toMatchInlineSnapshot('"Current Task Id: -"')
|
|
190
|
+
expect(renderResult.getByRole('current-id').innerHTML).toMatchInlineSnapshot('"Current Task Id: t1"')
|
|
177
191
|
|
|
178
|
-
|
|
192
|
+
React.act(() =>
|
|
193
|
+
store.mutate(
|
|
194
|
+
LiveStore.rawSqlMutation({
|
|
195
|
+
sql: LiveStore.sql`INSERT INTO todos (id, text, completed) VALUES ('t2', 'buy eggs', 0)`,
|
|
196
|
+
}),
|
|
197
|
+
AppRouterSchema.update({ where: { id: 'singleton' }, values: { currentTaskId: 't2' } }),
|
|
198
|
+
LiveStore.rawSqlMutation({
|
|
199
|
+
sql: LiveStore.sql`INSERT INTO todos (id, text, completed) VALUES ('t3', 'buy bread', 0)`,
|
|
200
|
+
}),
|
|
201
|
+
),
|
|
202
|
+
)
|
|
179
203
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
)
|
|
204
|
+
expect(appRouterRenderCount.val).toBe(3)
|
|
205
|
+
expect(renderResult.getByRole('current-id').innerHTML).toMatchInlineSnapshot('"Current Task Id: t2"')
|
|
206
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
184
207
|
|
|
185
|
-
|
|
208
|
+
it('should work for a useRow query chained with a useTemporary query', () =>
|
|
209
|
+
Effect.gen(function* () {
|
|
210
|
+
const { store, wrapper, AppComponentSchema, reactivityGraph, makeRenderCount } = yield* makeTodoMvc({
|
|
211
|
+
useGlobalReactivityGraph: false,
|
|
212
|
+
})
|
|
213
|
+
const renderCount = makeRenderCount()
|
|
186
214
|
|
|
187
|
-
React.act(() =>
|
|
188
215
|
store.mutate(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
AppRouterSchema.update({ where: { id: 'singleton' }, values: { currentTaskId: 't2' } }),
|
|
193
|
-
LiveStore.rawSqlMutation({
|
|
194
|
-
sql: LiveStore.sql`INSERT INTO todos (id, text, completed) VALUES ('t3', 'buy bread', 0)`,
|
|
195
|
-
}),
|
|
196
|
-
),
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
expect(appRouterRenderCount.val).toBe(3)
|
|
200
|
-
expect(renderResult.getByRole('current-id').innerHTML).toMatchInlineSnapshot('"Current Task Id: t2"')
|
|
201
|
-
})
|
|
216
|
+
todos.insert({ id: 't1', text: 'buy milk', completed: false }),
|
|
217
|
+
todos.insert({ id: 't2', text: 'buy bread', completed: false }),
|
|
218
|
+
)
|
|
202
219
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const renderCount = makeRenderCount()
|
|
207
|
-
|
|
208
|
-
store.mutate(
|
|
209
|
-
todos.insert({ id: 't1', text: 'buy milk', completed: false }),
|
|
210
|
-
todos.insert({ id: 't2', text: 'buy bread', completed: false }),
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
const { result, unmount, rerender } = renderHook(
|
|
214
|
-
(userId: string) => {
|
|
215
|
-
renderCount.inc()
|
|
216
|
-
|
|
217
|
-
const [_row, _setRow, rowState$] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
218
|
-
const todos = LiveStoreReact.useTemporaryQuery(
|
|
219
|
-
() =>
|
|
220
|
-
LiveStore.querySQL((get) => LiveStore.sql`select * from todos where text like '%${get(rowState$).text}%'`, {
|
|
221
|
-
schema: Schema.Array(tables.todos.schema),
|
|
222
|
-
reactivityGraph,
|
|
223
|
-
label: 'todosFiltered',
|
|
224
|
-
}),
|
|
225
|
-
userId,
|
|
226
|
-
)
|
|
220
|
+
const { result, unmount, rerender } = renderHook(
|
|
221
|
+
(userId: string) => {
|
|
222
|
+
renderCount.inc()
|
|
227
223
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
224
|
+
const [_row, _setRow, rowState$] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
225
|
+
const todos = LiveStoreReact.useTemporaryQuery(
|
|
226
|
+
() =>
|
|
227
|
+
LiveStore.querySQL(
|
|
228
|
+
(get) => LiveStore.sql`select * from todos where text like '%${get(rowState$).text}%'`,
|
|
229
|
+
{
|
|
230
|
+
schema: Schema.Array(tables.todos.schema),
|
|
231
|
+
reactivityGraph,
|
|
232
|
+
label: 'todosFiltered',
|
|
233
|
+
},
|
|
234
|
+
),
|
|
235
|
+
userId,
|
|
236
|
+
)
|
|
232
237
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
)
|
|
239
|
-
|
|
238
|
+
return { todos }
|
|
239
|
+
},
|
|
240
|
+
{ wrapper, initialProps: 'u1' },
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
React.act(() =>
|
|
244
|
+
store.mutate(
|
|
245
|
+
LiveStore.rawSqlMutation({
|
|
246
|
+
sql: LiveStore.sql`INSERT INTO UserInfo (id, username, text) VALUES ('u2', 'username_u2', 'milk')`,
|
|
247
|
+
}),
|
|
248
|
+
),
|
|
249
|
+
)
|
|
240
250
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
251
|
+
expect(result.current.todos.length).toBe(2)
|
|
252
|
+
// expect(result.current.state.username).toBe('')
|
|
253
|
+
expect(renderCount.val).toBe(1)
|
|
244
254
|
|
|
245
|
-
|
|
255
|
+
rerender('u2')
|
|
246
256
|
|
|
247
|
-
|
|
248
|
-
|
|
257
|
+
expect(result.current.todos.length).toBe(1)
|
|
258
|
+
expect(renderCount.val).toBe(2)
|
|
249
259
|
|
|
250
|
-
|
|
251
|
-
|
|
260
|
+
unmount()
|
|
261
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
252
262
|
|
|
253
263
|
let cachedProvider: BasicTracerProvider | undefined
|
|
254
264
|
|
|
@@ -266,43 +276,46 @@ describe.concurrent('useRow', () => {
|
|
|
266
276
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
267
277
|
|
|
268
278
|
it('should update the data based on component key', async () => {
|
|
269
|
-
|
|
279
|
+
const { strictMode } = await Effect.gen(function* () {
|
|
280
|
+
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount, strictMode } = yield* makeTodoMvc(
|
|
281
|
+
{ useGlobalReactivityGraph: false, otelContext, otelTracer },
|
|
282
|
+
)
|
|
270
283
|
|
|
271
|
-
|
|
284
|
+
const renderCount = makeRenderCount()
|
|
272
285
|
|
|
273
|
-
|
|
286
|
+
const { result, rerender, unmount } = renderHook(
|
|
287
|
+
(userId: string) => {
|
|
288
|
+
renderCount.inc()
|
|
274
289
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
290
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
291
|
+
return { state, setState }
|
|
292
|
+
},
|
|
293
|
+
{ wrapper, initialProps: 'u1' },
|
|
294
|
+
)
|
|
278
295
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
{ wrapper, initialProps: 'u1' },
|
|
283
|
-
)
|
|
296
|
+
expect(result.current.state.id).toBe('u1')
|
|
297
|
+
expect(result.current.state.username).toBe('')
|
|
298
|
+
expect(renderCount.val).toBe(1)
|
|
284
299
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
300
|
+
React.act(() =>
|
|
301
|
+
store.mutate(
|
|
302
|
+
LiveStore.rawSqlMutation({
|
|
303
|
+
sql: LiveStore.sql`INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')`,
|
|
304
|
+
}),
|
|
305
|
+
),
|
|
306
|
+
)
|
|
288
307
|
|
|
289
|
-
|
|
290
|
-
store.mutate(
|
|
291
|
-
LiveStore.rawSqlMutation({
|
|
292
|
-
sql: LiveStore.sql`INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')`,
|
|
293
|
-
}),
|
|
294
|
-
),
|
|
295
|
-
)
|
|
308
|
+
rerender('u2')
|
|
296
309
|
|
|
297
|
-
|
|
310
|
+
expect(result.current.state.id).toBe('u2')
|
|
311
|
+
expect(result.current.state.username).toBe('username_u2')
|
|
312
|
+
expect(renderCount.val).toBe(2)
|
|
298
313
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
expect(renderCount.val).toBe(2)
|
|
314
|
+
unmount()
|
|
315
|
+
span.end()
|
|
302
316
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
span.end()
|
|
317
|
+
return { strictMode }
|
|
318
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise)
|
|
306
319
|
|
|
307
320
|
const mapAttributes = (attributes: otel.Attributes) => {
|
|
308
321
|
return ReadonlyRecord.map(attributes, (val, key) => {
|
|
@@ -371,7 +384,7 @@ describe.concurrent('useRow', () => {
|
|
|
371
384
|
},
|
|
372
385
|
"children": [
|
|
373
386
|
{
|
|
374
|
-
"_name": "LiveStore:
|
|
387
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
375
388
|
"attributes": {
|
|
376
389
|
"livestore.args": "{
|
|
377
390
|
"sql": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')"
|
|
@@ -420,7 +433,7 @@ describe.concurrent('useRow', () => {
|
|
|
420
433
|
},
|
|
421
434
|
"children": [
|
|
422
435
|
{
|
|
423
|
-
"_name": "LiveStore:
|
|
436
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
424
437
|
"attributes": {
|
|
425
438
|
"livestore.args": "{
|
|
426
439
|
"id": "u1"
|
|
@@ -534,7 +547,7 @@ describe.concurrent('useRow', () => {
|
|
|
534
547
|
},
|
|
535
548
|
"children": [
|
|
536
549
|
{
|
|
537
|
-
"_name": "LiveStore:
|
|
550
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
538
551
|
"attributes": {
|
|
539
552
|
"livestore.args": "{
|
|
540
553
|
"sql": "INSERT INTO UserInfo (id, username) VALUES ('u2', 'username_u2')"
|
|
@@ -583,7 +596,7 @@ describe.concurrent('useRow', () => {
|
|
|
583
596
|
},
|
|
584
597
|
"children": [
|
|
585
598
|
{
|
|
586
|
-
"_name": "LiveStore:
|
|
599
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
587
600
|
"attributes": {
|
|
588
601
|
"livestore.args": "{
|
|
589
602
|
"id": "u1"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Schema } from '@livestore/utils/effect'
|
|
1
|
+
import { Effect, Schema } from '@livestore/utils/effect'
|
|
2
2
|
import { renderHook } from '@testing-library/react'
|
|
3
3
|
import { describe, expect, it } from 'vitest'
|
|
4
4
|
|
|
@@ -8,48 +8,49 @@ import { querySQL } from '../reactiveQueries/sql.js'
|
|
|
8
8
|
import * as LiveStoreReact from './index.js'
|
|
9
9
|
|
|
10
10
|
describe('useTemporaryQuery', () => {
|
|
11
|
-
it('simple',
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
11
|
+
it('simple', () =>
|
|
12
|
+
Effect.gen(function* () {
|
|
13
|
+
const { wrapper, store, makeRenderCount } = yield* makeTodoMvc()
|
|
14
|
+
|
|
15
|
+
const renderCount = makeRenderCount()
|
|
16
|
+
|
|
17
|
+
store.mutate(
|
|
18
|
+
todos.insert({ id: 't1', text: 'buy milk', completed: false }),
|
|
19
|
+
todos.insert({ id: 't2', text: 'buy bread', completed: false }),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const queryMap = new Map<string, LiveStore.LiveQuery<any>>()
|
|
23
|
+
|
|
24
|
+
const { rerender, result, unmount } = renderHook(
|
|
25
|
+
(id: string) => {
|
|
26
|
+
renderCount.inc()
|
|
27
|
+
|
|
28
|
+
return LiveStoreReact.useTemporaryQuery(() => {
|
|
29
|
+
const query$ = querySQL(`select * from todos where id = '${id}'`, {
|
|
30
|
+
schema: Schema.Array(tables.todos.schema),
|
|
31
|
+
})
|
|
32
|
+
queryMap.set(id, query$)
|
|
33
|
+
return query$
|
|
34
|
+
}, id)
|
|
35
|
+
},
|
|
36
|
+
{ wrapper, initialProps: 't1' },
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
expect(result.current.length).toBe(1)
|
|
40
|
+
expect(result.current[0]!.text).toBe('buy milk')
|
|
41
|
+
expect(renderCount.val).toBe(1)
|
|
42
|
+
expect(queryMap.get('t1')!.runs).toBe(1)
|
|
43
|
+
|
|
44
|
+
rerender('t2')
|
|
45
|
+
|
|
46
|
+
expect(result.current.length).toBe(1)
|
|
47
|
+
expect(result.current[0]!.text).toBe('buy bread')
|
|
48
|
+
expect(renderCount.val).toBe(2)
|
|
49
|
+
expect(queryMap.get('t1')!.runs).toBe(1)
|
|
50
|
+
expect(queryMap.get('t2')!.runs).toBe(1)
|
|
51
|
+
|
|
52
|
+
unmount()
|
|
53
|
+
|
|
54
|
+
expect(queryMap.get('t2')!.runs).toBe(1)
|
|
55
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise))
|
|
55
56
|
})
|