@livestore/livestore 0.0.9 → 0.0.12

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.
Files changed (152) hide show
  1. package/package.json +7 -7
  2. package/src/__tests__/react/fixture.tsx +1 -13
  3. package/src/__tests__/reactive.test.ts +39 -0
  4. package/src/inMemoryDatabase.ts +5 -5
  5. package/src/react/useGraphQL.ts +6 -7
  6. package/src/react/useLiveStoreComponent.ts +38 -48
  7. package/src/reactive.ts +12 -11
  8. package/src/reactiveQueries/graphql.ts +5 -3
  9. package/src/reactiveQueries/js.ts +1 -3
  10. package/src/reactiveQueries/sql.ts +6 -6
  11. package/src/store.ts +45 -31
  12. package/dist/.tsbuildinfo +0 -1
  13. package/dist/QueryCache.d.ts +0 -20
  14. package/dist/QueryCache.d.ts.map +0 -1
  15. package/dist/QueryCache.js +0 -71
  16. package/dist/QueryCache.js.map +0 -1
  17. package/dist/__tests__/react/fixture.d.ts +0 -141
  18. package/dist/__tests__/react/fixture.d.ts.map +0 -1
  19. package/dist/__tests__/react/fixture.js +0 -72
  20. package/dist/__tests__/react/fixture.js.map +0 -1
  21. package/dist/__tests__/react/useLiveStoreComponent.test.d.ts +0 -2
  22. package/dist/__tests__/react/useLiveStoreComponent.test.d.ts.map +0 -1
  23. package/dist/__tests__/react/useLiveStoreComponent.test.js +0 -78
  24. package/dist/__tests__/react/useLiveStoreComponent.test.js.map +0 -1
  25. package/dist/__tests__/reactive.test.d.ts +0 -2
  26. package/dist/__tests__/reactive.test.d.ts.map +0 -1
  27. package/dist/__tests__/reactive.test.js +0 -167
  28. package/dist/__tests__/reactive.test.js.map +0 -1
  29. package/dist/backends/base.d.ts +0 -13
  30. package/dist/backends/base.d.ts.map +0 -1
  31. package/dist/backends/base.js +0 -53
  32. package/dist/backends/base.js.map +0 -1
  33. package/dist/backends/index.d.ts +0 -45
  34. package/dist/backends/index.d.ts.map +0 -1
  35. package/dist/backends/index.js +0 -38
  36. package/dist/backends/index.js.map +0 -1
  37. package/dist/backends/noop.d.ts +0 -18
  38. package/dist/backends/noop.d.ts.map +0 -1
  39. package/dist/backends/noop.js +0 -21
  40. package/dist/backends/noop.js.map +0 -1
  41. package/dist/backends/tauri.d.ts +0 -22
  42. package/dist/backends/tauri.d.ts.map +0 -1
  43. package/dist/backends/tauri.js +0 -48
  44. package/dist/backends/tauri.js.map +0 -1
  45. package/dist/backends/utils/idb.d.ts +0 -10
  46. package/dist/backends/utils/idb.d.ts.map +0 -1
  47. package/dist/backends/utils/idb.js +0 -58
  48. package/dist/backends/utils/idb.js.map +0 -1
  49. package/dist/backends/web-in-memory.d.ts +0 -22
  50. package/dist/backends/web-in-memory.d.ts.map +0 -1
  51. package/dist/backends/web-in-memory.js +0 -45
  52. package/dist/backends/web-in-memory.js.map +0 -1
  53. package/dist/backends/web-worker.d.ts +0 -17
  54. package/dist/backends/web-worker.d.ts.map +0 -1
  55. package/dist/backends/web-worker.js +0 -139
  56. package/dist/backends/web-worker.js.map +0 -1
  57. package/dist/backends/web.d.ts +0 -27
  58. package/dist/backends/web.d.ts.map +0 -1
  59. package/dist/backends/web.js +0 -63
  60. package/dist/backends/web.js.map +0 -1
  61. package/dist/bounded-collections.d.ts +0 -34
  62. package/dist/bounded-collections.d.ts.map +0 -1
  63. package/dist/bounded-collections.js +0 -103
  64. package/dist/bounded-collections.js.map +0 -1
  65. package/dist/componentKey.d.ts +0 -20
  66. package/dist/componentKey.d.ts.map +0 -1
  67. package/dist/componentKey.js +0 -3
  68. package/dist/componentKey.js.map +0 -1
  69. package/dist/effect/LiveStore.d.ts +0 -42
  70. package/dist/effect/LiveStore.d.ts.map +0 -1
  71. package/dist/effect/LiveStore.js +0 -40
  72. package/dist/effect/LiveStore.js.map +0 -1
  73. package/dist/effect/index.d.ts +0 -2
  74. package/dist/effect/index.d.ts.map +0 -1
  75. package/dist/effect/index.js +0 -2
  76. package/dist/effect/index.js.map +0 -1
  77. package/dist/events.d.ts +0 -7
  78. package/dist/events.d.ts.map +0 -1
  79. package/dist/events.js +0 -2
  80. package/dist/events.js.map +0 -1
  81. package/dist/inMemoryDatabase.d.ts +0 -65
  82. package/dist/inMemoryDatabase.d.ts.map +0 -1
  83. package/dist/inMemoryDatabase.js +0 -241
  84. package/dist/inMemoryDatabase.js.map +0 -1
  85. package/dist/index.d.ts +0 -20
  86. package/dist/index.d.ts.map +0 -1
  87. package/dist/index.js +0 -10
  88. package/dist/index.js.map +0 -1
  89. package/dist/otel.d.ts +0 -5
  90. package/dist/otel.d.ts.map +0 -1
  91. package/dist/otel.js +0 -17
  92. package/dist/otel.js.map +0 -1
  93. package/dist/react/LiveStoreContext.d.ts +0 -11
  94. package/dist/react/LiveStoreContext.d.ts.map +0 -1
  95. package/dist/react/LiveStoreContext.js +0 -10
  96. package/dist/react/LiveStoreContext.js.map +0 -1
  97. package/dist/react/LiveStoreProvider.d.ts +0 -21
  98. package/dist/react/LiveStoreProvider.d.ts.map +0 -1
  99. package/dist/react/LiveStoreProvider.js +0 -48
  100. package/dist/react/LiveStoreProvider.js.map +0 -1
  101. package/dist/react/index.d.ts +0 -7
  102. package/dist/react/index.d.ts.map +0 -1
  103. package/dist/react/index.js +0 -6
  104. package/dist/react/index.js.map +0 -1
  105. package/dist/react/useGlobalQuery.d.ts +0 -3
  106. package/dist/react/useGlobalQuery.d.ts.map +0 -1
  107. package/dist/react/useGlobalQuery.js +0 -25
  108. package/dist/react/useGlobalQuery.js.map +0 -1
  109. package/dist/react/useGraphQL.d.ts +0 -11
  110. package/dist/react/useGraphQL.d.ts.map +0 -1
  111. package/dist/react/useGraphQL.js +0 -68
  112. package/dist/react/useGraphQL.js.map +0 -1
  113. package/dist/react/useLiveStoreComponent.d.ts +0 -70
  114. package/dist/react/useLiveStoreComponent.d.ts.map +0 -1
  115. package/dist/react/useLiveStoreComponent.js +0 -261
  116. package/dist/react/useLiveStoreComponent.js.map +0 -1
  117. package/dist/react/utils/useStateRefWithReactiveInput.d.ts +0 -13
  118. package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +0 -1
  119. package/dist/react/utils/useStateRefWithReactiveInput.js +0 -38
  120. package/dist/react/utils/useStateRefWithReactiveInput.js.map +0 -1
  121. package/dist/reactive.d.ts +0 -140
  122. package/dist/reactive.d.ts.map +0 -1
  123. package/dist/reactive.js +0 -301
  124. package/dist/reactive.js.map +0 -1
  125. package/dist/reactiveQueries/base-class.d.ts +0 -24
  126. package/dist/reactiveQueries/base-class.d.ts.map +0 -1
  127. package/dist/reactiveQueries/base-class.js +0 -22
  128. package/dist/reactiveQueries/base-class.js.map +0 -1
  129. package/dist/reactiveQueries/graphql.d.ts +0 -25
  130. package/dist/reactiveQueries/graphql.d.ts.map +0 -1
  131. package/dist/reactiveQueries/graphql.js +0 -14
  132. package/dist/reactiveQueries/graphql.js.map +0 -1
  133. package/dist/reactiveQueries/js.d.ts +0 -19
  134. package/dist/reactiveQueries/js.d.ts.map +0 -1
  135. package/dist/reactiveQueries/js.js +0 -13
  136. package/dist/reactiveQueries/js.js.map +0 -1
  137. package/dist/reactiveQueries/sql.d.ts +0 -31
  138. package/dist/reactiveQueries/sql.d.ts.map +0 -1
  139. package/dist/reactiveQueries/sql.js +0 -28
  140. package/dist/reactiveQueries/sql.js.map +0 -1
  141. package/dist/schema.d.ts +0 -163
  142. package/dist/schema.d.ts.map +0 -1
  143. package/dist/schema.js +0 -92
  144. package/dist/schema.js.map +0 -1
  145. package/dist/store.d.ts +0 -175
  146. package/dist/store.d.ts.map +0 -1
  147. package/dist/store.js +0 -549
  148. package/dist/store.js.map +0 -1
  149. package/dist/util.d.ts +0 -24
  150. package/dist/util.d.ts.map +0 -1
  151. package/dist/util.js +0 -51
  152. package/dist/util.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livestore/livestore",
3
- "version": "0.0.9",
3
+ "version": "0.0.12",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -31,13 +31,13 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@graphql-typed-document-node/core": "^3.2.0",
34
- "@livestore/utils": "0.0.9",
34
+ "@livestore/utils": "workspace:*",
35
35
  "@opentelemetry/api": "^1.6.0",
36
36
  "comlink": "^4.4.1",
37
- "graphql": "^16.8.0",
37
+ "graphql": "^16.8.1",
38
38
  "lodash-es": "^4.17.21",
39
39
  "sqlite-esm": "3.42.0-build6",
40
- "uuid": "^9.0.0"
40
+ "uuid": "^9.0.1"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@tauri-apps/api": "^1.4.0",
@@ -53,12 +53,12 @@
53
53
  "@tauri-apps/api": "^1.4.0",
54
54
  "@testing-library/react": "^14.0.0",
55
55
  "@types/lodash-es": "^4.17.9",
56
- "@types/uuid": "^9.0.3",
56
+ "@types/uuid": "^9.0.4",
57
57
  "jsdom": "^22.1.0",
58
58
  "react": "^18.2.0",
59
59
  "react-dom": "^18.2.0",
60
60
  "typescript": "5.2.2",
61
61
  "vite": "4.4.9",
62
- "vitest": "^0.34.3"
62
+ "vitest": "^0.34.6"
63
63
  }
64
- }
64
+ }
@@ -1,13 +1,10 @@
1
1
  import { mapObjectValues } from '@livestore/utils'
2
- import * as otel from '@opentelemetry/api'
3
2
  import React from 'react'
4
3
 
5
4
  import * as LiveStore from '../../index.js'
6
5
  import { sql } from '../../index.js'
7
6
  import * as LiveStoreReact from '../../react/index.js'
8
7
 
9
- const mockOtelCtx = otel.context.active()
10
-
11
8
  export type Todo = {
12
9
  id: string
13
10
  text: string | null
@@ -22,16 +19,7 @@ export type AppState = {
22
19
  }
23
20
 
24
21
  const appState: LiveStore.QueryDefinition = (store) =>
25
- store
26
- .querySQL<AppState>(
27
- () => `select newTodoText, filter from app;`,
28
- ['app'],
29
- undefined,
30
- undefined,
31
- undefined,
32
- mockOtelCtx,
33
- )
34
- .getFirstRow()
22
+ store.querySQL<AppState>(() => `select newTodoText, filter from app;`, { queriedTables: ['app'] }).getFirstRow()
35
23
 
36
24
  export const globalQueryDefs = {
37
25
  appState,
@@ -225,3 +225,42 @@ describe('a diamond shaped graph', () => {
225
225
  expect(dRuns.runs).toBe(2)
226
226
  })
227
227
  })
228
+
229
+ // TODO handle `undefined` in the graph
230
+ describe.todo('a trivial graph with undefined', () => {
231
+ const makeGraph = () => {
232
+ const graph = new ReactiveGraph({ otelTracer: makeNoopTracer() })
233
+ const a = graph.makeRef(undefined)
234
+ const b = graph.makeRef(2)
235
+ const numberOfRunsForC = { runs: 0 }
236
+ const c = graph.makeThunk(
237
+ (get) => {
238
+ numberOfRunsForC.runs++
239
+ return (get(a) ?? 0) + get(b)
240
+ },
241
+ undefined,
242
+ mockOtelCtx,
243
+ )
244
+ const d = graph.makeRef(3)
245
+ const e = graph.makeThunk((get) => get(c) + get(d), undefined, mockOtelCtx)
246
+
247
+ // a(1) b(2)
248
+ // \ /
249
+ // \ /
250
+ // c = a + b
251
+ // \
252
+ // \
253
+ // d(3) \
254
+ // \ \
255
+ // \ \
256
+ // e = c + d
257
+
258
+ return { graph, a, b, c, d, e, numberOfRunsForC }
259
+ }
260
+
261
+ it('has the right initial values', () => {
262
+ const { c, e } = makeGraph()
263
+ expect(c.result).toBe(3)
264
+ expect(e.result).toBe(6)
265
+ })
266
+ })
@@ -192,14 +192,14 @@ export class InMemoryDatabase {
192
192
  queriedTables?: string[]
193
193
  bindValues?: Bindable
194
194
  skipCache?: boolean
195
- parentSpanContext?: otel.Context
195
+ otelContext?: otel.Context
196
196
  },
197
197
  ): ReadonlyArray<T> {
198
- const { queriedTables, bindValues, skipCache = false, parentSpanContext } = options ?? {}
198
+ const { queriedTables, bindValues, skipCache = false, otelContext } = options ?? {}
199
199
  return this.otelTracer.startActiveSpan(
200
200
  'sql-in-memory-select',
201
201
  {},
202
- parentSpanContext ?? this.otelRootSpanContext,
202
+ otelContext ?? this.otelRootSpanContext,
203
203
  (span) => {
204
204
  try {
205
205
  span.setAttribute('sql.query', query)
@@ -279,9 +279,9 @@ export class InMemoryDatabase {
279
279
  applyEvent(
280
280
  event: LiveStoreEvent,
281
281
  eventDefinition: ActionDefinition,
282
- parentSpanContext: otel.Context,
282
+ otelContext: otel.Context,
283
283
  ): { durationMs: number } {
284
- return this.otelTracer.startActiveSpan('livestore.in-memory-db:applyEvent', {}, parentSpanContext, (span) => {
284
+ return this.otelTracer.startActiveSpan('livestore.in-memory-db:applyEvent', {}, otelContext, (span) => {
285
285
  // TODO: in the future, we'll do more CRDT-style stuff here to decide whether to run effects of the event
286
286
 
287
287
  // NOTE: These two updates should happen transactionally;
@@ -20,7 +20,7 @@ export type UseLiveStoreComponentProps<TResult extends Record<string, any>, TVar
20
20
  * so we need to "cache" the fact that we've already started a span for this component.
21
21
  * The map entry is being removed again in the `React.useEffect` call below.
22
22
  */
23
- const spanAlreadyStartedCache = new Map<string, { span: otel.Span; otelCtx: otel.Context }>()
23
+ const spanAlreadyStartedCache = new Map<string, { span: otel.Span; otelContext: otel.Context }>()
24
24
 
25
25
  // TODO 1) figure out a way to make `variables` optional if the query doesn't have any variables (probably requires positional args)
26
26
  // TODO 2) allow `.pipe` on the resulting query (possibly as a separate optional prop)
@@ -36,7 +36,7 @@ export const useGraphQL = <TResult extends Record<string, any>, TVariables exten
36
36
  const componentKeyLabel = React.useMemo(() => labelForKey(componentKey), [componentKey])
37
37
 
38
38
  // The following `React.useMemo` and `React.useEffect` calls are used to start and end a span for the lifetime of this component.
39
- const { span, otelCtx } = React.useMemo(() => {
39
+ const { span, otelContext } = React.useMemo(() => {
40
40
  const existingSpan = spanAlreadyStartedCache.get(componentKeyLabel)
41
41
  if (existingSpan !== undefined) return existingSpan
42
42
 
@@ -46,11 +46,11 @@ export const useGraphQL = <TResult extends Record<string, any>, TVariables exten
46
46
  store.otel.queriesSpanContext,
47
47
  )
48
48
 
49
- const otelCtx = otel.trace.setSpan(otel.context.active(), span)
49
+ const otelContext = otel.trace.setSpan(otel.context.active(), span)
50
50
 
51
- spanAlreadyStartedCache.set(componentKeyLabel, { span, otelCtx })
51
+ spanAlreadyStartedCache.set(componentKeyLabel, { span, otelContext })
52
52
 
53
- return { span, otelCtx }
53
+ return { span, otelContext }
54
54
  }, [componentKeyLabel, store.otel.queriesSpanContext, store.otel.tracer])
55
55
 
56
56
  React.useEffect(
@@ -62,7 +62,7 @@ export const useGraphQL = <TResult extends Record<string, any>, TVariables exten
62
62
  )
63
63
 
64
64
  const makeLiveStoreQuery = React.useCallback(
65
- () => store.queryGraphQL(query, () => variables ?? ({} as TVariables), { componentKey }, otelCtx),
65
+ () => store.queryGraphQL(query, () => variables ?? ({} as TVariables), { componentKey, otelContext }),
66
66
  // NOTE: we don't include the queries function passed in by the user here;
67
67
  // the reason is that we don't want to force them to memoize that function.
68
68
  // Instead, we just assume that the function always has the same contents.
@@ -100,7 +100,6 @@ export const useGraphQL = <TResult extends Record<string, any>, TVariables exten
100
100
  // This should probably be improved
101
101
  // eslint-disable-next-line react-hooks/exhaustive-deps
102
102
  }, [
103
- otelCtx,
104
103
  makeLiveStoreQuery,
105
104
  // setQueryResults_,
106
105
  store,
@@ -14,6 +14,7 @@ import type { LiveStoreJSQuery } from '../reactiveQueries/js.js'
14
14
  import type { LiveStoreSQLQuery } from '../reactiveQueries/sql.js'
15
15
  import type { ComponentStateSchema } from '../schema.js'
16
16
  import type { BaseGraphQLContext, LiveStoreQuery, QueryResult, Store } from '../store.js'
17
+ import type { Bindable } from '../util.js'
17
18
  import { sql } from '../util.js'
18
19
  import { useStore } from './LiveStoreContext.js'
19
20
  import { useStateRefWithReactiveInput } from './utils/useStateRefWithReactiveInput.js'
@@ -26,6 +27,7 @@ export type QueryResults<TQuery> = { [queryName in keyof TQuery]: QueryResult<TQ
26
27
  export type ReactiveSQL = <TResult>(
27
28
  genQuery: (get: GetAtom) => string,
28
29
  queriedTables: string[],
30
+ bindValues?: Bindable | undefined,
29
31
  ) => LiveStoreSQLQuery<TResult>
30
32
  export type ReactiveGraphQL = <
31
33
  TResult extends Record<string, any>,
@@ -81,7 +83,7 @@ type ComponentState = {
81
83
  * so we need to "cache" the fact that we've already started a span for this component.
82
84
  * The map entry is being removed again in the `React.useEffect` call below.
83
85
  */
84
- const spanAlreadyStartedCache = new Map<string, { span: otel.Span; otelCtx: otel.Context }>()
86
+ const spanAlreadyStartedCache = new Map<string, { span: otel.Span; otelContext: otel.Context }>()
85
87
 
86
88
  type UseLiveStoreJsonState<TState> = <TResult>(
87
89
  jsonStringKey: keyof TState,
@@ -118,7 +120,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
118
120
  const componentKeyLabel = React.useMemo(() => labelForKey(componentKey), [componentKey])
119
121
 
120
122
  // The following `React.useMemo` and `React.useEffect` calls are used to start and end a span for the lifetime of this component.
121
- const { span, otelCtx } = React.useMemo(() => {
123
+ const { span, otelContext } = React.useMemo(() => {
122
124
  const existingSpan = spanAlreadyStartedCache.get(componentKeyLabel)
123
125
  if (existingSpan !== undefined) return existingSpan
124
126
 
@@ -128,11 +130,11 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
128
130
  store.otel.queriesSpanContext,
129
131
  )
130
132
 
131
- const otelCtx = otel.trace.setSpan(otel.context.active(), span)
133
+ const otelContext = otel.trace.setSpan(otel.context.active(), span)
132
134
 
133
- spanAlreadyStartedCache.set(componentKeyLabel, { span, otelCtx })
135
+ spanAlreadyStartedCache.set(componentKeyLabel, { span, otelContext })
134
136
 
135
- return { span, otelCtx }
137
+ return { span, otelContext }
136
138
  }, [componentKeyLabel, store.otel.queriesSpanContext, store.otel.tracer])
137
139
 
138
140
  React.useEffect(
@@ -146,23 +148,23 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
146
148
  const generateQueries = React.useCallback(
147
149
  ({
148
150
  state$,
149
- otelCtx,
151
+ otelContext,
150
152
  registerSubscription,
151
153
  isTemporaryQuery,
152
154
  }: {
153
155
  state$: LiveStoreJSQuery<TComponentState>
154
- otelCtx: otel.Context
156
+ otelContext: otel.Context
155
157
  registerSubscription: RegisterSubscription
156
158
  isTemporaryQuery: boolean
157
159
  }) =>
158
160
  queries({
159
- rxSQL: <T>(genQuery: (get: GetAtom) => string, queriedTables: string[]) =>
160
- store.querySQL<T>(genQuery, queriedTables, undefined, componentKey, undefined, otelCtx),
161
+ rxSQL: <T>(genQuery: (get: GetAtom) => string, queriedTables: string[], bindValues?: Bindable) =>
162
+ store.querySQL<T>(genQuery, { queriedTables, bindValues, otelContext }),
161
163
  rxGraphQL: <Result extends Record<string, any>, Variables extends Record<string, any>>(
162
164
  query: DocumentNode<Result, Variables>,
163
165
  genVariableValues: (get: GetAtom) => Variables,
164
166
  label?: string,
165
- ) => store.queryGraphQL(query, genVariableValues, { componentKey, label }, otelCtx),
167
+ ) => store.queryGraphQL(query, genVariableValues, { componentKey, label, otelContext }),
166
168
  globalQueries,
167
169
  state$,
168
170
  subscribe: registerSubscription,
@@ -193,8 +195,8 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
193
195
  // We do this in a temporary query context which cleans up after itself, making it idempotent
194
196
  // TODO get rid of the temporary query workaround
195
197
  const { initialComponentState, initialQueryResults } = React.useMemo(() => {
196
- return store.otel.tracer.startActiveSpan('LiveStore:useLiveStoreComponent:initial', {}, otelCtx, (span) => {
197
- const otelCtx = otel.trace.setSpan(otel.context.active(), span)
198
+ return store.otel.tracer.startActiveSpan('LiveStore:useLiveStoreComponent:initial', {}, otelContext, (span) => {
199
+ const otelContext = otel.trace.setSpan(otel.context.active(), span)
198
200
 
199
201
  return store.inTempQueryContext(() => {
200
202
  try {
@@ -202,31 +204,27 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
202
204
  let stateQuery: LiveStoreJSQuery<TComponentState>
203
205
  if (stateSchema === undefined) {
204
206
  // TODO don't set up a query if there's no state schema (keeps the graph more clean)
205
- stateQuery = store.queryJS(
206
- () => ({}),
207
+ stateQuery = store.queryJS(() => ({}), {
207
208
  componentKey,
208
- undefined,
209
- otelCtx,
210
- ) as unknown as LiveStoreJSQuery<TComponentState>
209
+ otelContext,
210
+ }) as unknown as LiveStoreJSQuery<TComponentState>
211
211
  } else {
212
212
  const componentTableName = tableNameForComponentKey(componentKey)
213
213
  const whereClause = componentKey._tag === 'singleton' ? '' : `where id = '${componentKey.id}'`
214
214
  stateQuery = store
215
- .querySQL<TComponentState>(
216
- () => sql`select * from ${componentTableName} ${whereClause} limit 1`,
217
- [componentTableName],
218
- undefined,
215
+ .querySQL<TComponentState>(() => sql`select * from ${componentTableName} ${whereClause} limit 1`, {
216
+ queriedTables: [componentTableName],
219
217
  componentKey,
220
- `localState:query:${componentKeyLabel}`,
221
- otelCtx,
222
- )
218
+ label: `localState:query:${componentKeyLabel}`,
219
+ otelContext,
220
+ })
223
221
  .getFirstRow({ defaultValue: defaultComponentState })
224
222
  }
225
223
  const initialComponentState = stateQuery.results$.result
226
224
 
227
225
  const queries = generateQueries({
228
226
  state$: stateQuery,
229
- otelCtx,
227
+ otelContext,
230
228
  registerSubscription: () => {},
231
229
  isTemporaryQuery: true,
232
230
  })
@@ -241,7 +239,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
241
239
  }
242
240
  })
243
241
  })
244
- }, [store, otelCtx, stateSchema, generateQueries, componentKey, componentKeyLabel, defaultComponentState])
242
+ }, [store, otelContext, stateSchema, generateQueries, componentKey, componentKeyLabel, defaultComponentState])
245
243
 
246
244
  // Now that we've computed the initial state synchronously,
247
245
  // we can set up our useState calls w/ a default value populated...
@@ -287,48 +285,40 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
287
285
  return store.otel.tracer.startActiveSpan(
288
286
  'LiveStore:useLiveStoreComponent:long-running',
289
287
  { attributes: {} },
290
- otelCtx,
288
+ otelContext,
291
289
  (span) => {
292
- const otelCtx = otel.trace.setSpan(otel.context.active(), span)
290
+ const otelContext = otel.trace.setSpan(otel.context.active(), span)
293
291
  const unsubs: (() => void)[] = []
294
292
 
295
293
  // create state query
296
- let stateQuery: LiveStoreJSQuery<TComponentState>
294
+ let state$: LiveStoreJSQuery<TComponentState>
297
295
  if (stateSchema === undefined) {
298
- stateQuery = store.queryJS(
299
- () => ({}),
300
- componentKey,
301
- undefined,
302
- otelCtx,
303
- ) as unknown as LiveStoreJSQuery<TComponentState>
296
+ state$ = store.queryJS(() => ({}) as TComponentState, { componentKey, otelContext })
304
297
  } else {
305
298
  const componentTableName = tableNameForComponentKey(componentKey)
306
299
  insertRowForComponentInstance({ store, componentKey, stateSchema })
307
300
 
308
301
  const whereClause = componentKey._tag === 'singleton' ? '' : `where id = '${componentKey.id}'`
309
- stateQuery = store
310
- .querySQL<TComponentState>(
311
- () => sql`select * from ${componentTableName} ${whereClause} limit 1`,
312
- [componentTableName],
313
- undefined,
302
+ state$ = store
303
+ .querySQL<TComponentState>(() => sql`select * from ${componentTableName} ${whereClause} limit 1`, {
304
+ queriedTables: [componentTableName],
314
305
  componentKey,
315
- // TODO introduce a refresh "grouping" concept to associate related refreshes in the debugger UI
316
- `localState:query:${componentKeyLabel}`,
317
- otelCtx,
318
- )
306
+ label: `localState:query:${componentKeyLabel}`,
307
+ otelContext,
308
+ })
319
309
  .getFirstRow({ defaultValue: defaultComponentState })
320
310
  }
321
311
 
322
312
  unsubs.push(
323
313
  store.subscribe(
324
- stateQuery,
314
+ state$,
325
315
  (results) => {
326
316
  if (isEqual(results, componentStateRef.current) === false) {
327
317
  setComponentState_(results as TComponentState)
328
318
  }
329
319
  },
330
320
  undefined,
331
- { label: `useLiveStoreComponent:localState:subscribe:${stateQuery.label}` },
321
+ { label: `useLiveStoreComponent:localState:subscribe:${state$.label}` },
332
322
  ),
333
323
  )
334
324
 
@@ -345,7 +335,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
345
335
  )
346
336
  }
347
337
 
348
- const queries = generateQueries({ state$: stateQuery, otelCtx, registerSubscription, isTemporaryQuery: false })
338
+ const queries = generateQueries({ state$, otelContext, registerSubscription, isTemporaryQuery: false })
349
339
  // Use the name given to this query in the useQueries hook as its label
350
340
  for (const [name, query] of Object.entries(queries)) {
351
341
  query.label = name
@@ -384,7 +374,7 @@ export const useLiveStoreComponent = <TComponentState extends ComponentState, TQ
384
374
  stateSchema,
385
375
  defaultComponentState,
386
376
  generateQueries,
387
- otelCtx,
377
+ otelContext,
388
378
  componentStateRef,
389
379
  // setComponentState_,
390
380
  // setQueryResults_,
package/src/reactive.ts CHANGED
@@ -196,7 +196,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
196
196
  debugRefreshReason?: RefreshReasonWithGenericReasons<TDebugRefreshReason>
197
197
  }
198
198
  | undefined,
199
- parentSpanContext: otel.Context,
199
+ otelContext: otel.Context,
200
200
  ): Thunk<T> {
201
201
  const thunk: UnevaluatedThunk<T> = {
202
202
  _tag: 'thunk',
@@ -218,7 +218,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
218
218
  otelHint: options?.label ?? 'makeThunk',
219
219
  debugRefreshReason: options?.debugRefreshReason ?? { _tag: 'makeThunk', label: options?.label },
220
220
  },
221
- parentSpanContext,
221
+ otelContext,
222
222
  )
223
223
 
224
224
  // Manually tell the typesystem this thunk is guaranteed to have a result at this point
@@ -248,7 +248,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
248
248
  makeEffect(
249
249
  doEffect: (get: GetAtom) => void,
250
250
  options: { label?: string } | undefined,
251
- parentSpanContext: otel.Context,
251
+ otelContext: otel.Context,
252
252
  ): Effect {
253
253
  const effect: Effect = {
254
254
  _tag: 'effect',
@@ -261,7 +261,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
261
261
  this.dirtyNodes.add(effect)
262
262
  this.refresh(
263
263
  { otelHint: 'makeEffect', debugRefreshReason: { _tag: 'makeEffect', label: options?.label } },
264
- parentSpanContext,
264
+ otelContext,
265
265
  )
266
266
 
267
267
  return effect
@@ -277,7 +277,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
277
277
  debugRefreshReason?: TDebugRefreshReason
278
278
  }
279
279
  | undefined,
280
- parentSpanContext: otel.Context,
280
+ otelContext: otel.Context,
281
281
  ) {
282
282
  const { otelHint, skipRefresh, debugRefreshReason } = options ?? {}
283
283
  ref.result = val
@@ -297,7 +297,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
297
297
  return
298
298
  }
299
299
 
300
- this.refresh({ otelHint, debugRefreshReason }, parentSpanContext)
300
+ this.refresh({ otelHint, debugRefreshReason }, otelContext)
301
301
  }
302
302
 
303
303
  setRefs<T>(
@@ -309,7 +309,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
309
309
  debugRefreshReason?: TDebugRefreshReason
310
310
  }
311
311
  | undefined,
312
- parentSpanContext: otel.Context,
312
+ otelContext: otel.Context,
313
313
  ) {
314
314
  const otelHint = options?.otelHint ?? ''
315
315
  const skipRefresh = options?.skipRefresh ?? false
@@ -333,7 +333,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
333
333
  return
334
334
  }
335
335
 
336
- this.refresh({ otelHint, debugRefreshReason }, parentSpanContext)
336
+ this.refresh({ otelHint, debugRefreshReason }, otelContext)
337
337
  }
338
338
 
339
339
  get<T>(atom: Atom<T>, context: Atom<any> | Effect): T {
@@ -350,7 +350,8 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
350
350
  )
351
351
  }
352
352
 
353
- return atom.result!
353
+ // TODO handle case when `atom.result` is undefined
354
+ return atom.result
354
355
  }
355
356
 
356
357
  /**
@@ -367,7 +368,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
367
368
  debugRefreshReason?: RefreshReasonWithGenericReasons<TDebugRefreshReason>
368
369
  }
369
370
  | undefined,
370
- parentSpanContext: otel.Context,
371
+ otelContext: otel.Context,
371
372
  ): void {
372
373
  const otelHint = options?.otelHint ?? ''
373
374
  const debugRefreshReason = options?.debugRefreshReason
@@ -380,7 +381,7 @@ export class ReactiveGraph<TDebugRefreshReason extends Taggable, TDebugThunkInfo
380
381
  // console.log('refresh', otelHint, { shouldTrace })
381
382
  // }
382
383
 
383
- this.otelTracer.startActiveSpan(`LiveStore.refresh:${otelHint}`, {}, parentSpanContext, (span) => {
384
+ this.otelTracer.startActiveSpan(`LiveStore.refresh:${otelHint}`, {}, otelContext, (span) => {
384
385
  const atomsToRefresh = roots.filter(isAtom)
385
386
  const effectsToRun = new Set(roots.filter(isEffect))
386
387
 
@@ -45,8 +45,10 @@ export class LiveStoreGraphQLQuery<
45
45
  const results = get(this.results$)
46
46
  return f(results, get)
47
47
  },
48
- this.componentKey,
49
- `${this.label}:js`,
50
- this.otelContext,
48
+ {
49
+ componentKey: this.componentKey,
50
+ label: `${this.label}:js`,
51
+ otelContext: this.otelContext,
52
+ },
51
53
  )
52
54
  }
@@ -31,8 +31,6 @@ export class LiveStoreJSQuery<TResult> extends LiveStoreQueryBase {
31
31
  const results = get(this.results$)
32
32
  return f(results, get)
33
33
  },
34
- this.componentKey,
35
- `${this.label}:js`,
36
- this.otelContext,
34
+ { componentKey: this.componentKey, label: `${this.label}:js`, otelContext: this.otelContext },
37
35
  )
38
36
  }
@@ -42,9 +42,11 @@ export class LiveStoreSQLQuery<Row> extends LiveStoreQueryBase {
42
42
  const results = get(this.results$)
43
43
  return f(results, get)
44
44
  },
45
- this.componentKey,
46
- `${this.label}:js`,
47
- this.otelContext,
45
+ {
46
+ componentKey: this.componentKey,
47
+ label: `${this.label}:js`,
48
+ otelContext: this.otelContext,
49
+ },
48
50
  )
49
51
 
50
52
  /** Returns a reactive query */
@@ -58,8 +60,6 @@ export class LiveStoreSQLQuery<Row> extends LiveStoreQueryBase {
58
60
  }
59
61
  return (results[0] ?? args?.defaultValue) as Row
60
62
  },
61
- this.componentKey,
62
- `${this.label}:first`,
63
- this.otelContext,
63
+ { componentKey: this.componentKey, label: `${this.label}:first`, otelContext: this.otelContext },
64
64
  )
65
65
  }