@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.
@@ -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": "select 1 from UserInfo where id = 'u1'",
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": "select 1 from UserInfo where id = 'u2'",
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": "sql:select * from UserInfo where id = 'u1' limit 1",
78
+ "_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
79
79
  "attributes": {
80
- "sql.query": "select * from UserInfo where id = 'u1' limit 1",
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": "select * from UserInfo where id = 'u1' limit 1",
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:sql(rowQuery:query:UserInfo:u1)",
118
+ "_name": "LiveStore:useQuery:db(row:UserInfo:u1)",
119
119
  "attributes": {
120
- "label": "sql(rowQuery:query:UserInfo:u1)",
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": "sql:select * from UserInfo where id = 'u1' limit 1",
125
+ "_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
126
126
  "attributes": {
127
- "sql.query": "select * from UserInfo where id = 'u1' limit 1",
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": "select * from UserInfo where id = 'u1' limit 1",
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": "sql(rowQuery:query:UserInfo:u1)",
145
- "queryLabel": "sql(rowQuery:query:UserInfo:u1)",
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:sql(rowQuery:query:UserInfo:u2)",
159
+ "_name": "LiveStore:useQuery:db(row:UserInfo:u2)",
160
160
  "attributes": {
161
- "label": "sql(rowQuery:query:UserInfo:u2)",
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": "sql:select * from UserInfo where id = 'u2' limit 1",
166
+ "_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
167
167
  "attributes": {
168
- "sql.query": "select * from UserInfo where id = 'u2' limit 1",
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": "select * from UserInfo where id = 'u2' limit 1",
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": "sql(rowQuery:query:UserInfo:u2)",
186
- "queryLabel": "sql(rowQuery:query:UserInfo:u2)",
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": "select 1 from UserInfo where id = 'u1'",
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": "select 1 from UserInfo where id = 'u2'",
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": "sql:select * from UserInfo where id = 'u1' limit 1",
274
+ "_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
275
275
  "attributes": {
276
- "sql.query": "select * from UserInfo where id = 'u1' limit 1",
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": "select * from UserInfo where id = 'u1' limit 1",
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:sql(rowQuery:query:UserInfo:u1)",
314
+ "_name": "LiveStore:useQuery:db(row:UserInfo:u1)",
315
315
  "attributes": {
316
- "label": "sql(rowQuery:query:UserInfo:u1)",
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": "sql:select * from UserInfo where id = 'u1' limit 1",
321
+ "_name": "db:SELECT * FROM 'UserInfo' WHERE id = ?",
322
322
  "attributes": {
323
- "sql.query": "select * from UserInfo where id = 'u1' limit 1",
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": "select * from UserInfo where id = 'u1' limit 1",
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": "sql(rowQuery:query:UserInfo:u1)",
341
- "queryLabel": "sql(rowQuery:query:UserInfo:u1)",
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": "sql(rowQuery:query:UserInfo:u1)",
348
- "queryLabel": "sql(rowQuery:query:UserInfo:u1)",
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 { type QueryInfoCol, type QueryInfoRow } from '@livestore/common'
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
- TQuery extends LiveQuery<any, QueryInfoRow<TTableDef> | QueryInfoCol<TTableDef, any>>,
12
- TTableDef extends DbSchema.TableDef<
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 (query$.queryInfo.table.options.isSingleton && query$.queryInfo.table.isSingleColumn) {
31
- store.mutate(query$.queryInfo.table.update(newValue))
32
- } else if (query$.queryInfo.table.options.isSingleColumn) {
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(query$.queryInfo.table.update({ where: { id: query$.queryInfo.id }, values: newValue }))
34
+ store.mutate(table.update({ where: { id: query$.queryInfo.id }, values: newValue }))
38
35
  }
39
36
  } else {
40
- if (query$.queryInfo.table.options.isSingleton && query$.queryInfo.table.isSingleColumn) {
41
- store.mutate(query$.queryInfo.table.update({ [query$.queryInfo.column]: newValue }))
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
- query$.queryInfo.table.update({
41
+ table.update({
45
42
  where: { id: query$.queryInfo.id },
46
43
  values: { [query$.queryInfo.column]: newValue },
47
44
  }),
@@ -1,4 +1,4 @@
1
- import { querySQL } from '@livestore/livestore'
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$ = querySQL(`select * from todos`, { schema: Schema.Array(tables.todos.schema) })
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$ = querySQL(`select * from todos where id = 't1'`, {
45
- label: 'libraryTracksView1',
46
- schema: Schema.Array(tables.todos.schema),
47
- })
48
- const todo2$ = querySQL(`select * from todos where id = 't2'`, {
49
- label: 'libraryTracksView2',
50
- schema: Schema.Array(tables.todos.schema),
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) => {
@@ -121,11 +121,10 @@ describe('useRow', () => {
121
121
  useGlobalReactivityGraph: false,
122
122
  })
123
123
 
124
- const allTodos$ = LiveStore.querySQL(`select * from todos`, {
125
- label: 'allTodos',
126
- schema: Schema.Array(tables.todos.schema),
127
- reactivityGraph,
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.querySQL(
227
- (get) => LiveStore.sql`select * from todos where text like '%${get(rowState$).text}%'`,
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
- reactivityGraph,
231
- label: 'todosFiltered',
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, RowResult } from '@livestore/livestore'
6
- import { rowQuery } from '@livestore/livestore'
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.TableDef> = [
16
- row: RowResult<TTableDef>,
15
+ export type UseRowResult<TTableDef extends DbSchema.TableDefBase> = [
16
+ row: RowQuery.Result<TTableDef>,
17
17
  setRow: StateSetters<TTableDef>,
18
- query$: LiveQuery<RowResult<TTableDef>, QueryInfo>,
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
- boolean,
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?: UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>,
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 & UseRowOptionsDefaulValues<TTableDef>,
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 & UseRowOptionsDefaulValues<TTableDef>) | undefined =
82
+ const options: (UseRowOptionsBase & Partial<RowQuery.RequiredColumnsOptions<TTableDef>>) | undefined =
75
83
  typeof idOrOptions === 'string' || idOrOptions === SessionIdSymbol ? options_ : idOrOptions
76
- const { defaultValues, reactivityGraph } = options ?? {}
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(table, { otelContext, reactivityGraph }) as LiveQuery<RowResult<TTableDef>, QueryInfo>)
103
- : (rowQuery(table as TTableDef & { options: { isSingleton: false } }, id!, {
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<RowResult<TTableDef>>
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: RowResult<TTableDef>) => {
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.TableDef> = TTableDef['isSingleColumn'] extends true
177
- ? Dispatch<SetStateAction<RowResult<TTableDef>>>
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 RowResult<TTableDef>]: Dispatch<SetStateAction<RowResult<TTableDef>[K]>>
185
+ [K in keyof RowQuery.Result<TTableDef>]: Dispatch<SetStateAction<RowQuery.Result<TTableDef>[K]>>
180
186
  } & {
181
- setMany: Dispatch<SetStateAction<Partial<RowResult<TTableDef>>>>
187
+ setMany: Dispatch<SetStateAction<Partial<RowQuery.Result<TTableDef>>>>
182
188
  }
@@ -1,5 +1,5 @@
1
1
  import * as LiveStore from '@livestore/livestore'
2
- import { querySQL } from '@livestore/livestore'
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$ = querySQL(`select * from todos where id = '${id}'`, {
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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=useTemporaryQuery.test.d.ts.map
@@ -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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"}