@livestore/livestore 0.0.24 → 0.0.27
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/QueryCache.d.ts +3 -3
- package/dist/QueryCache.d.ts.map +1 -1
- package/dist/QueryCache.js +50 -60
- package/dist/QueryCache.js.map +1 -1
- package/dist/__tests__/react/fixture.d.ts +22 -7
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +14 -15
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/__tests__/react/useQuery.test.js +37 -12
- package/dist/__tests__/react/useQuery.test.js.map +1 -1
- package/dist/__tests__/react/useRow.test.d.ts +2 -0
- package/dist/__tests__/react/useRow.test.d.ts.map +1 -0
- package/dist/__tests__/react/useRow.test.js +131 -0
- package/dist/__tests__/react/useRow.test.js.map +1 -0
- package/dist/__tests__/react/utils/stack-info.test.js +32 -0
- package/dist/__tests__/react/utils/stack-info.test.js.map +1 -1
- package/dist/__tests__/reactive.test.js +51 -0
- package/dist/__tests__/reactive.test.js.map +1 -1
- package/dist/__tests__/reactiveQueries/sql.test.js +6 -13
- package/dist/__tests__/reactiveQueries/sql.test.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +3 -3
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +2 -2
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/global-state.d.ts +19 -0
- package/dist/global-state.d.ts.map +1 -0
- package/dist/global-state.js +20 -0
- package/dist/global-state.js.map +1 -0
- package/dist/inMemoryDatabase.d.ts +6 -6
- package/dist/inMemoryDatabase.d.ts.map +1 -1
- package/dist/inMemoryDatabase.js +16 -10
- package/dist/inMemoryDatabase.js.map +1 -1
- package/dist/index.d.ts +9 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -8
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts +4 -4
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +34 -28
- package/dist/migrations.js.map +1 -1
- package/dist/react/LiveStoreContext.js.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +2 -2
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/index.d.ts +1 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/useQuery.d.ts +3 -0
- package/dist/react/useQuery.d.ts.map +1 -1
- package/dist/react/useQuery.js +7 -6
- package/dist/react/useQuery.js.map +1 -1
- package/dist/react/useRow.d.ts +33 -0
- package/dist/react/useRow.d.ts.map +1 -0
- package/dist/react/useRow.js +136 -0
- package/dist/react/useRow.js.map +1 -0
- package/dist/react/useTemporaryQuery.d.ts +2 -0
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/react/useTemporaryQuery.js +28 -11
- package/dist/react/useTemporaryQuery.js.map +1 -1
- package/dist/react/utils/stack-info.d.ts.map +1 -1
- package/dist/react/utils/stack-info.js +3 -3
- package/dist/react/utils/stack-info.js.map +1 -1
- package/dist/react/utils/useStateRefWithReactiveInput.js.map +1 -1
- package/dist/reactive.d.ts +38 -29
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +73 -45
- package/dist/reactive.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +10 -6
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +11 -12
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +2 -2
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +56 -50
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +7 -3
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js +25 -15
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +5 -5
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +39 -34
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/row-query.d.ts +21 -0
- package/dist/row-query.d.ts.map +1 -0
- package/dist/row-query.js +77 -0
- package/dist/row-query.js.map +1 -0
- package/dist/schema/action.d.ts +30 -0
- package/dist/schema/action.d.ts.map +1 -0
- package/dist/schema/action.js +3 -0
- package/dist/schema/action.js.map +1 -0
- package/dist/schema/index.d.ts +28 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +26 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/system-tables.d.ts +24 -0
- package/dist/schema/system-tables.d.ts.map +1 -0
- package/dist/schema/system-tables.js +11 -0
- package/dist/schema/system-tables.js.map +1 -0
- package/dist/schema/table-def.d.ts +161 -0
- package/dist/schema/table-def.d.ts.map +1 -0
- package/dist/schema/table-def.js +53 -0
- package/dist/schema/table-def.js.map +1 -0
- package/dist/storage/in-memory/index.d.ts +1 -1
- package/dist/storage/in-memory/index.d.ts.map +1 -1
- package/dist/storage/in-memory/index.js +6 -7
- package/dist/storage/in-memory/index.js.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/tauri/index.d.ts +1 -1
- package/dist/storage/tauri/index.d.ts.map +1 -1
- package/dist/storage/tauri/index.js +25 -23
- package/dist/storage/tauri/index.js.map +1 -1
- package/dist/storage/utils/idb.js +3 -1
- package/dist/storage/utils/idb.js.map +1 -1
- package/dist/storage/web-worker/index.d.ts +1 -1
- package/dist/storage/web-worker/index.d.ts.map +1 -1
- package/dist/storage/web-worker/index.js +38 -34
- package/dist/storage/web-worker/index.js.map +1 -1
- package/dist/storage/web-worker/worker.d.ts +1 -1
- package/dist/storage/web-worker/worker.d.ts.map +1 -1
- package/dist/storage/web-worker/worker.js +1 -1
- package/dist/storage/web-worker/worker.js.map +1 -1
- package/dist/store.d.ts +11 -21
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +284 -272
- package/dist/store.js.map +1 -1
- package/dist/utils/bounded-collections.d.ts.map +1 -0
- package/dist/utils/bounded-collections.js +90 -0
- package/dist/utils/bounded-collections.js.map +1 -0
- package/dist/utils/otel.d.ts.map +1 -0
- package/dist/{otel.js → utils/otel.js} +1 -1
- package/dist/utils/otel.js.map +1 -0
- package/dist/utils/util.d.ts.map +1 -0
- package/dist/utils/util.js.map +1 -0
- package/package.json +21 -18
- package/src/QueryCache.ts +4 -4
- package/src/__tests__/react/fixture.tsx +17 -17
- package/src/__tests__/react/useQuery.test.tsx +56 -14
- package/src/__tests__/react/useRow.test.tsx +205 -0
- package/src/__tests__/react/utils/stack-info.test.ts +34 -0
- package/src/__tests__/reactive.test.ts +71 -0
- package/src/__tests__/reactiveQueries/sql.test.ts +6 -13
- package/src/effect/LiveStore.ts +7 -7
- package/src/global-state.ts +26 -0
- package/src/inMemoryDatabase.ts +14 -12
- package/src/index.ts +22 -29
- package/src/migrations.ts +41 -35
- package/src/react/LiveStoreProvider.tsx +2 -2
- package/src/react/index.ts +7 -9
- package/src/react/useQuery.ts +12 -6
- package/src/react/useRow.ts +221 -0
- package/src/react/useTemporaryQuery.ts +43 -11
- package/src/react/utils/stack-info.ts +4 -3
- package/src/reactive.ts +81 -65
- package/src/reactiveQueries/base-class.ts +14 -10
- package/src/reactiveQueries/graphql.ts +4 -3
- package/src/reactiveQueries/js.ts +9 -5
- package/src/reactiveQueries/sql.ts +9 -9
- package/src/row-query.ts +142 -0
- package/src/schema/action.ts +41 -0
- package/src/schema/index.ts +63 -0
- package/src/schema/system-tables.ts +21 -0
- package/src/schema/table-def.ts +199 -0
- package/src/storage/in-memory/index.ts +1 -1
- package/src/storage/index.ts +2 -1
- package/src/storage/tauri/index.ts +2 -2
- package/src/storage/web-worker/index.ts +1 -1
- package/src/storage/web-worker/worker.ts +2 -2
- package/src/store.ts +51 -51
- package/dist/__tests__/react/useComponentState.test.d.ts +0 -2
- package/dist/__tests__/react/useComponentState.test.d.ts.map +0 -1
- package/dist/__tests__/react/useComponentState.test.js +0 -68
- package/dist/__tests__/react/useComponentState.test.js.map +0 -1
- package/dist/__tests__/react/useLQuery.test.d.ts +0 -2
- package/dist/__tests__/react/useLQuery.test.d.ts.map +0 -1
- package/dist/__tests__/react/useLQuery.test.js +0 -38
- package/dist/__tests__/react/useLQuery.test.js.map +0 -1
- package/dist/__tests__/react/useLiveStoreComponent.test.d.ts +0 -2
- package/dist/__tests__/react/useLiveStoreComponent.test.d.ts.map +0 -1
- package/dist/__tests__/react/useLiveStoreComponent.test.js +0 -73
- package/dist/__tests__/react/useLiveStoreComponent.test.js.map +0 -1
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.d.ts +0 -2
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.d.ts.map +0 -1
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.js +0 -38
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.js.map +0 -1
- package/dist/bounded-collections.d.ts.map +0 -1
- package/dist/bounded-collections.js +0 -103
- package/dist/bounded-collections.js.map +0 -1
- package/dist/componentKey.d.ts +0 -20
- package/dist/componentKey.d.ts.map +0 -1
- package/dist/componentKey.js +0 -3
- package/dist/componentKey.js.map +0 -1
- package/dist/otel.d.ts.map +0 -1
- package/dist/otel.js.map +0 -1
- package/dist/react/useComponentState.d.ts +0 -50
- package/dist/react/useComponentState.d.ts.map +0 -1
- package/dist/react/useComponentState.js +0 -240
- package/dist/react/useComponentState.js.map +0 -1
- package/dist/react/useGlobalQuery.d.ts +0 -3
- package/dist/react/useGlobalQuery.d.ts.map +0 -1
- package/dist/react/useGlobalQuery.js +0 -26
- package/dist/react/useGlobalQuery.js.map +0 -1
- package/dist/react/useGraphQL.d.ts +0 -13
- package/dist/react/useGraphQL.d.ts.map +0 -1
- package/dist/react/useGraphQL.js +0 -87
- package/dist/react/useGraphQL.js.map +0 -1
- package/dist/react/useLiveStoreComponent.d.ts +0 -75
- package/dist/react/useLiveStoreComponent.d.ts.map +0 -1
- package/dist/react/useLiveStoreComponent.js +0 -361
- package/dist/react/useLiveStoreComponent.js.map +0 -1
- package/dist/react/utils/extractNamesFromStackTrace.d.ts +0 -3
- package/dist/react/utils/extractNamesFromStackTrace.d.ts.map +0 -1
- package/dist/react/utils/extractNamesFromStackTrace.js +0 -40
- package/dist/react/utils/extractNamesFromStackTrace.js.map +0 -1
- package/dist/react/utils/extractStackInfoFromStackTrace.d.ts +0 -7
- package/dist/react/utils/extractStackInfoFromStackTrace.d.ts.map +0 -1
- package/dist/react/utils/extractStackInfoFromStackTrace.js +0 -40
- package/dist/react/utils/extractStackInfoFromStackTrace.js.map +0 -1
- package/dist/reactiveQueries/graph.d.ts +0 -10
- package/dist/reactiveQueries/graph.d.ts.map +0 -1
- package/dist/reactiveQueries/graph.js +0 -6
- package/dist/reactiveQueries/graph.js.map +0 -1
- package/dist/schema.d.ts +0 -81
- package/dist/schema.d.ts.map +0 -1
- package/dist/schema.js +0 -46
- package/dist/schema.js.map +0 -1
- package/dist/util.d.ts.map +0 -1
- package/dist/util.js.map +0 -1
- package/src/__tests__/react/useComponentState.test.tsx +0 -100
- package/src/componentKey.ts +0 -9
- package/src/react/useComponentState.ts +0 -404
- package/src/reactiveQueries/graph.ts +0 -15
- package/src/schema.ts +0 -143
- /package/dist/{bounded-collections.d.ts → utils/bounded-collections.d.ts} +0 -0
- /package/dist/{otel.d.ts → utils/otel.d.ts} +0 -0
- /package/dist/{util.d.ts → utils/util.d.ts} +0 -0
- /package/dist/{util.js → utils/util.js} +0 -0
- /package/src/{bounded-collections.ts → utils/bounded-collections.ts} +0 -0
- /package/src/{otel.ts → utils/otel.ts} +0 -0
- /package/src/{util.ts → utils/util.ts} +0 -0
|
@@ -159,6 +159,77 @@ describe('a trivial graph', () => {
|
|
|
159
159
|
graph.setRef(a, 2)
|
|
160
160
|
// expect(numberOfCallsToC).toBe(2) // TODO comp caching
|
|
161
161
|
})
|
|
162
|
+
|
|
163
|
+
describe('skip refresh', () => {
|
|
164
|
+
it(`defers effect execution until manual run`, () => {
|
|
165
|
+
const { graph, a, c, d, numberOfRunsForC } = makeGraph()
|
|
166
|
+
|
|
167
|
+
// using here both to track number oe effect runs and to "update the effect behavior"
|
|
168
|
+
let numberOfEffectRuns = 0
|
|
169
|
+
const effect = graph.makeEffect((get) => {
|
|
170
|
+
expect(get(c)).toBe(numberOfEffectRuns === 0 ? 3 : 4)
|
|
171
|
+
numberOfEffectRuns++
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
effect.doEffect()
|
|
175
|
+
|
|
176
|
+
expect(numberOfEffectRuns).toBe(1)
|
|
177
|
+
expect(numberOfRunsForC.runs).toBe(1)
|
|
178
|
+
|
|
179
|
+
graph.setRef(a, 2, { skipRefresh: true })
|
|
180
|
+
|
|
181
|
+
expect(numberOfEffectRuns).toBe(1)
|
|
182
|
+
expect(numberOfRunsForC.runs).toBe(1)
|
|
183
|
+
|
|
184
|
+
// Even setting a unrelated ref should not trigger a refresh
|
|
185
|
+
graph.setRef(d, 0)
|
|
186
|
+
|
|
187
|
+
expect(numberOfEffectRuns).toBe(1)
|
|
188
|
+
expect(numberOfRunsForC.runs).toBe(1)
|
|
189
|
+
|
|
190
|
+
graph.runDeferredEffects()
|
|
191
|
+
|
|
192
|
+
expect(numberOfEffectRuns).toBe(2)
|
|
193
|
+
expect(numberOfRunsForC.runs).toBe(2)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it(`doesn't run deferred effects which have been destroyed already`, () => {
|
|
197
|
+
const { graph, a, c, numberOfRunsForC } = makeGraph()
|
|
198
|
+
|
|
199
|
+
let numberOfEffect1Runs = 0
|
|
200
|
+
const effect1 = graph.makeEffect((get) => {
|
|
201
|
+
expect(get(c)).toBe(numberOfEffect1Runs === 0 ? 3 : 4)
|
|
202
|
+
numberOfEffect1Runs++
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
let numberOfEffect2Runs = 0
|
|
206
|
+
const effect2 = graph.makeEffect((get) => {
|
|
207
|
+
expect(get(c)).toBe(numberOfEffect2Runs === 0 ? 3 : 4)
|
|
208
|
+
numberOfEffect2Runs++
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
effect1.doEffect()
|
|
212
|
+
effect2.doEffect()
|
|
213
|
+
|
|
214
|
+
expect(numberOfEffect1Runs).toBe(1)
|
|
215
|
+
expect(numberOfEffect2Runs).toBe(1)
|
|
216
|
+
expect(numberOfRunsForC.runs).toBe(1)
|
|
217
|
+
|
|
218
|
+
graph.setRef(a, 2, { skipRefresh: true })
|
|
219
|
+
|
|
220
|
+
expect(numberOfEffect1Runs).toBe(1)
|
|
221
|
+
expect(numberOfEffect2Runs).toBe(1)
|
|
222
|
+
expect(numberOfRunsForC.runs).toBe(1)
|
|
223
|
+
|
|
224
|
+
graph.destroy(effect1)
|
|
225
|
+
|
|
226
|
+
graph.runDeferredEffects()
|
|
227
|
+
|
|
228
|
+
expect(numberOfEffect1Runs).toBe(1)
|
|
229
|
+
expect(numberOfEffect2Runs).toBe(2)
|
|
230
|
+
expect(numberOfRunsForC.runs).toBe(2)
|
|
231
|
+
})
|
|
232
|
+
})
|
|
162
233
|
})
|
|
163
234
|
})
|
|
164
235
|
|
|
@@ -30,12 +30,11 @@ describe('otel', () => {
|
|
|
30
30
|
it('otel', async () => {
|
|
31
31
|
const { store, exporter, span } = await makeQuery()
|
|
32
32
|
|
|
33
|
-
const query = querySQL(`select * from todos`, { queriedTables: ['todos'] })
|
|
33
|
+
const query = querySQL(`select * from todos`, { queriedTables: new Set(['todos']) })
|
|
34
34
|
expect(query.run()).toMatchInlineSnapshot('[]')
|
|
35
35
|
|
|
36
|
-
store.applyEvent('RawSql', {
|
|
36
|
+
store.applyEvent('livestore.RawSql', {
|
|
37
37
|
sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);`,
|
|
38
|
-
bindValues: {},
|
|
39
38
|
writeTables: ['todos'],
|
|
40
39
|
})
|
|
41
40
|
|
|
@@ -93,10 +92,9 @@ describe('otel', () => {
|
|
|
93
92
|
{
|
|
94
93
|
"_name": "LiveStore:applyEventWithoutRefresh",
|
|
95
94
|
"attributes": {
|
|
96
|
-
"livestore.actionType": "RawSql",
|
|
95
|
+
"livestore.actionType": "livestore.RawSql",
|
|
97
96
|
"livestore.args": "{
|
|
98
97
|
\\"sql\\": \\"INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);\\",
|
|
99
|
-
\\"bindValues\\": {},
|
|
100
98
|
\\"writeTables\\": [
|
|
101
99
|
\\"todos\\"
|
|
102
100
|
]
|
|
@@ -165,10 +163,7 @@ describe('otel', () => {
|
|
|
165
163
|
const defaultTodo = { id: '', text: '', completed: 0 }
|
|
166
164
|
|
|
167
165
|
const filter = queryJS(() => `where completed = 0`, { label: 'where-filter' })
|
|
168
|
-
const query = querySQL((get) => `select * from todos ${get(filter)}`, {
|
|
169
|
-
// queriedTables: ['todos'],
|
|
170
|
-
label: 'all todos',
|
|
171
|
-
}).getFirstRow({
|
|
166
|
+
const query = querySQL((get) => `select * from todos ${get(filter)}`, { label: 'all todos' }).getFirstRow({
|
|
172
167
|
defaultValue: defaultTodo,
|
|
173
168
|
})
|
|
174
169
|
|
|
@@ -180,9 +175,8 @@ describe('otel', () => {
|
|
|
180
175
|
}
|
|
181
176
|
`)
|
|
182
177
|
|
|
183
|
-
store.applyEvent('RawSql', {
|
|
178
|
+
store.applyEvent('livestore.RawSql', {
|
|
184
179
|
sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);`,
|
|
185
|
-
bindValues: {},
|
|
186
180
|
writeTables: ['todos'],
|
|
187
181
|
})
|
|
188
182
|
|
|
@@ -238,10 +232,9 @@ describe('otel', () => {
|
|
|
238
232
|
{
|
|
239
233
|
"_name": "LiveStore:applyEventWithoutRefresh",
|
|
240
234
|
"attributes": {
|
|
241
|
-
"livestore.actionType": "RawSql",
|
|
235
|
+
"livestore.actionType": "livestore.RawSql",
|
|
242
236
|
"livestore.args": "{
|
|
243
237
|
\\"sql\\": \\"INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);\\",
|
|
244
|
-
\\"bindValues\\": {},
|
|
245
238
|
\\"writeTables\\": [
|
|
246
239
|
\\"todos\\"
|
|
247
240
|
]
|
package/src/effect/LiveStore.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { GraphQLSchema } from 'graphql'
|
|
|
5
5
|
import initSqlite3Wasm from 'sqlite-esm'
|
|
6
6
|
|
|
7
7
|
import type { InMemoryDatabase } from '../inMemoryDatabase.js'
|
|
8
|
-
import type {
|
|
8
|
+
import type { LiveStoreSchema } from '../schema/index.js'
|
|
9
9
|
import type { StorageInit } from '../storage/index.js'
|
|
10
10
|
import type { BaseGraphQLContext, GraphQLOptions, LiveStoreQuery, Store } from '../store.js'
|
|
11
11
|
import { createStore } from '../store.js'
|
|
@@ -25,7 +25,7 @@ export type LiveStoreContext = {
|
|
|
25
25
|
export type QueryDefinition = (store: Store) => LiveStoreQuery
|
|
26
26
|
|
|
27
27
|
export type LiveStoreCreateStoreOptions<GraphQLContext extends BaseGraphQLContext> = {
|
|
28
|
-
schema:
|
|
28
|
+
schema: LiveStoreSchema
|
|
29
29
|
loadStorage: () => StorageInit | Promise<StorageInit>
|
|
30
30
|
graphQLOptions?: GraphQLOptions<GraphQLContext>
|
|
31
31
|
otelTracer?: otel.Tracer
|
|
@@ -43,7 +43,7 @@ export const DeferredStoreContext = Context.Tag<DeferredStoreContext>(
|
|
|
43
43
|
// export const DeferredStoreContext = Effect.cached(Effect.flatMap(StoreContext, (_) => Effect.succeed(_)))
|
|
44
44
|
|
|
45
45
|
export type LiveStoreContextProps<GraphQLContext extends BaseGraphQLContext> = {
|
|
46
|
-
schema:
|
|
46
|
+
schema: LiveStoreSchema
|
|
47
47
|
loadStorage: () => StorageInit | Promise<StorageInit>
|
|
48
48
|
graphQLOptions?: {
|
|
49
49
|
schema: Effect.Effect<otel.Tracer, never, GraphQLSchema>
|
|
@@ -55,9 +55,9 @@ export type LiveStoreContextProps<GraphQLContext extends BaseGraphQLContext> = {
|
|
|
55
55
|
export const LiveStoreContextLayer = <GraphQLContext extends BaseGraphQLContext>(
|
|
56
56
|
props: LiveStoreContextProps<GraphQLContext>,
|
|
57
57
|
): Layer.Layer<otel.Tracer, never, LiveStoreContext> =>
|
|
58
|
-
Layer.
|
|
59
|
-
|
|
60
|
-
Layer.
|
|
58
|
+
Layer.scoped(LiveStoreContext, makeLiveStoreContext(props)).pipe(
|
|
59
|
+
Layer.withSpan('LiveStore'),
|
|
60
|
+
Layer.provide(LiveStoreContextDeferred),
|
|
61
61
|
)
|
|
62
62
|
|
|
63
63
|
export const LiveStoreContextDeferred = Layer.effect(DeferredStoreContext, Deferred.make<never, LiveStoreContext>())
|
|
@@ -78,7 +78,7 @@ export const makeLiveStoreContext = <GraphQLContext extends BaseGraphQLContext>(
|
|
|
78
78
|
|
|
79
79
|
const otelRootSpanContext = otel.context.active()
|
|
80
80
|
|
|
81
|
-
const otelTracer = yield* $(OtelTracer.
|
|
81
|
+
const otelTracer = yield* $(OtelTracer.Tracer)
|
|
82
82
|
|
|
83
83
|
const graphQLOptions = yield* $(
|
|
84
84
|
graphQLOptions_
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* LiveStore currently relies on some global state in order to simplify the end-user API.
|
|
4
|
+
* This however also has the downside that LiveStore can't be used in multiple instances in the same app.
|
|
5
|
+
* It could possibly also lead to some other problems.
|
|
6
|
+
*
|
|
7
|
+
* We should find some better way to do this and ideally remove this global state.
|
|
8
|
+
*
|
|
9
|
+
* Another approach could be to use the global state by default but provide an additional way to let the user
|
|
10
|
+
* explicitly pass instances of state below into the LiveStore constructors.
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import ReactDOM from 'react-dom'
|
|
15
|
+
|
|
16
|
+
import { ReactiveGraph } from './reactive.js'
|
|
17
|
+
import type { DbContext } from './reactiveQueries/base-class.js'
|
|
18
|
+
import type { TableDef } from './schema/table-def.js'
|
|
19
|
+
import type { QueryDebugInfo, RefreshReason } from './store.js'
|
|
20
|
+
|
|
21
|
+
export const dbGraph = new ReactiveGraph<RefreshReason, QueryDebugInfo, DbContext>({
|
|
22
|
+
// TODO also find a better way to only use this effects wrapper when used in a React app
|
|
23
|
+
effectsWrapper: (run) => ReactDOM.unstable_batchedUpdates(() => run()),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export const dynamicallyRegisteredTables: Map<string, TableDef> = new Map()
|
package/src/inMemoryDatabase.ts
CHANGED
|
@@ -4,12 +4,12 @@ import { shouldNeverHappen } from '@livestore/utils'
|
|
|
4
4
|
import type * as otel from '@opentelemetry/api'
|
|
5
5
|
import type * as Sqlite from 'sqlite-esm'
|
|
6
6
|
|
|
7
|
-
import BoundMap, { BoundArray } from './bounded-collections.js'
|
|
8
7
|
// import { EVENTS_TABLE_NAME } from './events.js'
|
|
9
8
|
import { sql } from './index.js'
|
|
10
|
-
import { getDurationMsFromSpan, getStartTimeHighResFromSpan } from './otel.js'
|
|
11
9
|
import QueryCache from './QueryCache.js'
|
|
12
|
-
import
|
|
10
|
+
import BoundMap, { BoundArray } from './utils/bounded-collections.js'
|
|
11
|
+
import { getDurationMsFromSpan, getStartTimeHighResFromSpan } from './utils/otel.js'
|
|
12
|
+
import type { Bindable, PreparedBindValues } from './utils/util.js'
|
|
13
13
|
|
|
14
14
|
type DatabaseWithCAPI = Sqlite.Database & { capi: Sqlite.CAPI }
|
|
15
15
|
|
|
@@ -25,7 +25,7 @@ export type SlowQueryInfo = [
|
|
|
25
25
|
bindValues: PreparedBindValues | undefined,
|
|
26
26
|
durationMs: number,
|
|
27
27
|
rowsCount: number | undefined,
|
|
28
|
-
queriedTables:
|
|
28
|
+
queriedTables: Set<string>,
|
|
29
29
|
startTimePerfNow: DOMHighResTimeStamp,
|
|
30
30
|
]
|
|
31
31
|
|
|
@@ -39,7 +39,7 @@ export const emptyDebugInfo = (): DebugInfo => ({
|
|
|
39
39
|
export class InMemoryDatabase {
|
|
40
40
|
// TODO: how many unique active statements are expected?
|
|
41
41
|
private cachedStmts = new BoundMap<string, Sqlite.PreparedStatement>(200)
|
|
42
|
-
private tablesUsedCache = new BoundMap<string, string
|
|
42
|
+
private tablesUsedCache = new BoundMap<string, Set<string>>(200)
|
|
43
43
|
private resultCache = new QueryCache()
|
|
44
44
|
private tablesUsedStmt
|
|
45
45
|
public debugInfo: DebugInfo = emptyDebugInfo()
|
|
@@ -119,25 +119,27 @@ export class InMemoryDatabase {
|
|
|
119
119
|
return cached
|
|
120
120
|
}
|
|
121
121
|
const stmt = this.tablesUsedStmt
|
|
122
|
-
const tablesUsed =
|
|
122
|
+
const tablesUsed = new Set<string>()
|
|
123
123
|
try {
|
|
124
124
|
stmt.bind([query])
|
|
125
125
|
while (stmt.step()) {
|
|
126
|
-
tablesUsed.
|
|
126
|
+
tablesUsed.add(stmt.get(0))
|
|
127
127
|
}
|
|
128
128
|
} finally {
|
|
129
129
|
stmt.reset()
|
|
130
130
|
}
|
|
131
|
-
this.tablesUsedCache.set(query, tablesUsed
|
|
132
|
-
return tablesUsed
|
|
131
|
+
this.tablesUsedCache.set(query, tablesUsed)
|
|
132
|
+
return tablesUsed
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
execute(
|
|
136
136
|
query: string,
|
|
137
137
|
bindValues?: PreparedBindValues,
|
|
138
|
-
writeTables?: string
|
|
138
|
+
writeTables?: ReadonlyArray<string>,
|
|
139
139
|
options?: { hasNoEffects?: boolean; otelContext?: otel.Context },
|
|
140
140
|
): { durationMs: number } {
|
|
141
|
+
// console.debug('in-memory-db:execute', query, bindValues)
|
|
142
|
+
|
|
141
143
|
return this.otelTracer.startActiveSpan(
|
|
142
144
|
'livestore.in-memory-db:execute',
|
|
143
145
|
// TODO truncate query string
|
|
@@ -192,7 +194,7 @@ export class InMemoryDatabase {
|
|
|
192
194
|
bindValues,
|
|
193
195
|
durationMs,
|
|
194
196
|
undefined,
|
|
195
|
-
|
|
197
|
+
new Set(),
|
|
196
198
|
getStartTimeHighResFromSpan(span),
|
|
197
199
|
])
|
|
198
200
|
}
|
|
@@ -205,7 +207,7 @@ export class InMemoryDatabase {
|
|
|
205
207
|
select<T = any>(
|
|
206
208
|
query: string,
|
|
207
209
|
options?: {
|
|
208
|
-
queriedTables?:
|
|
210
|
+
queriedTables?: Set<string>
|
|
209
211
|
bindValues?: PreparedBindValues
|
|
210
212
|
skipCache?: boolean
|
|
211
213
|
otelContext?: otel.Context
|
package/src/index.ts
CHANGED
|
@@ -3,41 +3,34 @@ export type { LiveStoreQuery, BaseGraphQLContext, QueryResult, QueryDebugInfo, R
|
|
|
3
3
|
|
|
4
4
|
export type { QueryDefinition, LiveStoreCreateStoreOptions, LiveStoreContext } from './effect/LiveStore.js'
|
|
5
5
|
|
|
6
|
-
export {
|
|
7
|
-
defineComponentStateSchema,
|
|
8
|
-
defineAction,
|
|
9
|
-
defineActions,
|
|
10
|
-
defineTables,
|
|
11
|
-
defineMaterializedViews,
|
|
12
|
-
makeSchema,
|
|
13
|
-
} from './schema.js'
|
|
14
6
|
export { InMemoryDatabase, type DebugInfo, emptyDebugInfo } from './inMemoryDatabase.js'
|
|
7
|
+
|
|
15
8
|
export type { Storage, StorageType, StorageInit } from './storage/index.js'
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
SerializedAtom,
|
|
22
|
-
SerializedEffect,
|
|
23
|
-
Atom,
|
|
24
|
-
} from './reactive.js'
|
|
25
|
-
export { type LiveStoreJSQuery, queryJS } from './reactiveQueries/js.js'
|
|
26
|
-
export { type LiveStoreSQLQuery, querySQL } from './reactiveQueries/sql.js'
|
|
27
|
-
export { type LiveStoreGraphQLQuery, queryGraphQL } from './reactiveQueries/graphql.js'
|
|
9
|
+
|
|
10
|
+
export type { GetAtom, AtomDebugInfo, RefreshDebugInfo, SerializedAtom, Atom } from './reactive.js'
|
|
11
|
+
export { LiveStoreJSQuery, queryJS } from './reactiveQueries/js.js'
|
|
12
|
+
export { LiveStoreSQLQuery, querySQL } from './reactiveQueries/sql.js'
|
|
13
|
+
export { LiveStoreGraphQLQuery, queryGraphQL } from './reactiveQueries/graphql.js'
|
|
28
14
|
export { type GetAtomResult } from './reactiveQueries/base-class.js'
|
|
29
|
-
export { dbGraph } from './reactiveQueries/graph.js'
|
|
30
15
|
|
|
31
|
-
export {
|
|
32
|
-
export type { ComponentKey } from './componentKey.js'
|
|
33
|
-
export type { Schema, GetActionArgs, GetApplyEventArgs, Index, ActionDefinition, ActionDefinitions } from './schema.js'
|
|
16
|
+
export { dbGraph } from './global-state.js'
|
|
34
17
|
|
|
35
|
-
export {
|
|
18
|
+
export { type RowResult, type RowResultEncoded, type RowQueryArgs, rowQuery } from './row-query.js'
|
|
36
19
|
|
|
37
|
-
|
|
38
|
-
export type TableDefinition = SqliteAst.Table
|
|
20
|
+
export { defineAction, defineActions, makeSchema, DbSchema } from './schema/index.js'
|
|
39
21
|
|
|
40
|
-
export {
|
|
22
|
+
export type {
|
|
23
|
+
LiveStoreSchema,
|
|
24
|
+
InputSchema,
|
|
25
|
+
GetActionArgs,
|
|
26
|
+
GetApplyEventArgs,
|
|
27
|
+
ActionDefinition,
|
|
28
|
+
ActionDefinitions,
|
|
29
|
+
SQLWriteStatement,
|
|
30
|
+
SchemaMetaRow,
|
|
31
|
+
} from './schema/index.js'
|
|
32
|
+
|
|
33
|
+
export { SqliteAst, SqliteDsl } from 'effect-db-schema'
|
|
41
34
|
|
|
42
|
-
export { prepareBindValues, sql, type Bindable, type PreparedBindValues } from './util.js'
|
|
35
|
+
export { prepareBindValues, sql, type Bindable, type PreparedBindValues } from './utils/util.js'
|
|
43
36
|
export { isEqual } from 'lodash-es'
|
package/src/migrations.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { Schema as EffectSchema } from '@livestore/utils/effect'
|
|
1
2
|
import type * as otel from '@opentelemetry/api'
|
|
2
3
|
import { SqliteAst } from 'effect-db-schema'
|
|
3
|
-
import { memoize
|
|
4
|
+
import { memoize } from 'lodash-es'
|
|
4
5
|
|
|
6
|
+
import { dynamicallyRegisteredTables } from './global-state.js'
|
|
5
7
|
import type { InMemoryDatabase } from './index.js'
|
|
6
|
-
import type {
|
|
7
|
-
import {
|
|
8
|
-
import type { PreparedBindValues } from './util.js'
|
|
9
|
-
import { sql } from './util.js'
|
|
8
|
+
import type { LiveStoreSchema, SchemaMetaRow } from './schema/index.js'
|
|
9
|
+
import { SCHEMA_META_TABLE, systemTables } from './schema/index.js'
|
|
10
|
+
import type { PreparedBindValues } from './utils/util.js'
|
|
11
|
+
import { sql } from './utils/util.js'
|
|
10
12
|
|
|
11
13
|
const getMemoizedTimestamp = memoize(() => new Date().toISOString())
|
|
12
14
|
|
|
@@ -18,7 +20,7 @@ export const migrateDb = ({
|
|
|
18
20
|
}: {
|
|
19
21
|
db: InMemoryDatabase
|
|
20
22
|
otelContext: otel.Context
|
|
21
|
-
schema:
|
|
23
|
+
schema: LiveStoreSchema
|
|
22
24
|
}) => {
|
|
23
25
|
db.execute(
|
|
24
26
|
// TODO use schema migration definition from schema.ts instead
|
|
@@ -34,16 +36,18 @@ export const migrateDb = ({
|
|
|
34
36
|
schemaMetaRows.map(({ tableName, schemaHash }) => [tableName, schemaHash]),
|
|
35
37
|
)
|
|
36
38
|
|
|
37
|
-
const tableDefs =
|
|
39
|
+
const tableDefs = new Set([
|
|
38
40
|
// NOTE it's important the `SCHEMA_META_TABLE` comes first since we're writing to it below
|
|
39
|
-
|
|
40
|
-
...
|
|
41
|
-
...
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
for (const
|
|
41
|
+
...systemTables,
|
|
42
|
+
...Array.from(schema.tables.values()).filter((_) => _.schema.name !== SCHEMA_META_TABLE),
|
|
43
|
+
...dynamicallyRegisteredTables.values(),
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
for (const tableDef of tableDefs) {
|
|
47
|
+
const tableAst = tableDef.schema.ast
|
|
48
|
+
const tableName = tableAst.name
|
|
45
49
|
const dbSchemaHash = dbSchemaHashByTable[tableName]
|
|
46
|
-
const schemaHash = SqliteAst.hash(
|
|
50
|
+
const schemaHash = SqliteAst.hash(tableAst)
|
|
47
51
|
if (schemaHash !== dbSchemaHash) {
|
|
48
52
|
if (import.meta.env.VITE_LIVESTORE_SKIP_MIGRATIONS) {
|
|
49
53
|
console.log(
|
|
@@ -54,7 +58,7 @@ export const migrateDb = ({
|
|
|
54
58
|
`Schema hash mismatch for table '${tableName}' (DB: ${dbSchemaHash}, expected: ${schemaHash}), migrating table...`,
|
|
55
59
|
)
|
|
56
60
|
|
|
57
|
-
migrateTable({ db,
|
|
61
|
+
migrateTable({ db, tableAst, otelContext, schemaHash })
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
}
|
|
@@ -62,24 +66,24 @@ export const migrateDb = ({
|
|
|
62
66
|
|
|
63
67
|
export const migrateTable = ({
|
|
64
68
|
db,
|
|
65
|
-
|
|
69
|
+
tableAst,
|
|
66
70
|
otelContext,
|
|
67
71
|
schemaHash,
|
|
68
72
|
}: {
|
|
69
73
|
db: InMemoryDatabase
|
|
70
|
-
|
|
74
|
+
tableAst: SqliteAst.Table
|
|
71
75
|
otelContext: otel.Context
|
|
72
76
|
schemaHash: number
|
|
73
77
|
}) => {
|
|
74
|
-
console.log(`Migrating table '${
|
|
75
|
-
const tableName =
|
|
76
|
-
const columnSpec = makeColumnSpec(
|
|
78
|
+
console.log(`Migrating table '${tableAst.name}'...`)
|
|
79
|
+
const tableName = tableAst.name
|
|
80
|
+
const columnSpec = makeColumnSpec(tableAst)
|
|
77
81
|
|
|
78
82
|
// TODO need to possibly handle cascading deletes due to foreign keys
|
|
79
83
|
db.execute(sql`drop table if exists ${tableName}`, undefined, [], { otelContext })
|
|
80
84
|
db.execute(sql`create table if not exists ${tableName} (${columnSpec});`, undefined, [], { otelContext })
|
|
81
85
|
|
|
82
|
-
for (const index of
|
|
86
|
+
for (const index of tableAst.indexes) {
|
|
83
87
|
db.execute(createIndexFromDefinition(tableName, index), undefined, [], { otelContext })
|
|
84
88
|
}
|
|
85
89
|
|
|
@@ -100,9 +104,9 @@ const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) =>
|
|
|
100
104
|
return sql`create ${uniqueStr} index ${index.name} on ${tableName} (${index.columns.join(', ')})`
|
|
101
105
|
}
|
|
102
106
|
|
|
103
|
-
const makeColumnSpec = (
|
|
104
|
-
const primaryKeys =
|
|
105
|
-
const columnDefStrs =
|
|
107
|
+
const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
|
108
|
+
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
|
|
109
|
+
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
|
|
106
110
|
if (primaryKeys.length > 0) {
|
|
107
111
|
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
|
|
108
112
|
}
|
|
@@ -110,16 +114,18 @@ const makeColumnSpec = (tableDef: SqliteAst.Table) => {
|
|
|
110
114
|
return columnDefStrs.join(', ')
|
|
111
115
|
}
|
|
112
116
|
|
|
117
|
+
/** NOTE primary keys are applied on a table level not on a column level to account for multi-column primary keys */
|
|
113
118
|
const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
const columnTypeStr = column.type._tag
|
|
120
|
+
const nullableStr = column.nullable === false ? 'not null' : ''
|
|
121
|
+
const defaultValueStr = (() => {
|
|
122
|
+
if (column.default === undefined) return ''
|
|
123
|
+
|
|
124
|
+
const encodeValue = EffectSchema.encodeSync(column.codec)
|
|
125
|
+
const encodedDefaultValue = encodeValue(column.default ?? null)
|
|
126
|
+
|
|
127
|
+
return columnTypeStr === 'text' ? `default '${encodedDefaultValue}'` : `default ${encodedDefaultValue}`
|
|
128
|
+
})()
|
|
129
|
+
|
|
130
|
+
return `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
|
|
125
131
|
}
|
|
@@ -6,7 +6,7 @@ import initSqlite3Wasm from 'sqlite-esm'
|
|
|
6
6
|
// TODO refactor so the `react` module doesn't depend on `effect` module
|
|
7
7
|
import type { LiveStoreContext as StoreContext_, LiveStoreCreateStoreOptions } from '../effect/LiveStore.js'
|
|
8
8
|
import type { InMemoryDatabase } from '../inMemoryDatabase.js'
|
|
9
|
-
import type {
|
|
9
|
+
import type { LiveStoreSchema } from '../schema/index.js'
|
|
10
10
|
import type { StorageInit } from '../storage/index.js'
|
|
11
11
|
import type { BaseGraphQLContext, GraphQLOptions } from '../store.js'
|
|
12
12
|
import { createStore } from '../store.js'
|
|
@@ -20,7 +20,7 @@ const sqlite3Promise = initSqlite3Wasm({
|
|
|
20
20
|
})
|
|
21
21
|
|
|
22
22
|
interface LiveStoreProviderProps<GraphQLContext> {
|
|
23
|
-
schema:
|
|
23
|
+
schema: LiveStoreSchema
|
|
24
24
|
loadStorage: () => StorageInit | Promise<StorageInit>
|
|
25
25
|
boot?: (db: InMemoryDatabase, parentSpan: otel.Span) => unknown | Promise<unknown>
|
|
26
26
|
graphQLOptions?: GraphQLOptions<GraphQLContext>
|
package/src/react/index.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
Setters,
|
|
3
|
-
ComponentKeyConfig,
|
|
4
|
-
QueryDefinitions,
|
|
5
|
-
ComponentColumns,
|
|
6
|
-
GetStateType,
|
|
7
|
-
GetStateTypeEncoded,
|
|
8
|
-
} from './useComponentState.js'
|
|
9
1
|
export { LiveStoreContext, useStore } from './LiveStoreContext.js'
|
|
10
2
|
export { LiveStoreProvider } from './LiveStoreProvider.js'
|
|
11
|
-
export { useComponentState } from './useComponentState.js'
|
|
12
3
|
export { useQuery } from './useQuery.js'
|
|
13
4
|
export { useTemporaryQuery } from './useTemporaryQuery.js'
|
|
14
5
|
export { useStackInfo } from './utils/stack-info.js'
|
|
6
|
+
export {
|
|
7
|
+
useRow,
|
|
8
|
+
type StateSetters,
|
|
9
|
+
type SetStateAction,
|
|
10
|
+
type Dispatch,
|
|
11
|
+
type UseRowResult as UseStateResult,
|
|
12
|
+
} from './useRow.js'
|
|
15
13
|
|
|
16
14
|
// Needed to make TS happy
|
|
17
15
|
export type { TypedDocumentNode } from '@graphql-typed-document-node/core'
|
package/src/react/useQuery.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { ILiveStoreQuery } from '../reactiveQueries/base-class.js'
|
|
|
6
6
|
import { useStore } from './LiveStoreContext.js'
|
|
7
7
|
import { extractStackInfoFromStackTrace, originalStackLimit } from './utils/stack-info.js'
|
|
8
8
|
import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.js'
|
|
9
|
+
|
|
9
10
|
/**
|
|
10
11
|
* This is needed because the `React.useMemo` call below, can sometimes be called multiple times 🤷,
|
|
11
12
|
* so we need to "cache" the fact that we've already started a span for this component.
|
|
@@ -13,7 +14,12 @@ import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInp
|
|
|
13
14
|
*/
|
|
14
15
|
const spanAlreadyStartedCache = new Map<ILiveStoreQuery<any>, { span: otel.Span; otelContext: otel.Context }>()
|
|
15
16
|
|
|
16
|
-
export const useQuery = <TResult>(query: ILiveStoreQuery<TResult>): TResult =>
|
|
17
|
+
export const useQuery = <TResult>(query: ILiveStoreQuery<TResult>): TResult => useQueryRef(query).current
|
|
18
|
+
|
|
19
|
+
export const useQueryRef = <TResult>(
|
|
20
|
+
query: ILiveStoreQuery<TResult>,
|
|
21
|
+
parentOtelContext?: otel.Context,
|
|
22
|
+
): React.MutableRefObject<TResult> => {
|
|
17
23
|
const { store } = useStore()
|
|
18
24
|
|
|
19
25
|
const stackInfo = React.useMemo(() => {
|
|
@@ -32,7 +38,7 @@ export const useQuery = <TResult>(query: ILiveStoreQuery<TResult>): TResult => {
|
|
|
32
38
|
const span = store.otel.tracer.startSpan(
|
|
33
39
|
`LiveStore:useQuery:${query.label}`,
|
|
34
40
|
{ attributes: { label: query.label, stackInfo: JSON.stringify(stackInfo) } },
|
|
35
|
-
store.otel.queriesSpanContext,
|
|
41
|
+
parentOtelContext ?? store.otel.queriesSpanContext,
|
|
36
42
|
)
|
|
37
43
|
|
|
38
44
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
@@ -40,7 +46,7 @@ export const useQuery = <TResult>(query: ILiveStoreQuery<TResult>): TResult => {
|
|
|
40
46
|
spanAlreadyStartedCache.set(query, { span, otelContext })
|
|
41
47
|
|
|
42
48
|
return { span, otelContext }
|
|
43
|
-
}, [query, stackInfo, store.otel.queriesSpanContext, store.otel.tracer])
|
|
49
|
+
}, [parentOtelContext, query, stackInfo, store.otel.queriesSpanContext, store.otel.tracer])
|
|
44
50
|
|
|
45
51
|
const initialResult = React.useMemo(
|
|
46
52
|
() =>
|
|
@@ -67,7 +73,7 @@ export const useQuery = <TResult>(query: ILiveStoreQuery<TResult>): TResult => {
|
|
|
67
73
|
// Subscribe to future updates for this query
|
|
68
74
|
React.useEffect(() => {
|
|
69
75
|
query.activeSubscriptions.add(stackInfo)
|
|
70
|
-
const
|
|
76
|
+
const unsubFromStore = store.subscribe(
|
|
71
77
|
query,
|
|
72
78
|
(newValue) => {
|
|
73
79
|
// NOTE: we return a reference to the result object within LiveStore;
|
|
@@ -82,9 +88,9 @@ export const useQuery = <TResult>(query: ILiveStoreQuery<TResult>): TResult => {
|
|
|
82
88
|
)
|
|
83
89
|
return () => {
|
|
84
90
|
query.activeSubscriptions.delete(stackInfo)
|
|
85
|
-
|
|
91
|
+
unsubFromStore()
|
|
86
92
|
}
|
|
87
93
|
}, [stackInfo, query, setValue, store, valueRef, otelContext, span])
|
|
88
94
|
|
|
89
|
-
return valueRef
|
|
95
|
+
return valueRef
|
|
90
96
|
}
|