@livestore/react 0.0.0-snapshot-6cc3ccfc2318063f931d98d618e1345665c2f8c5 → 0.0.0-snapshot-6d428e0ce79da666fbb12cf54f67ff91732aec2b
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.d.ts +0 -22
- package/dist/useTemporaryQuery.d.ts.map +0 -1
- package/dist/useTemporaryQuery.js +0 -75
- package/dist/useTemporaryQuery.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,22 +0,0 @@
|
|
|
1
|
-
import type { QueryInfo } from '@livestore/common';
|
|
2
|
-
import type { LiveQuery } from '@livestore/livestore';
|
|
3
|
-
import * as otel from '@opentelemetry/api';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
export type DepKey = string | number | ReadonlyArray<string | number>;
|
|
6
|
-
/**
|
|
7
|
-
* Creates a query, subscribes and destroys it when the component unmounts.
|
|
8
|
-
*
|
|
9
|
-
* The `key` is used to determine whether the a new query should be created or if the existing one should be reused.
|
|
10
|
-
*/
|
|
11
|
-
export declare const useScopedQuery: <TResult>(makeQuery: () => LiveQuery<TResult>, key: DepKey) => TResult;
|
|
12
|
-
export declare const useScopedQueryRef: <TResult>(makeQuery: () => LiveQuery<TResult>, key: DepKey) => React.MutableRefObject<TResult>;
|
|
13
|
-
export declare const useMakeScopedQuery: <TResult, TQueryInfo extends QueryInfo>(makeQuery: (otelContext: otel.Context) => LiveQuery<TResult, TQueryInfo>, key: DepKey, options?: {
|
|
14
|
-
otel?: {
|
|
15
|
-
spanName?: string;
|
|
16
|
-
attributes?: otel.Attributes;
|
|
17
|
-
};
|
|
18
|
-
}) => {
|
|
19
|
-
query$: LiveQuery<TResult, TQueryInfo>;
|
|
20
|
-
otelContext: otel.Context;
|
|
21
|
-
};
|
|
22
|
-
//# sourceMappingURL=useTemporaryQuery.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.d.ts","sourceRoot":"","sources":["../src/useTemporaryQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAC1C,OAAO,KAAK,MAAM,OAAO,CAAA;AAuBzB,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC,CAAA;AAErE;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,aAAa,MAAM,SAAS,CAAC,OAAO,CAAC,OAAO,MAAM,KAAG,OAChD,CAAA;AAE3C,eAAO,MAAM,iBAAiB,GAAI,OAAO,aAC5B,MAAM,SAAS,CAAC,OAAO,CAAC,OAC9B,MAAM,KACV,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAIhC,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,EAAE,UAAU,SAAS,SAAS,aAC3D,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,OACnE,MAAM,YACD;IACR,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,CAAA;KAC7B,CAAA;CACF,KACA;IAAE,MAAM,EAAE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAA;CA4ErE,CAAA"}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import * as otel from '@opentelemetry/api';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { useStore } from './LiveStoreContext.js';
|
|
4
|
-
import { useQueryRef } from './useQuery.js';
|
|
5
|
-
// NOTE Given `useMemo` will be called multiple times (e.g. when using React Strict mode or Fast Refresh),
|
|
6
|
-
// we are using this cache to avoid starting multiple queries/spans for the same component.
|
|
7
|
-
// This is somewhat against some recommended React best practices, but it should be fine in our case below.
|
|
8
|
-
// Please definitely open an issue if you see or run into any problems with this approach!
|
|
9
|
-
const cache = new Map();
|
|
10
|
-
/**
|
|
11
|
-
* Creates a query, subscribes and destroys it when the component unmounts.
|
|
12
|
-
*
|
|
13
|
-
* The `key` is used to determine whether the a new query should be created or if the existing one should be reused.
|
|
14
|
-
*/
|
|
15
|
-
export const useScopedQuery = (makeQuery, key) => useScopedQueryRef(makeQuery, key).current;
|
|
16
|
-
export const useScopedQueryRef = (makeQuery, key) => {
|
|
17
|
-
const { query$ } = useMakeScopedQuery(makeQuery, key);
|
|
18
|
-
return useQueryRef(query$);
|
|
19
|
-
};
|
|
20
|
-
export const useMakeScopedQuery = (makeQuery, key, options) => {
|
|
21
|
-
const { store } = useStore();
|
|
22
|
-
const fullKey = React.useMemo(
|
|
23
|
-
// NOTE We're using the `makeQuery` function body string to make sure the key is unique across the app
|
|
24
|
-
// TODO we should figure out whether this could cause some problems and/or if there's a better way to do this
|
|
25
|
-
() => (Array.isArray(key) ? key.join('-') : key) + '-' + store.reactivityGraph.id + '-' + makeQuery.toString(), [key, makeQuery, store.reactivityGraph.id]);
|
|
26
|
-
const fullKeyRef = React.useRef();
|
|
27
|
-
const { query$, otelContext } = React.useMemo(() => {
|
|
28
|
-
if (fullKeyRef.current !== undefined && fullKeyRef.current !== fullKey) {
|
|
29
|
-
// console.debug('fullKey changed', 'prev', fullKeyRef.current.split('-')[0]!, '-> new', fullKey.split('-')[0]!)
|
|
30
|
-
const cachedItem = cache.get(fullKeyRef.current);
|
|
31
|
-
if (cachedItem !== undefined && cachedItem._tag === 'active') {
|
|
32
|
-
cachedItem.rc--;
|
|
33
|
-
if (cachedItem.rc === 0) {
|
|
34
|
-
// console.debug('rc=0-changed', cachedItem.query$.id, cachedItem.query$.label)
|
|
35
|
-
cachedItem.query$.destroy();
|
|
36
|
-
cachedItem.span.end();
|
|
37
|
-
cache.set(fullKeyRef.current, { _tag: 'destroyed' });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
const cachedItem = cache.get(fullKey);
|
|
42
|
-
if (cachedItem !== undefined && cachedItem._tag === 'active') {
|
|
43
|
-
// console.debug('rc++', cachedItem.query$.id, cachedItem.query$.label)
|
|
44
|
-
cachedItem.rc++;
|
|
45
|
-
return cachedItem;
|
|
46
|
-
}
|
|
47
|
-
const spanName = options?.otel?.spanName ?? `LiveStore:useScopedQuery:${key}`;
|
|
48
|
-
const span = store.otel.tracer.startSpan(spanName, { attributes: options?.otel?.attributes }, store.otel.queriesSpanContext);
|
|
49
|
-
const otelContext = otel.trace.setSpan(otel.context.active(), span);
|
|
50
|
-
const query$ = makeQuery(otelContext);
|
|
51
|
-
cache.set(fullKey, { _tag: 'active', rc: 1, query$, span, otelContext });
|
|
52
|
-
return { query$, otelContext };
|
|
53
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
54
|
-
}, [fullKey]);
|
|
55
|
-
fullKeyRef.current = fullKey;
|
|
56
|
-
React.useEffect(() => {
|
|
57
|
-
return () => {
|
|
58
|
-
const fullKey = fullKeyRef.current;
|
|
59
|
-
const cachedItem = cache.get(fullKey);
|
|
60
|
-
// NOTE in case the fullKey changed then the query was already destroyed in the useMemo above
|
|
61
|
-
if (cachedItem === undefined || cachedItem._tag === 'destroyed')
|
|
62
|
-
return;
|
|
63
|
-
// console.debug('rc--', cachedItem.query$.id, cachedItem.query$.label)
|
|
64
|
-
cachedItem.rc--;
|
|
65
|
-
if (cachedItem.rc === 0) {
|
|
66
|
-
// console.debug('rc=0', cachedItem.query$.id, cachedItem.query$.label)
|
|
67
|
-
cachedItem.query$.destroy();
|
|
68
|
-
cachedItem.span.end();
|
|
69
|
-
cache.delete(fullKey);
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
}, []);
|
|
73
|
-
return { query$, otelContext };
|
|
74
|
-
};
|
|
75
|
-
//# sourceMappingURL=useTemporaryQuery.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useTemporaryQuery.js","sourceRoot":"","sources":["../src/useTemporaryQuery.ts"],"names":[],"mappings":"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"}
|