@livestore/react 0.1.0-dev.9 → 0.2.0-dev.0
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/LiveStoreProvider.test.js +2 -2
- package/dist/LiveStoreProvider.test.js.map +1 -1
- package/dist/__tests__/fixture.d.ts +372 -276
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/useAtom.d.ts +2 -7
- package/dist/useAtom.d.ts.map +1 -1
- package/dist/useAtom.js +9 -8
- package/dist/useAtom.js.map +1 -1
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +3 -0
- package/dist/useQuery.js.map +1 -1
- package/dist/useQuery.test.js +4 -10
- package/dist/useQuery.test.js.map +1 -1
- package/dist/useRow.d.ts +18 -14
- package/dist/useRow.d.ts.map +1 -1
- package/dist/useRow.js +6 -9
- package/dist/useRow.js.map +1 -1
- package/dist/useRow.test.js +4 -9
- package/dist/useRow.test.js.map +1 -1
- package/dist/useScopedQuery.test.js +3 -2
- package/dist/useScopedQuery.test.js.map +1 -1
- package/package.json +6 -6
- package/src/LiveStoreProvider.test.tsx +2 -2
- package/src/__snapshots__/useRow.test.tsx.snap +33 -33
- package/src/useAtom.ts +14 -17
- package/src/useQuery.test.tsx +10 -10
- package/src/useQuery.ts +4 -0
- package/src/useRow.test.tsx +9 -11
- package/src/useRow.ts +36 -30
- package/src/useScopedQuery.test.tsx +3 -2
- package/dist/useTemporaryQuery.test.d.ts +0 -2
- package/dist/useTemporaryQuery.test.d.ts.map +0 -1
- package/dist/useTemporaryQuery.test.js +0 -59
- package/dist/useTemporaryQuery.test.js.map +0 -1
- package/src/useTemporaryQuery.ts +0 -131
|
@@ -21,7 +21,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
21
21
|
"_name": "sql-in-memory-select",
|
|
22
22
|
"attributes": {
|
|
23
23
|
"sql.cached": false,
|
|
24
|
-
"sql.query": "
|
|
24
|
+
"sql.query": "SELECT 1 FROM 'UserInfo' WHERE id = ?",
|
|
25
25
|
"sql.rowsCount": 0,
|
|
26
26
|
},
|
|
27
27
|
},
|
|
@@ -29,7 +29,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
29
29
|
"_name": "sql-in-memory-select",
|
|
30
30
|
"attributes": {
|
|
31
31
|
"sql.cached": false,
|
|
32
|
-
"sql.query": "
|
|
32
|
+
"sql.query": "SELECT 1 FROM 'UserInfo' WHERE id = ?",
|
|
33
33
|
"sql.rowsCount": 1,
|
|
34
34
|
},
|
|
35
35
|
},
|
|
@@ -75,9 +75,9 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
75
75
|
"_name": "LiveStore:queries",
|
|
76
76
|
"children": [
|
|
77
77
|
{
|
|
78
|
-
"_name": "
|
|
78
|
+
"_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
79
79
|
"attributes": {
|
|
80
|
-
"sql.query": "
|
|
80
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
81
81
|
"sql.rowsCount": 1,
|
|
82
82
|
},
|
|
83
83
|
"children": [
|
|
@@ -85,7 +85,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
85
85
|
"_name": "sql-in-memory-select",
|
|
86
86
|
"attributes": {
|
|
87
87
|
"sql.cached": false,
|
|
88
|
-
"sql.query": "
|
|
88
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
89
89
|
"sql.rowsCount": 1,
|
|
90
90
|
},
|
|
91
91
|
},
|
|
@@ -115,16 +115,16 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
115
115
|
],
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
|
-
"_name": "LiveStore:useQuery:
|
|
118
|
+
"_name": "LiveStore:useQuery:db(row:UserInfo:u1)",
|
|
119
119
|
"attributes": {
|
|
120
|
-
"label": "
|
|
120
|
+
"label": "db(row:UserInfo:u1)",
|
|
121
121
|
"stackInfo": "{"frames":[{"name":"renderHook.wrapper","filePath":"__REPLACED_FOR_SNAPSHOT__"},{"name":"useRow","filePath":"__REPLACED_FOR_SNAPSHOT__"}]}",
|
|
122
122
|
},
|
|
123
123
|
"children": [
|
|
124
124
|
{
|
|
125
|
-
"_name": "
|
|
125
|
+
"_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
126
126
|
"attributes": {
|
|
127
|
-
"sql.query": "
|
|
127
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
128
128
|
"sql.rowsCount": 1,
|
|
129
129
|
},
|
|
130
130
|
"children": [
|
|
@@ -132,7 +132,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
132
132
|
"_name": "sql-in-memory-select",
|
|
133
133
|
"attributes": {
|
|
134
134
|
"sql.cached": false,
|
|
135
|
-
"sql.query": "
|
|
135
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
136
136
|
"sql.rowsCount": 1,
|
|
137
137
|
},
|
|
138
138
|
},
|
|
@@ -141,8 +141,8 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
141
141
|
{
|
|
142
142
|
"_name": "LiveStore.subscribe",
|
|
143
143
|
"attributes": {
|
|
144
|
-
"label": "
|
|
145
|
-
"queryLabel": "
|
|
144
|
+
"label": "db(row:UserInfo:u1)",
|
|
145
|
+
"queryLabel": "db(row:UserInfo:u1)",
|
|
146
146
|
},
|
|
147
147
|
},
|
|
148
148
|
],
|
|
@@ -156,16 +156,16 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
156
156
|
},
|
|
157
157
|
"children": [
|
|
158
158
|
{
|
|
159
|
-
"_name": "LiveStore:useQuery:
|
|
159
|
+
"_name": "LiveStore:useQuery:db(row:UserInfo:u2)",
|
|
160
160
|
"attributes": {
|
|
161
|
-
"label": "
|
|
161
|
+
"label": "db(row:UserInfo:u2)",
|
|
162
162
|
"stackInfo": "{"frames":[{"name":"renderHook.wrapper","filePath":"__REPLACED_FOR_SNAPSHOT__"},{"name":"useRow","filePath":"__REPLACED_FOR_SNAPSHOT__"}]}",
|
|
163
163
|
},
|
|
164
164
|
"children": [
|
|
165
165
|
{
|
|
166
|
-
"_name": "
|
|
166
|
+
"_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
167
167
|
"attributes": {
|
|
168
|
-
"sql.query": "
|
|
168
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
169
169
|
"sql.rowsCount": 1,
|
|
170
170
|
},
|
|
171
171
|
"children": [
|
|
@@ -173,7 +173,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
173
173
|
"_name": "sql-in-memory-select",
|
|
174
174
|
"attributes": {
|
|
175
175
|
"sql.cached": false,
|
|
176
|
-
"sql.query": "
|
|
176
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
177
177
|
"sql.rowsCount": 1,
|
|
178
178
|
},
|
|
179
179
|
},
|
|
@@ -182,8 +182,8 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
182
182
|
{
|
|
183
183
|
"_name": "LiveStore.subscribe",
|
|
184
184
|
"attributes": {
|
|
185
|
-
"label": "
|
|
186
|
-
"queryLabel": "
|
|
185
|
+
"label": "db(row:UserInfo:u2)",
|
|
186
|
+
"queryLabel": "db(row:UserInfo:u2)",
|
|
187
187
|
},
|
|
188
188
|
},
|
|
189
189
|
],
|
|
@@ -217,7 +217,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
217
217
|
"_name": "sql-in-memory-select",
|
|
218
218
|
"attributes": {
|
|
219
219
|
"sql.cached": false,
|
|
220
|
-
"sql.query": "
|
|
220
|
+
"sql.query": "SELECT 1 FROM 'UserInfo' WHERE id = ?",
|
|
221
221
|
"sql.rowsCount": 0,
|
|
222
222
|
},
|
|
223
223
|
},
|
|
@@ -225,7 +225,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
225
225
|
"_name": "sql-in-memory-select",
|
|
226
226
|
"attributes": {
|
|
227
227
|
"sql.cached": false,
|
|
228
|
-
"sql.query": "
|
|
228
|
+
"sql.query": "SELECT 1 FROM 'UserInfo' WHERE id = ?",
|
|
229
229
|
"sql.rowsCount": 1,
|
|
230
230
|
},
|
|
231
231
|
},
|
|
@@ -271,9 +271,9 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
271
271
|
"_name": "LiveStore:queries",
|
|
272
272
|
"children": [
|
|
273
273
|
{
|
|
274
|
-
"_name": "
|
|
274
|
+
"_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
275
275
|
"attributes": {
|
|
276
|
-
"sql.query": "
|
|
276
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
277
277
|
"sql.rowsCount": 1,
|
|
278
278
|
},
|
|
279
279
|
"children": [
|
|
@@ -281,7 +281,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
281
281
|
"_name": "sql-in-memory-select",
|
|
282
282
|
"attributes": {
|
|
283
283
|
"sql.cached": false,
|
|
284
|
-
"sql.query": "
|
|
284
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
285
285
|
"sql.rowsCount": 1,
|
|
286
286
|
},
|
|
287
287
|
},
|
|
@@ -311,16 +311,16 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
311
311
|
],
|
|
312
312
|
},
|
|
313
313
|
{
|
|
314
|
-
"_name": "LiveStore:useQuery:
|
|
314
|
+
"_name": "LiveStore:useQuery:db(row:UserInfo:u1)",
|
|
315
315
|
"attributes": {
|
|
316
|
-
"label": "
|
|
316
|
+
"label": "db(row:UserInfo:u1)",
|
|
317
317
|
"stackInfo": "{"frames":[{"name":"renderHook.wrapper","filePath":"__REPLACED_FOR_SNAPSHOT__"},{"name":"useRow","filePath":"__REPLACED_FOR_SNAPSHOT__"}]}",
|
|
318
318
|
},
|
|
319
319
|
"children": [
|
|
320
320
|
{
|
|
321
|
-
"_name": "
|
|
321
|
+
"_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
322
322
|
"attributes": {
|
|
323
|
-
"sql.query": "
|
|
323
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
324
324
|
"sql.rowsCount": 1,
|
|
325
325
|
},
|
|
326
326
|
"children": [
|
|
@@ -328,7 +328,7 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
328
328
|
"_name": "sql-in-memory-select",
|
|
329
329
|
"attributes": {
|
|
330
330
|
"sql.cached": false,
|
|
331
|
-
"sql.query": "
|
|
331
|
+
"sql.query": "SELECT * FROM 'UserInfo' WHERE id = ?",
|
|
332
332
|
"sql.rowsCount": 1,
|
|
333
333
|
},
|
|
334
334
|
},
|
|
@@ -337,15 +337,15 @@ exports[`useRow > otel > should update the data based on component key > strictM
|
|
|
337
337
|
{
|
|
338
338
|
"_name": "LiveStore.subscribe",
|
|
339
339
|
"attributes": {
|
|
340
|
-
"label": "
|
|
341
|
-
"queryLabel": "
|
|
340
|
+
"label": "db(row:UserInfo:u1)",
|
|
341
|
+
"queryLabel": "db(row:UserInfo:u1)",
|
|
342
342
|
},
|
|
343
343
|
},
|
|
344
344
|
{
|
|
345
345
|
"_name": "LiveStore.subscribe",
|
|
346
346
|
"attributes": {
|
|
347
|
-
"label": "
|
|
348
|
-
"queryLabel": "
|
|
347
|
+
"label": "db(row:UserInfo:u1)",
|
|
348
|
+
"queryLabel": "db(row:UserInfo:u1)",
|
|
349
349
|
},
|
|
350
350
|
},
|
|
351
351
|
],
|
package/src/useAtom.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DerivedMutationHelperFns, QueryInfo } from '@livestore/common'
|
|
2
2
|
import type { DbSchema } from '@livestore/common/schema'
|
|
3
|
+
import type { SqliteDsl } from '@livestore/db-schema'
|
|
3
4
|
import type { LiveQuery } from '@livestore/livestore'
|
|
4
5
|
import React from 'react'
|
|
5
6
|
|
|
@@ -8,12 +9,8 @@ import { useQueryRef } from './useQuery.js'
|
|
|
8
9
|
import type { Dispatch, SetStateAction } from './useRow.js'
|
|
9
10
|
|
|
10
11
|
export const useAtom = <
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
DbSchema.DefaultSqliteTableDefConstrained,
|
|
14
|
-
boolean,
|
|
15
|
-
DbSchema.TableOptions & { deriveMutations: { enabled: true } }
|
|
16
|
-
>,
|
|
12
|
+
// TODO also support colJsonValue
|
|
13
|
+
TQuery extends LiveQuery<any, QueryInfo.Row | QueryInfo.Col>,
|
|
17
14
|
>(
|
|
18
15
|
query$: TQuery,
|
|
19
16
|
): [value: TQuery['__result!'], setValue: Dispatch<SetStateAction<Partial<TQuery['__result!']>>>] => {
|
|
@@ -25,23 +22,23 @@ export const useAtom = <
|
|
|
25
22
|
const setValue = React.useMemo<Dispatch<SetStateAction<TQuery['__result!']>>>(() => {
|
|
26
23
|
return (newValueOrFn: any) => {
|
|
27
24
|
const newValue = typeof newValueOrFn === 'function' ? newValueOrFn(query$Ref.current) : newValueOrFn
|
|
25
|
+
const table = query$.queryInfo.table as DbSchema.TableDef &
|
|
26
|
+
DerivedMutationHelperFns<SqliteDsl.Columns, DbSchema.TableOptions>
|
|
28
27
|
|
|
29
28
|
if (query$.queryInfo._tag === 'Row') {
|
|
30
|
-
if (
|
|
31
|
-
store.mutate(
|
|
32
|
-
} else if (
|
|
33
|
-
store.mutate(
|
|
34
|
-
query$.queryInfo.table.update({ where: { id: query$.queryInfo.id }, values: { value: newValue } }),
|
|
35
|
-
)
|
|
29
|
+
if (table.options.isSingleton && table.options.isSingleColumn) {
|
|
30
|
+
store.mutate(table.update(newValue))
|
|
31
|
+
} else if (table.options.isSingleColumn) {
|
|
32
|
+
store.mutate(table.update({ where: { id: query$.queryInfo.id }, values: { value: newValue } }))
|
|
36
33
|
} else {
|
|
37
|
-
store.mutate(
|
|
34
|
+
store.mutate(table.update({ where: { id: query$.queryInfo.id }, values: newValue }))
|
|
38
35
|
}
|
|
39
36
|
} else {
|
|
40
|
-
if (
|
|
41
|
-
store.mutate(
|
|
37
|
+
if (table.options.isSingleton && table.options.isSingleColumn) {
|
|
38
|
+
store.mutate(table.update({ [query$.queryInfo.column]: newValue }))
|
|
42
39
|
} else {
|
|
43
40
|
store.mutate(
|
|
44
|
-
|
|
41
|
+
table.update({
|
|
45
42
|
where: { id: query$.queryInfo.id },
|
|
46
43
|
values: { [query$.queryInfo.column]: newValue },
|
|
47
44
|
}),
|
package/src/useQuery.test.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { queryDb } from '@livestore/livestore'
|
|
2
2
|
import { Effect, Schema } from '@livestore/utils/effect'
|
|
3
3
|
import { renderHook } from '@testing-library/react'
|
|
4
4
|
import React from 'react'
|
|
@@ -14,7 +14,7 @@ describe('useQuery', () => {
|
|
|
14
14
|
|
|
15
15
|
const renderCount = makeRenderCount()
|
|
16
16
|
|
|
17
|
-
const allTodos$ =
|
|
17
|
+
const allTodos$ = queryDb({ query: `select * from todos`, schema: Schema.Array(tables.todos.schema) })
|
|
18
18
|
|
|
19
19
|
const { result } = renderHook(
|
|
20
20
|
() => {
|
|
@@ -41,14 +41,14 @@ describe('useQuery', () => {
|
|
|
41
41
|
|
|
42
42
|
const renderCount = makeRenderCount()
|
|
43
43
|
|
|
44
|
-
const todo1$ =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const todo2$ =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
const todo1$ = queryDb(
|
|
45
|
+
{ query: `select * from todos where id = 't1'`, schema: Schema.Array(tables.todos.schema) },
|
|
46
|
+
{ label: 'libraryTracksView1' },
|
|
47
|
+
)
|
|
48
|
+
const todo2$ = queryDb(
|
|
49
|
+
{ query: `select * from todos where id = 't2'`, schema: Schema.Array(tables.todos.schema) },
|
|
50
|
+
{ label: 'libraryTracksView2' },
|
|
51
|
+
)
|
|
52
52
|
|
|
53
53
|
store.mutate(
|
|
54
54
|
todos.insert({ id: 't1', text: 'buy milk', completed: false }),
|
package/src/useQuery.ts
CHANGED
|
@@ -101,6 +101,10 @@ Stack trace:
|
|
|
101
101
|
React.useEffect(() => {
|
|
102
102
|
query$.activeSubscriptions.add(stackInfo)
|
|
103
103
|
|
|
104
|
+
// Dynamic queries only set their actual label after they've been run the first time,
|
|
105
|
+
// so we're also updating the span name here.
|
|
106
|
+
span.updateName(`LiveStore:useQuery:${query$.label}`)
|
|
107
|
+
|
|
104
108
|
return store.subscribe(
|
|
105
109
|
query$,
|
|
106
110
|
(newValue) => {
|
package/src/useRow.test.tsx
CHANGED
|
@@ -121,11 +121,10 @@ describe('useRow', () => {
|
|
|
121
121
|
useGlobalReactivityGraph: false,
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
-
const allTodos$ = LiveStore.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
})
|
|
124
|
+
const allTodos$ = LiveStore.queryDb(
|
|
125
|
+
{ query: `select * from todos`, schema: Schema.Array(tables.todos.schema) },
|
|
126
|
+
{ label: 'allTodos', reactivityGraph },
|
|
127
|
+
)
|
|
129
128
|
|
|
130
129
|
const appRouterRenderCount = makeRenderCount()
|
|
131
130
|
let globalSetState: LiveStoreReact.StateSetters<typeof AppRouterSchema> | undefined
|
|
@@ -223,13 +222,12 @@ describe('useRow', () => {
|
|
|
223
222
|
const [_row, _setRow, rowState$] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
224
223
|
const todos = LiveStoreReact.useScopedQuery(
|
|
225
224
|
() =>
|
|
226
|
-
LiveStore.
|
|
227
|
-
(get) =>
|
|
228
|
-
|
|
225
|
+
LiveStore.queryDb(
|
|
226
|
+
(get) => ({
|
|
227
|
+
query: LiveStore.sql`select * from todos where text like '%${get(rowState$).text}%'`,
|
|
229
228
|
schema: Schema.Array(tables.todos.schema),
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
},
|
|
229
|
+
}),
|
|
230
|
+
{ reactivityGraph, label: 'todosFiltered' },
|
|
233
231
|
),
|
|
234
232
|
userId,
|
|
235
233
|
)
|
package/src/useRow.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { QueryInfo } from '@livestore/common'
|
|
1
|
+
import type { QueryInfo, RowQuery } from '@livestore/common'
|
|
2
2
|
import { SessionIdSymbol } from '@livestore/common'
|
|
3
3
|
import { DbSchema } from '@livestore/common/schema'
|
|
4
4
|
import type { SqliteDsl } from '@livestore/db-schema'
|
|
5
|
-
import type { LiveQuery, ReactivityGraph
|
|
6
|
-
import {
|
|
5
|
+
import type { LiveQuery, ReactivityGraph } from '@livestore/livestore'
|
|
6
|
+
import { queryDb } from '@livestore/livestore'
|
|
7
7
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
8
8
|
import { ReadonlyRecord } from '@livestore/utils/effect'
|
|
9
9
|
import React from 'react'
|
|
@@ -12,16 +12,12 @@ import { useStore } from './LiveStoreContext.js'
|
|
|
12
12
|
import { useQueryRef } from './useQuery.js'
|
|
13
13
|
import { useMakeScopedQuery } from './useScopedQuery.js'
|
|
14
14
|
|
|
15
|
-
export type UseRowResult<TTableDef extends DbSchema.
|
|
16
|
-
row:
|
|
15
|
+
export type UseRowResult<TTableDef extends DbSchema.TableDefBase> = [
|
|
16
|
+
row: RowQuery.Result<TTableDef>,
|
|
17
17
|
setRow: StateSetters<TTableDef>,
|
|
18
|
-
query$: LiveQuery<
|
|
18
|
+
query$: LiveQuery<RowQuery.Result<TTableDef>, QueryInfo>,
|
|
19
19
|
]
|
|
20
20
|
|
|
21
|
-
export type UseRowOptionsDefaulValues<TTableDef extends DbSchema.TableDef> = {
|
|
22
|
-
defaultValues?: Partial<RowResult<TTableDef>>
|
|
23
|
-
}
|
|
24
|
-
|
|
25
21
|
export type UseRowOptionsBase = {
|
|
26
22
|
reactivityGraph?: ReactivityGraph
|
|
27
23
|
}
|
|
@@ -39,7 +35,6 @@ export const useRow: {
|
|
|
39
35
|
<
|
|
40
36
|
TTableDef extends DbSchema.TableDef<
|
|
41
37
|
DbSchema.DefaultSqliteTableDef,
|
|
42
|
-
boolean,
|
|
43
38
|
DbSchema.TableOptions & { isSingleton: true; deriveMutations: { enabled: true } }
|
|
44
39
|
>,
|
|
45
40
|
>(
|
|
@@ -49,31 +44,44 @@ export const useRow: {
|
|
|
49
44
|
<
|
|
50
45
|
TTableDef extends DbSchema.TableDef<
|
|
51
46
|
DbSchema.DefaultSqliteTableDef,
|
|
52
|
-
|
|
47
|
+
DbSchema.TableOptions & {
|
|
48
|
+
isSingleton: false
|
|
49
|
+
requiredInsertColumnNames: 'id'
|
|
50
|
+
deriveMutations: { enabled: true }
|
|
51
|
+
}
|
|
52
|
+
>,
|
|
53
|
+
>(
|
|
54
|
+
table: TTableDef,
|
|
55
|
+
// TODO adjust so it works with arbitrary primary keys or unique constraints
|
|
56
|
+
id: string | SessionIdSymbol,
|
|
57
|
+
options?: UseRowOptionsBase & Partial<RowQuery.RequiredColumnsOptions<TTableDef>>,
|
|
58
|
+
): UseRowResult<TTableDef>
|
|
59
|
+
<
|
|
60
|
+
TTableDef extends DbSchema.TableDef<
|
|
61
|
+
DbSchema.DefaultSqliteTableDef,
|
|
53
62
|
DbSchema.TableOptions & { isSingleton: false; deriveMutations: { enabled: true } }
|
|
54
63
|
>,
|
|
55
64
|
>(
|
|
56
65
|
table: TTableDef,
|
|
57
66
|
// TODO adjust so it works with arbitrary primary keys or unique constraints
|
|
58
67
|
id: string | SessionIdSymbol,
|
|
59
|
-
options
|
|
68
|
+
options: UseRowOptionsBase & RowQuery.RequiredColumnsOptions<TTableDef>,
|
|
60
69
|
): UseRowResult<TTableDef>
|
|
61
70
|
} = <
|
|
62
71
|
TTableDef extends DbSchema.TableDef<
|
|
63
72
|
DbSchema.DefaultSqliteTableDefConstrained,
|
|
64
|
-
boolean,
|
|
65
73
|
DbSchema.TableOptions & { deriveMutations: { enabled: true } }
|
|
66
74
|
>,
|
|
67
75
|
>(
|
|
68
76
|
table: TTableDef,
|
|
69
77
|
idOrOptions?: string | SessionIdSymbol | UseRowOptionsBase,
|
|
70
|
-
options_?: UseRowOptionsBase &
|
|
78
|
+
options_?: UseRowOptionsBase & Partial<RowQuery.RequiredColumnsOptions<TTableDef>>,
|
|
71
79
|
): UseRowResult<TTableDef> => {
|
|
72
80
|
const sqliteTableDef = table.sqliteDef
|
|
73
81
|
const id = typeof idOrOptions === 'string' || idOrOptions === SessionIdSymbol ? idOrOptions : undefined
|
|
74
|
-
const options: (UseRowOptionsBase &
|
|
82
|
+
const options: (UseRowOptionsBase & Partial<RowQuery.RequiredColumnsOptions<TTableDef>>) | undefined =
|
|
75
83
|
typeof idOrOptions === 'string' || idOrOptions === SessionIdSymbol ? options_ : idOrOptions
|
|
76
|
-
const {
|
|
84
|
+
const { insertValues, reactivityGraph } = options ?? {}
|
|
77
85
|
|
|
78
86
|
type TComponentState = SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>
|
|
79
87
|
|
|
@@ -95,16 +103,14 @@ export const useRow: {
|
|
|
95
103
|
// console.debug('useRow', tableName, id)
|
|
96
104
|
|
|
97
105
|
const idStr = id === SessionIdSymbol ? 'session' : id
|
|
106
|
+
const rowQuery = table.query.row as any
|
|
98
107
|
|
|
108
|
+
type Query$ = LiveQuery<RowQuery.Result<TTableDef>, QueryInfo.Row>
|
|
99
109
|
const { query$, otelContext } = useMakeScopedQuery(
|
|
100
110
|
(otelContext) =>
|
|
101
111
|
DbSchema.tableIsSingleton(table)
|
|
102
|
-
? (rowQuery(
|
|
103
|
-
: (rowQuery(
|
|
104
|
-
otelContext,
|
|
105
|
-
defaultValues: defaultValues!,
|
|
106
|
-
reactivityGraph,
|
|
107
|
-
}) as any as LiveQuery<RowResult<TTableDef>, QueryInfo>),
|
|
112
|
+
? (queryDb(rowQuery(), { reactivityGraph, otelContext }) as any as Query$)
|
|
113
|
+
: (queryDb(rowQuery(id!, { insertValues: insertValues! }), { reactivityGraph, otelContext }) as any as Query$),
|
|
108
114
|
[idStr!, tableName],
|
|
109
115
|
{
|
|
110
116
|
otel: {
|
|
@@ -114,11 +120,11 @@ export const useRow: {
|
|
|
114
120
|
},
|
|
115
121
|
)
|
|
116
122
|
|
|
117
|
-
const query$Ref = useQueryRef(query$, otelContext) as React.MutableRefObject<
|
|
123
|
+
const query$Ref = useQueryRef(query$, otelContext) as React.MutableRefObject<RowQuery.Result<TTableDef>>
|
|
118
124
|
|
|
119
125
|
const setState = React.useMemo<StateSetters<TTableDef>>(() => {
|
|
120
|
-
if (table.isSingleColumn) {
|
|
121
|
-
return (newValueOrFn:
|
|
126
|
+
if (table.options.isSingleColumn) {
|
|
127
|
+
return (newValueOrFn: RowQuery.Result<TTableDef>) => {
|
|
122
128
|
const newValue = typeof newValueOrFn === 'function' ? newValueOrFn(query$Ref.current) : newValueOrFn
|
|
123
129
|
if (query$Ref.current === newValue) return
|
|
124
130
|
|
|
@@ -173,10 +179,10 @@ export const useRow: {
|
|
|
173
179
|
export type Dispatch<A> = (action: A) => void
|
|
174
180
|
export type SetStateAction<S> = S | ((previousValue: S) => S)
|
|
175
181
|
|
|
176
|
-
export type StateSetters<TTableDef extends DbSchema.
|
|
177
|
-
? Dispatch<SetStateAction<
|
|
182
|
+
export type StateSetters<TTableDef extends DbSchema.TableDefBase> = TTableDef['options']['isSingleColumn'] extends true
|
|
183
|
+
? Dispatch<SetStateAction<RowQuery.Result<TTableDef>>>
|
|
178
184
|
: {
|
|
179
|
-
[K in keyof
|
|
185
|
+
[K in keyof RowQuery.Result<TTableDef>]: Dispatch<SetStateAction<RowQuery.Result<TTableDef>[K]>>
|
|
180
186
|
} & {
|
|
181
|
-
setMany: Dispatch<SetStateAction<Partial<
|
|
187
|
+
setMany: Dispatch<SetStateAction<Partial<RowQuery.Result<TTableDef>>>>
|
|
182
188
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as LiveStore from '@livestore/livestore'
|
|
2
|
-
import {
|
|
2
|
+
import { queryDb } from '@livestore/livestore'
|
|
3
3
|
import { Effect, Schema } from '@livestore/utils/effect'
|
|
4
4
|
import { render, renderHook } from '@testing-library/react'
|
|
5
5
|
import React from 'react'
|
|
@@ -29,7 +29,8 @@ describe('useScopedQuery', () => {
|
|
|
29
29
|
renderCount.inc()
|
|
30
30
|
|
|
31
31
|
return LiveStoreReact.useScopedQuery(() => {
|
|
32
|
-
const query$ =
|
|
32
|
+
const query$ = queryDb({
|
|
33
|
+
query: `select * from todos where id = '${id}'`,
|
|
33
34
|
schema: Schema.Array(tables.todos.schema),
|
|
34
35
|
})
|
|
35
36
|
queryMap.set(id, query$)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.test.d.ts","sourceRoot":"","sources":["../src/useTemporaryQuery.test.tsx"],"names":[],"mappings":""}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import * as LiveStore from '@livestore/livestore';
|
|
2
|
-
import { querySQL } from '@livestore/livestore';
|
|
3
|
-
import { Effect, Schema } from '@livestore/utils/effect';
|
|
4
|
-
import { render, renderHook } from '@testing-library/react';
|
|
5
|
-
import React from 'react';
|
|
6
|
-
// @ts-expect-error no types
|
|
7
|
-
import * as ReactWindow from 'react-window';
|
|
8
|
-
import { describe, expect, it } from 'vitest';
|
|
9
|
-
import { makeTodoMvcReact, tables, todos } from './__tests__/fixture.js';
|
|
10
|
-
import * as LiveStoreReact from './mod.js';
|
|
11
|
-
describe('useTemporaryQuery', () => {
|
|
12
|
-
it('simple', () => Effect.gen(function* () {
|
|
13
|
-
const { wrapper, store, makeRenderCount } = yield* makeTodoMvcReact();
|
|
14
|
-
const renderCount = makeRenderCount();
|
|
15
|
-
store.mutate(todos.insert({ id: 't1', text: 'buy milk', completed: false }), todos.insert({ id: 't2', text: 'buy bread', completed: false }));
|
|
16
|
-
const queryMap = new Map();
|
|
17
|
-
const { rerender, result, unmount } = renderHook((id) => {
|
|
18
|
-
renderCount.inc();
|
|
19
|
-
return LiveStoreReact.useTemporaryQuery(() => {
|
|
20
|
-
const query$ = querySQL(`select * from todos where id = '${id}'`, {
|
|
21
|
-
schema: Schema.Array(tables.todos.schema),
|
|
22
|
-
});
|
|
23
|
-
queryMap.set(id, query$);
|
|
24
|
-
return query$;
|
|
25
|
-
}, id);
|
|
26
|
-
}, { wrapper, initialProps: 't1' });
|
|
27
|
-
expect(result.current.length).toBe(1);
|
|
28
|
-
expect(result.current[0].text).toBe('buy milk');
|
|
29
|
-
expect(renderCount.val).toBe(1);
|
|
30
|
-
expect(queryMap.get('t1').runs).toBe(1);
|
|
31
|
-
rerender('t2');
|
|
32
|
-
expect(result.current.length).toBe(1);
|
|
33
|
-
expect(result.current[0].text).toBe('buy bread');
|
|
34
|
-
expect(renderCount.val).toBe(2);
|
|
35
|
-
expect(queryMap.get('t1').runs).toBe(1);
|
|
36
|
-
expect(queryMap.get('t2').runs).toBe(1);
|
|
37
|
-
unmount();
|
|
38
|
-
expect(queryMap.get('t2').runs).toBe(1);
|
|
39
|
-
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise));
|
|
40
|
-
// NOTE this test covers some special react lifecyle paths which I couldn't easily reproduce without react-window
|
|
41
|
-
// it basically causes a "query swap" in the `useMemo` and both a `useEffect` cleanup call.
|
|
42
|
-
// To handle this properly we introduced the `_tag: 'destroyed'` state in the `spanAlreadyStartedCache`.
|
|
43
|
-
it('should work for a list with react-window', () => Effect.gen(function* () {
|
|
44
|
-
const { wrapper } = yield* makeTodoMvcReact();
|
|
45
|
-
const ListWrapper = ({ numItems }) => {
|
|
46
|
-
return (React.createElement(ReactWindow.FixedSizeList, { height: 100, width: 100, itemSize: 10, itemCount: numItems, itemData: Array.from({ length: numItems }, (_, i) => i).reverse() }, ListItem));
|
|
47
|
-
};
|
|
48
|
-
const ListItem = ({ data: ids, index }) => {
|
|
49
|
-
const id = ids[index];
|
|
50
|
-
const res = LiveStoreReact.useTemporaryQuery(() => LiveStore.computed(() => id, { label: `ListItem.${id}` }), id);
|
|
51
|
-
return React.createElement("div", { role: "listitem" }, res);
|
|
52
|
-
};
|
|
53
|
-
const renderResult = render(React.createElement(ListWrapper, { numItems: 1 }), { wrapper });
|
|
54
|
-
expect(renderResult.container.textContent).toBe('0');
|
|
55
|
-
renderResult.rerender(React.createElement(ListWrapper, { numItems: 2 }));
|
|
56
|
-
expect(renderResult.container.textContent).toBe('10');
|
|
57
|
-
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise));
|
|
58
|
-
});
|
|
59
|
-
//# sourceMappingURL=useTemporaryQuery.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.test.js","sourceRoot":"","sources":["../src/useTemporaryQuery.test.tsx"],"names":[],"mappings":"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"}
|