@livestore/react 0.4.0-dev.1 → 0.4.0-dev.10
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.d.ts +1 -3
- package/dist/LiveStoreProvider.d.ts.map +1 -1
- package/dist/LiveStoreProvider.js +22 -18
- package/dist/LiveStoreProvider.js.map +1 -1
- package/dist/LiveStoreProvider.test.js +1 -1
- package/dist/LiveStoreProvider.test.js.map +1 -1
- package/dist/__tests__/fixture.d.ts +24 -3
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +10 -3
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js.map +1 -1
- package/dist/useClientDocument.d.ts +10 -13
- package/dist/useClientDocument.d.ts.map +1 -1
- package/dist/useClientDocument.js +3 -4
- package/dist/useClientDocument.js.map +1 -1
- package/dist/useClientDocument.test.js +20 -2
- package/dist/useClientDocument.test.js.map +1 -1
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +1 -2
- package/dist/useQuery.js.map +1 -1
- package/package.json +13 -13
- package/src/LiveStoreProvider.test.tsx +1 -1
- package/src/LiveStoreProvider.tsx +24 -19
- package/src/__snapshots__/useClientDocument.test.tsx.snap +208 -100
- package/src/__snapshots__/useQuery.test.tsx.snap +388 -116
- package/src/__tests__/fixture.tsx +17 -9
- package/src/mod.ts +2 -1
- package/src/useClientDocument.test.tsx +31 -2
- package/src/useClientDocument.ts +22 -12
- package/src/useQuery.ts +1 -2
@@ -3,6 +3,7 @@ import { provideOtel, type UnexpectedError } from '@livestore/common'
|
|
3
3
|
import { Events, makeSchema, State } from '@livestore/common/schema'
|
4
4
|
import type { LiveStoreSchema, SqliteDsl, Store } from '@livestore/livestore'
|
5
5
|
import { createStore } from '@livestore/livestore'
|
6
|
+
import { omitUndefineds } from '@livestore/utils'
|
6
7
|
import { Effect, Schema, type Scope } from '@livestore/utils/effect'
|
7
8
|
import type * as otel from '@opentelemetry/api'
|
8
9
|
import React from 'react'
|
@@ -60,6 +61,12 @@ const AppRouterSchema = State.SQLite.clientDocument({
|
|
60
61
|
},
|
61
62
|
})
|
62
63
|
|
64
|
+
const kv = State.SQLite.clientDocument({
|
65
|
+
name: 'Kv',
|
66
|
+
schema: Schema.Any,
|
67
|
+
default: { value: null },
|
68
|
+
})
|
69
|
+
|
63
70
|
export const events = {
|
64
71
|
todoCreated: Events.synced({
|
65
72
|
name: 'todoCreated',
|
@@ -75,14 +82,15 @@ export const events = {
|
|
75
82
|
}),
|
76
83
|
AppRouterSet: AppRouterSchema.set,
|
77
84
|
UserInfoSet: userInfo.set,
|
85
|
+
KvSet: kv.set,
|
78
86
|
}
|
79
87
|
|
80
88
|
const materializers = State.SQLite.materializers(events, {
|
81
89
|
todoCreated: ({ id, text, completed }) => todos.insert({ id, text, completed }),
|
82
|
-
todoUpdated: ({ id, text, completed }) => todos.update({ completed, text }).where({ id }),
|
90
|
+
todoUpdated: ({ id, text, completed }) => todos.update({ ...omitUndefineds({ completed, text }) }).where({ id }),
|
83
91
|
})
|
84
92
|
|
85
|
-
export const tables = { todos, app, userInfo, AppRouterSchema }
|
93
|
+
export const tables = { todos, app, userInfo, AppRouterSchema, kv }
|
86
94
|
|
87
95
|
const state = State.SQLite.makeState({ tables, materializers })
|
88
96
|
export const schema = makeSchema({ state, events })
|
@@ -92,9 +100,9 @@ export const makeTodoMvcReact: ({
|
|
92
100
|
otelContext,
|
93
101
|
strictMode,
|
94
102
|
}?: {
|
95
|
-
otelTracer?: otel.Tracer
|
96
|
-
otelContext?: otel.Context
|
97
|
-
strictMode?: boolean
|
103
|
+
otelTracer?: otel.Tracer | undefined
|
104
|
+
otelContext?: otel.Context | undefined
|
105
|
+
strictMode?: boolean | undefined
|
98
106
|
}) => Effect.Effect<
|
99
107
|
{
|
100
108
|
wrapper: ({ children }: any) => React.JSX.Element
|
@@ -108,9 +116,9 @@ export const makeTodoMvcReact: ({
|
|
108
116
|
otelContext,
|
109
117
|
strictMode,
|
110
118
|
}: {
|
111
|
-
otelTracer?: otel.Tracer
|
112
|
-
otelContext?: otel.Context
|
113
|
-
strictMode?: boolean
|
119
|
+
otelTracer?: otel.Tracer | undefined
|
120
|
+
otelContext?: otel.Context | undefined
|
121
|
+
strictMode?: boolean | undefined
|
114
122
|
} = {}) =>
|
115
123
|
Effect.gen(function* () {
|
116
124
|
const makeRenderCount = () => {
|
@@ -156,4 +164,4 @@ export const makeTodoMvcReact: ({
|
|
156
164
|
const renderCount = makeRenderCount()
|
157
165
|
|
158
166
|
return { wrapper, store: storeWithReactApi, renderCount }
|
159
|
-
}).pipe(provideOtel({ parentSpanContext: otelContext, otelTracer }))
|
167
|
+
}).pipe(provideOtel(omitUndefineds({ parentSpanContext: otelContext, otelTracer })))
|
package/src/mod.ts
CHANGED
@@ -3,8 +3,9 @@ export { LiveStoreProvider } from './LiveStoreProvider.tsx'
|
|
3
3
|
export {
|
4
4
|
type Dispatch,
|
5
5
|
type SetStateAction,
|
6
|
+
type SetStateActionPartial,
|
6
7
|
type StateSetters,
|
7
|
-
type
|
8
|
+
type UseClientDocumentResult,
|
8
9
|
useClientDocument,
|
9
10
|
} from './useClientDocument.ts'
|
10
11
|
export { useQuery, useQueryRef } from './useQuery.ts'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
/** biome-ignore-all lint/a11y/useValidAriaRole: not needed for testing */
|
2
2
|
/** biome-ignore-all lint/a11y/noStaticElementInteractions: not needed for testing */
|
3
3
|
import * as LiveStore from '@livestore/livestore'
|
4
|
-
import { getSimplifiedRootSpan } from '@livestore/livestore/internal/testing-utils'
|
4
|
+
import { getAllSimplifiedRootSpans, getSimplifiedRootSpan } from '@livestore/livestore/internal/testing-utils'
|
5
5
|
import { Effect, ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
6
6
|
import { Vitest } from '@livestore/utils-dev/node-vitest'
|
7
7
|
import * as otel from '@opentelemetry/api'
|
@@ -224,6 +224,34 @@ Vitest.describe('useClientDocument', () => {
|
|
224
224
|
}),
|
225
225
|
)
|
226
226
|
|
227
|
+
Vitest.scopedLive('kv client document overwrites value (Schema.Any, no partial merge)', () =>
|
228
|
+
Effect.gen(function* () {
|
229
|
+
const { wrapper, store, renderCount } = yield* makeTodoMvcReact({})
|
230
|
+
|
231
|
+
const { result } = ReactTesting.renderHook(
|
232
|
+
(id: string) => {
|
233
|
+
renderCount.inc()
|
234
|
+
|
235
|
+
const [state, setState] = store.useClientDocument(tables.kv, id)
|
236
|
+
return { state, setState, id }
|
237
|
+
},
|
238
|
+
{ wrapper, initialProps: 'k1' },
|
239
|
+
)
|
240
|
+
|
241
|
+
expect(result.current.id).toBe('k1')
|
242
|
+
expect(result.current.state).toBe(null)
|
243
|
+
expect(renderCount.val).toBe(1)
|
244
|
+
|
245
|
+
ReactTesting.act(() => result.current.setState(1))
|
246
|
+
expect(result.current.state).toEqual(1)
|
247
|
+
expect(renderCount.val).toBe(2)
|
248
|
+
|
249
|
+
ReactTesting.act(() => result.current.setState({ b: 2 }))
|
250
|
+
expect(result.current.state).toEqual({ b: 2 })
|
251
|
+
expect(renderCount.val).toBe(3)
|
252
|
+
}),
|
253
|
+
)
|
254
|
+
|
227
255
|
Vitest.describe('otel', () => {
|
228
256
|
it.each([{ strictMode: true }, { strictMode: false }])(
|
229
257
|
'should update the data based on component key strictMode=%s',
|
@@ -295,7 +323,8 @@ Vitest.describe('useClientDocument', () => {
|
|
295
323
|
})
|
296
324
|
}
|
297
325
|
|
298
|
-
expect(getSimplifiedRootSpan(exporter, mapAttributes)).toMatchSnapshot()
|
326
|
+
expect(getSimplifiedRootSpan(exporter, 'createStore', mapAttributes)).toMatchSnapshot()
|
327
|
+
expect(getAllSimplifiedRootSpans(exporter, 'LiveStore:commit', mapAttributes)).toMatchSnapshot()
|
299
328
|
|
300
329
|
await provider.shutdown()
|
301
330
|
},
|
package/src/useClientDocument.ts
CHANGED
@@ -3,13 +3,13 @@ import { SessionIdSymbol } from '@livestore/common'
|
|
3
3
|
import { State } from '@livestore/common/schema'
|
4
4
|
import type { LiveQuery, LiveQueryDef, Store } from '@livestore/livestore'
|
5
5
|
import { queryDb } from '@livestore/livestore'
|
6
|
-
import { shouldNeverHappen } from '@livestore/utils'
|
6
|
+
import { omitUndefineds, shouldNeverHappen } from '@livestore/utils'
|
7
7
|
import React from 'react'
|
8
8
|
|
9
9
|
import { LiveStoreContext } from './LiveStoreContext.ts'
|
10
10
|
import { useQueryRef } from './useQuery.ts'
|
11
11
|
|
12
|
-
export type
|
12
|
+
export type UseClientDocumentResult<TTableDef extends State.SQLite.ClientDocumentTableDef.TraitAny> = [
|
13
13
|
row: TTableDef['Value'],
|
14
14
|
setRow: StateSetters<TTableDef>,
|
15
15
|
id: string,
|
@@ -54,13 +54,17 @@ export const useClientDocument: {
|
|
54
54
|
any,
|
55
55
|
any,
|
56
56
|
any,
|
57
|
-
{
|
57
|
+
{
|
58
|
+
partialSet: boolean
|
59
|
+
/** Default value to use instead of the default value from the table definition */
|
60
|
+
default: any
|
61
|
+
}
|
58
62
|
>,
|
59
63
|
>(
|
60
64
|
table: TTableDef,
|
61
65
|
id?: State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | SessionIdSymbol,
|
62
66
|
options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>,
|
63
|
-
):
|
67
|
+
): UseClientDocumentResult<TTableDef>
|
64
68
|
|
65
69
|
// case: no default id → id arg is required
|
66
70
|
<
|
@@ -68,20 +72,24 @@ export const useClientDocument: {
|
|
68
72
|
any,
|
69
73
|
any,
|
70
74
|
any,
|
71
|
-
{
|
75
|
+
{
|
76
|
+
partialSet: boolean
|
77
|
+
/** Default value to use instead of the default value from the table definition */
|
78
|
+
default: any
|
79
|
+
}
|
72
80
|
>,
|
73
81
|
>(
|
74
82
|
table: TTableDef,
|
75
83
|
// TODO adjust so it works with arbitrary primary keys or unique constraints
|
76
84
|
id: State.SQLite.ClientDocumentTableDef.DefaultIdType<TTableDef> | string | SessionIdSymbol,
|
77
85
|
options?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>,
|
78
|
-
):
|
86
|
+
): UseClientDocumentResult<TTableDef>
|
79
87
|
} = <TTableDef extends State.SQLite.ClientDocumentTableDef.Any>(
|
80
88
|
table: TTableDef,
|
81
89
|
idOrOptions?: string | SessionIdSymbol,
|
82
90
|
options_?: Partial<RowQuery.GetOrCreateOptions<TTableDef>>,
|
83
91
|
storeArg?: { store?: Store },
|
84
|
-
):
|
92
|
+
): UseClientDocumentResult<TTableDef> => {
|
85
93
|
const id =
|
86
94
|
typeof idOrOptions === 'string' || idOrOptions === SessionIdSymbol
|
87
95
|
? idOrOptions
|
@@ -97,8 +105,7 @@ export const useClientDocument: {
|
|
97
105
|
const tableName = table.sqliteDef.name
|
98
106
|
|
99
107
|
const store =
|
100
|
-
storeArg?.store ??
|
101
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
108
|
+
storeArg?.store ?? // biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
102
109
|
React.useContext(LiveStoreContext)?.store ??
|
103
110
|
shouldNeverHappen(`No store provided to useClientDocument`)
|
104
111
|
|
@@ -117,7 +124,7 @@ export const useClientDocument: {
|
|
117
124
|
|
118
125
|
const queryRef = useQueryRef(queryDef, {
|
119
126
|
otelSpanName: `LiveStore:useClientDocument:${tableName}:${idStr}`,
|
120
|
-
store: storeArg?.store,
|
127
|
+
...omitUndefineds({ store: storeArg?.store }),
|
121
128
|
})
|
122
129
|
|
123
130
|
const setState = React.useMemo<StateSetters<TTableDef>>(
|
@@ -134,10 +141,13 @@ export const useClientDocument: {
|
|
134
141
|
}
|
135
142
|
|
136
143
|
export type Dispatch<A> = (action: A) => void
|
137
|
-
export type
|
144
|
+
export type SetStateActionPartial<S> = Partial<S> | ((previousValue: S) => Partial<S>)
|
145
|
+
export type SetStateAction<S> = S | ((previousValue: S) => S)
|
138
146
|
|
139
147
|
export type StateSetters<TTableDef extends State.SQLite.ClientDocumentTableDef.TraitAny> = Dispatch<
|
140
|
-
|
148
|
+
TTableDef[State.SQLite.ClientDocumentTableDefSymbol]['options']['partialSet'] extends false
|
149
|
+
? SetStateAction<TTableDef['Value']>
|
150
|
+
: SetStateActionPartial<TTableDef['Value']>
|
141
151
|
>
|
142
152
|
|
143
153
|
const validateTableOptions = (table: State.SQLite.TableDef<any, any>) => {
|
package/src/useQuery.ts
CHANGED
@@ -42,8 +42,7 @@ export const useQueryRef = <TQuery extends LiveQueryDef.Any>(
|
|
42
42
|
queryRcRef: LiveQueries.RcRef<LiveQuery<LiveQueries.GetResult<TQuery>>>
|
43
43
|
} => {
|
44
44
|
const store =
|
45
|
-
options?.store ??
|
46
|
-
// biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
45
|
+
options?.store ?? // biome-ignore lint/correctness/useHookAtTopLevel: store is stable
|
47
46
|
React.useContext(LiveStoreContext)?.store ??
|
48
47
|
shouldNeverHappen(`No store provided to useQuery`)
|
49
48
|
|