@livestore/livestore 0.3.0-dev.5 → 0.3.0-dev.50

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 (170) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/QueryCache.d.ts.map +1 -1
  3. package/dist/SqliteDbWrapper.d.ts +60 -0
  4. package/dist/SqliteDbWrapper.d.ts.map +1 -0
  5. package/dist/{SynchronousDatabaseWrapper.js → SqliteDbWrapper.js} +69 -34
  6. package/dist/SqliteDbWrapper.js.map +1 -0
  7. package/dist/effect/LiveStore.d.ts +6 -34
  8. package/dist/effect/LiveStore.d.ts.map +1 -1
  9. package/dist/effect/LiveStore.js +10 -12
  10. package/dist/effect/LiveStore.js.map +1 -1
  11. package/dist/effect/mod.d.ts +3 -0
  12. package/dist/effect/mod.d.ts.map +1 -0
  13. package/dist/effect/mod.js +3 -0
  14. package/dist/effect/mod.js.map +1 -0
  15. package/dist/internal/mod.d.ts +3 -0
  16. package/dist/internal/mod.d.ts.map +1 -0
  17. package/dist/internal/mod.js +3 -0
  18. package/dist/internal/mod.js.map +1 -0
  19. package/dist/live-queries/base-class.d.ts +65 -27
  20. package/dist/live-queries/base-class.d.ts.map +1 -1
  21. package/dist/live-queries/base-class.js +54 -13
  22. package/dist/live-queries/base-class.js.map +1 -1
  23. package/dist/live-queries/client-document-get-query.d.ts +12 -0
  24. package/dist/live-queries/client-document-get-query.d.ts.map +1 -0
  25. package/dist/live-queries/client-document-get-query.js +18 -0
  26. package/dist/live-queries/client-document-get-query.js.map +1 -0
  27. package/dist/live-queries/computed.d.ts +12 -14
  28. package/dist/live-queries/computed.d.ts.map +1 -1
  29. package/dist/live-queries/computed.js +37 -15
  30. package/dist/live-queries/computed.js.map +1 -1
  31. package/dist/live-queries/db-query.d.ts +93 -0
  32. package/dist/live-queries/db-query.d.ts.map +1 -0
  33. package/dist/live-queries/{db.js → db-query.js} +111 -40
  34. package/dist/live-queries/db-query.js.map +1 -0
  35. package/dist/live-queries/db-query.test.d.ts +2 -0
  36. package/dist/live-queries/db-query.test.d.ts.map +1 -0
  37. package/dist/live-queries/db-query.test.js +133 -0
  38. package/dist/live-queries/db-query.test.js.map +1 -0
  39. package/dist/live-queries/mod.d.ts +5 -0
  40. package/dist/live-queries/mod.d.ts.map +1 -0
  41. package/dist/live-queries/mod.js +5 -0
  42. package/dist/live-queries/mod.js.map +1 -0
  43. package/dist/live-queries/signal.d.ts +20 -0
  44. package/dist/live-queries/signal.d.ts.map +1 -0
  45. package/dist/live-queries/signal.js +33 -0
  46. package/dist/live-queries/signal.js.map +1 -0
  47. package/dist/live-queries/signal.test.d.ts +2 -0
  48. package/dist/live-queries/signal.test.d.ts.map +1 -0
  49. package/dist/live-queries/signal.test.js +25 -0
  50. package/dist/live-queries/signal.test.js.map +1 -0
  51. package/dist/mod.d.ts +14 -0
  52. package/dist/mod.d.ts.map +1 -0
  53. package/dist/mod.js +13 -0
  54. package/dist/mod.js.map +1 -0
  55. package/dist/reactive.d.ts +23 -17
  56. package/dist/reactive.d.ts.map +1 -1
  57. package/dist/reactive.js +23 -19
  58. package/dist/reactive.js.map +1 -1
  59. package/dist/reactive.test.js +1 -1
  60. package/dist/reactive.test.js.map +1 -1
  61. package/dist/store/create-store.d.ts +70 -12
  62. package/dist/store/create-store.d.ts.map +1 -1
  63. package/dist/store/create-store.js +68 -19
  64. package/dist/store/create-store.js.map +1 -1
  65. package/dist/store/devtools.d.ts +5 -4
  66. package/dist/store/devtools.d.ts.map +1 -1
  67. package/dist/store/devtools.js +92 -40
  68. package/dist/store/devtools.js.map +1 -1
  69. package/dist/store/store-types.d.ts +54 -42
  70. package/dist/store/store-types.d.ts.map +1 -1
  71. package/dist/store/store-types.js +2 -5
  72. package/dist/store/store-types.js.map +1 -1
  73. package/dist/store/store.d.ts +141 -35
  74. package/dist/store/store.d.ts.map +1 -1
  75. package/dist/store/store.js +319 -153
  76. package/dist/store/store.js.map +1 -1
  77. package/dist/utils/data-structures.d.ts.map +1 -1
  78. package/dist/utils/dev.d.ts.map +1 -1
  79. package/dist/utils/dev.js +6 -1
  80. package/dist/utils/dev.js.map +1 -1
  81. package/dist/utils/function-string.d.ts +7 -0
  82. package/dist/utils/function-string.d.ts.map +1 -0
  83. package/dist/utils/function-string.js +9 -0
  84. package/dist/utils/function-string.js.map +1 -0
  85. package/dist/utils/stack-info.d.ts.map +1 -1
  86. package/dist/utils/stack-info.js +6 -1
  87. package/dist/utils/stack-info.js.map +1 -1
  88. package/dist/utils/stack-info.test.js +54 -1
  89. package/dist/utils/stack-info.test.js.map +1 -1
  90. package/dist/utils/tests/fixture.d.ts +59 -216
  91. package/dist/utils/tests/fixture.d.ts.map +1 -1
  92. package/dist/utils/tests/fixture.js +23 -18
  93. package/dist/utils/tests/fixture.js.map +1 -1
  94. package/dist/utils/tests/mod.d.ts +1 -0
  95. package/dist/utils/tests/mod.d.ts.map +1 -1
  96. package/dist/utils/tests/mod.js +1 -0
  97. package/dist/utils/tests/mod.js.map +1 -1
  98. package/dist/utils/tests/otel.d.ts.map +1 -1
  99. package/dist/utils/tests/otel.js +8 -3
  100. package/dist/utils/tests/otel.js.map +1 -1
  101. package/package.json +29 -26
  102. package/src/{SynchronousDatabaseWrapper.ts → SqliteDbWrapper.ts} +92 -42
  103. package/src/effect/LiveStore.ts +27 -64
  104. package/src/effect/{index.ts → mod.ts} +2 -3
  105. package/src/internal/mod.ts +2 -0
  106. package/src/live-queries/__snapshots__/{db.test.ts.snap → db-query.test.ts.snap} +241 -45
  107. package/src/live-queries/base-class.ts +152 -50
  108. package/src/live-queries/client-document-get-query.ts +52 -0
  109. package/src/live-queries/computed.ts +51 -33
  110. package/src/live-queries/db-query.test.ts +192 -0
  111. package/src/live-queries/{db.ts → db-query.ts} +168 -81
  112. package/src/live-queries/mod.ts +4 -0
  113. package/src/live-queries/signal.test.ts +40 -0
  114. package/src/live-queries/signal.ts +47 -0
  115. package/src/mod.ts +42 -0
  116. package/src/reactive.test.ts +1 -1
  117. package/src/reactive.ts +66 -43
  118. package/src/store/create-store.ts +188 -62
  119. package/src/store/devtools.ts +124 -46
  120. package/src/store/store-types.ts +54 -43
  121. package/src/store/store.ts +454 -236
  122. package/src/utils/dev.ts +6 -1
  123. package/src/utils/function-string.ts +12 -0
  124. package/src/utils/stack-info.test.ts +58 -1
  125. package/src/utils/stack-info.ts +6 -1
  126. package/src/utils/tests/fixture.ts +22 -31
  127. package/src/utils/tests/mod.ts +1 -0
  128. package/src/utils/tests/otel.ts +10 -3
  129. package/dist/SynchronousDatabaseWrapper.d.ts +0 -41
  130. package/dist/SynchronousDatabaseWrapper.d.ts.map +0 -1
  131. package/dist/SynchronousDatabaseWrapper.js.map +0 -1
  132. package/dist/effect/index.d.ts +0 -2
  133. package/dist/effect/index.d.ts.map +0 -1
  134. package/dist/effect/index.js +0 -2
  135. package/dist/effect/index.js.map +0 -1
  136. package/dist/global-state.d.ts +0 -14
  137. package/dist/global-state.d.ts.map +0 -1
  138. package/dist/global-state.js +0 -16
  139. package/dist/global-state.js.map +0 -1
  140. package/dist/index.d.ts +0 -20
  141. package/dist/index.d.ts.map +0 -1
  142. package/dist/index.js +0 -16
  143. package/dist/index.js.map +0 -1
  144. package/dist/live-queries/db.d.ts +0 -66
  145. package/dist/live-queries/db.d.ts.map +0 -1
  146. package/dist/live-queries/db.js.map +0 -1
  147. package/dist/live-queries/db.test.d.ts +0 -2
  148. package/dist/live-queries/db.test.d.ts.map +0 -1
  149. package/dist/live-queries/db.test.js +0 -118
  150. package/dist/live-queries/db.test.js.map +0 -1
  151. package/dist/live-queries/graphql.d.ts +0 -49
  152. package/dist/live-queries/graphql.d.ts.map +0 -1
  153. package/dist/live-queries/graphql.js +0 -122
  154. package/dist/live-queries/graphql.js.map +0 -1
  155. package/dist/row-query-utils.d.ts +0 -17
  156. package/dist/row-query-utils.d.ts.map +0 -1
  157. package/dist/row-query-utils.js +0 -30
  158. package/dist/row-query-utils.js.map +0 -1
  159. package/dist/utils/otel.d.ts +0 -4
  160. package/dist/utils/otel.d.ts.map +0 -1
  161. package/dist/utils/otel.js +0 -6
  162. package/dist/utils/otel.js.map +0 -1
  163. package/src/global-state.ts +0 -20
  164. package/src/index.ts +0 -66
  165. package/src/live-queries/db.test.ts +0 -154
  166. package/src/live-queries/graphql.ts +0 -219
  167. package/src/row-query-utils.ts +0 -65
  168. package/src/utils/otel.ts +0 -9
  169. package/tsconfig.json +0 -18
  170. package/vitest.config.js +0 -9
@@ -0,0 +1,52 @@
1
+ import type { PreparedBindValues } from '@livestore/common'
2
+ import { SessionIdSymbol } from '@livestore/common'
3
+ import { State } from '@livestore/common/schema'
4
+ import { shouldNeverHappen } from '@livestore/utils'
5
+ import type * as otel from '@opentelemetry/api'
6
+
7
+ import type { ReactivityGraphContext } from './base-class.js'
8
+
9
+ export const rowQueryLabel = (
10
+ table: State.SQLite.ClientDocumentTableDef.Any,
11
+ id: string | SessionIdSymbol | undefined,
12
+ ) => `${table.sqliteDef.name}.get:${id === undefined ? table.default.id : id === SessionIdSymbol ? 'sessionId' : id}`
13
+
14
+ export const makeExecBeforeFirstRun =
15
+ ({
16
+ id,
17
+ explicitDefaultValues,
18
+ table,
19
+ otelContext: otelContext_,
20
+ }: {
21
+ id?: string | SessionIdSymbol
22
+ explicitDefaultValues?: any
23
+ table: State.SQLite.TableDefBase
24
+ otelContext: otel.Context | undefined
25
+ }) =>
26
+ ({ store }: ReactivityGraphContext) => {
27
+ if (State.SQLite.tableIsClientDocumentTable(table) === false) {
28
+ return shouldNeverHappen(
29
+ `Cannot insert row for table "${table.sqliteDef.name}" which does not have 'deriveEvents: true' set`,
30
+ )
31
+ }
32
+
33
+ const otelContext = otelContext_ ?? store.otel.queriesSpanContext
34
+
35
+ const idVal = id === SessionIdSymbol ? store.sessionId : id!
36
+ const rowExists =
37
+ store.sqliteDbWrapper.select(
38
+ `SELECT 1 FROM '${table.sqliteDef.name}' WHERE id = ?`,
39
+ [idVal] as any as PreparedBindValues,
40
+ { otelContext },
41
+ ).length === 1
42
+
43
+ if (rowExists) return
44
+
45
+ // It's important that we only commit and don't refresh here, as this function might be called during a render
46
+ // and otherwise we might end up in a "reactive loop"
47
+
48
+ store.commit(
49
+ { otelContext, skipRefresh: true, label: `${table.sqliteDef.name}.set:${idVal}` },
50
+ table.set(explicitDefaultValues, idVal as TODO),
51
+ )
52
+ }
@@ -1,68 +1,80 @@
1
- import type { QueryInfo } from '@livestore/common'
1
+ import { getDurationMsFromSpan } from '@livestore/common'
2
2
  import * as otel from '@opentelemetry/api'
3
3
 
4
- import { globalReactivityGraph } from '../global-state.js'
5
4
  import type { Thunk } from '../reactive.js'
6
5
  import type { RefreshReason } from '../store/store-types.js'
7
- import { getDurationMsFromSpan } from '../utils/otel.js'
8
- import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
9
- import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
6
+ import { isValidFunctionString } from '../utils/function-string.js'
7
+ import type { DepKey, GetAtomResult, LiveQueryDef, ReactivityGraph, ReactivityGraphContext } from './base-class.js'
8
+ import { depsToString, LiveStoreQueryBase, makeGetAtomResult, withRCMap } from './base-class.js'
10
9
 
11
- export const computed = <TResult, TQueryInfo extends QueryInfo = QueryInfo.None>(
10
+ export const computed = <TResult>(
12
11
  fn: (get: GetAtomResult) => TResult,
13
12
  options?: {
14
- label: string
15
- reactivityGraph?: ReactivityGraph
16
- queryInfo?: TQueryInfo
13
+ label?: string
14
+ deps?: DepKey
17
15
  },
18
- ): LiveQuery<TResult, TQueryInfo> =>
19
- new LiveStoreComputedQuery<TResult, TQueryInfo>({
20
- fn,
16
+ ): LiveQueryDef<TResult> => {
17
+ const hash = options?.deps ? depsToString(options.deps) : fn.toString()
18
+ if (isValidFunctionString(hash)._tag === 'invalid') {
19
+ throw new Error(`On Expo/React Native, computed queries must provide a \`deps\` option`)
20
+ }
21
+
22
+ const def: LiveQueryDef.Any = {
23
+ _tag: 'def',
24
+ make: withRCMap(hash, (ctx, _otelContext) => {
25
+ // TODO onDestroy
26
+ return new LiveStoreComputedQuery<TResult>({
27
+ fn,
28
+ label: options?.label ?? fn.toString(),
29
+ reactivityGraph: ctx.reactivityGraph.deref()!,
30
+ def,
31
+ })
32
+ }),
21
33
  label: options?.label ?? fn.toString(),
22
- reactivityGraph: options?.reactivityGraph,
23
- queryInfo: options?.queryInfo,
24
- })
25
-
26
- export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> extends LiveStoreQueryBase<
27
- TResult,
28
- TQueryInfo
29
- > {
34
+ // NOTE We're using the `makeQuery` function body string to make sure the key is unique across the app
35
+ // TODO we should figure out whether this could cause some problems and/or if there's a better way to do this
36
+ // NOTE `fn.toString()` doesn't work in Expo as it always produces `[native code]`
37
+ hash,
38
+ }
39
+
40
+ return def
41
+ }
42
+
43
+ export class LiveStoreComputedQuery<TResult> extends LiveStoreQueryBase<TResult> {
30
44
  _tag: 'computed' = 'computed'
31
45
 
32
46
  /** A reactive thunk representing the query results */
33
- results$: Thunk<TResult, QueryContext, RefreshReason>
47
+ results$: Thunk<TResult, ReactivityGraphContext, RefreshReason>
34
48
 
35
49
  label: string
36
50
 
37
- protected reactivityGraph: ReactivityGraph
38
-
39
- queryInfo: TQueryInfo
51
+ reactivityGraph: ReactivityGraph
52
+ def: LiveQueryDef<TResult>
40
53
 
41
54
  constructor({
42
55
  fn,
43
56
  label,
44
57
  reactivityGraph,
45
- queryInfo,
58
+ def,
46
59
  }: {
47
60
  label: string
48
61
  fn: (get: GetAtomResult) => TResult
49
- reactivityGraph?: ReactivityGraph
50
- queryInfo?: TQueryInfo
62
+ reactivityGraph: ReactivityGraph
63
+ def: LiveQueryDef<TResult>
51
64
  }) {
52
65
  super()
53
66
 
54
67
  this.label = label
55
-
56
- this.reactivityGraph = reactivityGraph ?? globalReactivityGraph
57
- this.queryInfo = queryInfo ?? ({ _tag: 'None' } as TQueryInfo)
68
+ this.reactivityGraph = reactivityGraph
69
+ this.def = def
58
70
 
59
71
  const queryLabel = `${label}:results`
60
72
 
61
73
  this.results$ = this.reactivityGraph.makeThunk(
62
- (get, setDebugInfo, { otelTracer, rootOtelContext }, otelContext) =>
63
- otelTracer.startActiveSpan(`js:${label}`, {}, otelContext ?? rootOtelContext, (span) => {
74
+ (get, setDebugInfo, ctx, otelContext) =>
75
+ ctx.otelTracer.startActiveSpan(`js:${label}`, {}, otelContext ?? ctx.rootOtelContext, (span) => {
64
76
  const otelContext = otel.trace.setSpan(otel.context.active(), span)
65
- const res = fn(makeGetAtomResult(get, otelContext))
77
+ const res = fn(makeGetAtomResult(get, ctx, otelContext, this.dependencyQueriesRef))
66
78
 
67
79
  span.end()
68
80
 
@@ -79,6 +91,12 @@ export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = Quer
79
91
  }
80
92
 
81
93
  destroy = () => {
94
+ this.isDestroyed = true
95
+
82
96
  this.reactivityGraph.destroyNode(this.results$)
97
+
98
+ for (const query of this.dependencyQueriesRef) {
99
+ query.deref()
100
+ }
83
101
  }
84
102
  }
@@ -0,0 +1,192 @@
1
+ import { sql } from '@livestore/common'
2
+ import { rawSqlEvent } from '@livestore/common/schema'
3
+ import { Effect, ReadonlyRecord, Schema } from '@livestore/utils/effect'
4
+ import { Vitest } from '@livestore/utils-dev/node-vitest'
5
+ import * as otel from '@opentelemetry/api'
6
+ import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
7
+ import { expect } from 'vitest'
8
+
9
+ import * as RG from '../reactive.js'
10
+ import { makeTodoMvc, tables } from '../utils/tests/fixture.js'
11
+ import { getSimplifiedRootSpan } from '../utils/tests/otel.js'
12
+ import { computed } from './computed.js'
13
+ import { queryDb } from './db-query.js'
14
+
15
+ /*
16
+ TODO write tests for:
17
+
18
+ - sql queries without and with `map` (incl. callback and schemas)
19
+ - optional and explicit `queriedTables` argument
20
+ */
21
+
22
+ Vitest.describe('otel', () => {
23
+ const mapAttributes = (attributes: otel.Attributes) => {
24
+ return ReadonlyRecord.map(attributes, (val, key) => {
25
+ if (key === 'code.stacktrace') {
26
+ return '<STACKTRACE>'
27
+ }
28
+ return val
29
+ })
30
+ }
31
+
32
+ const makeQuery = Effect.gen(function* () {
33
+ const exporter = new InMemorySpanExporter()
34
+
35
+ RG.__resetIds()
36
+
37
+ const provider = new BasicTracerProvider({
38
+ spanProcessors: [new SimpleSpanProcessor(exporter)],
39
+ })
40
+
41
+ const otelTracer = provider.getTracer('test')
42
+
43
+ const span = otelTracer.startSpan('test-root')
44
+ const otelContext = otel.trace.setSpan(otel.context.active(), span)
45
+
46
+ const store = yield* makeTodoMvc({ otelTracer, otelContext })
47
+
48
+ return {
49
+ store,
50
+ otelTracer,
51
+ exporter,
52
+ span,
53
+ provider,
54
+ }
55
+ })
56
+
57
+ Vitest.scopedLive('otel', () =>
58
+ Effect.gen(function* () {
59
+ const { store, exporter, span, provider } = yield* makeQuery
60
+
61
+ const query$ = queryDb({
62
+ query: `select * from todos`,
63
+ schema: Schema.Array(tables.todos.rowSchema),
64
+ queriedTables: new Set(['todos']),
65
+ })
66
+ expect(store.query(query$)).toMatchInlineSnapshot('[]')
67
+
68
+ store.commit(rawSqlEvent({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
69
+
70
+ expect(store.query(query$)).toMatchInlineSnapshot(`
71
+ [
72
+ {
73
+ "completed": false,
74
+ "id": "t1",
75
+ "text": "buy milk",
76
+ },
77
+ ]
78
+ `)
79
+
80
+ span.end()
81
+
82
+ return { exporter, provider }
83
+ }).pipe(
84
+ Effect.scoped,
85
+ Effect.tap(({ exporter, provider }) =>
86
+ Effect.promise(async () => {
87
+ await provider.forceFlush()
88
+ expect(getSimplifiedRootSpan(exporter, mapAttributes)).toMatchSnapshot()
89
+ await provider.shutdown()
90
+ }),
91
+ ),
92
+ ),
93
+ )
94
+
95
+ Vitest.scopedLive('with thunks', () =>
96
+ Effect.gen(function* () {
97
+ const { store, exporter, span, provider } = yield* makeQuery
98
+
99
+ const defaultTodo = { id: '', text: '', completed: false }
100
+
101
+ const filter = computed(() => `where completed = 0`, { label: 'where-filter' })
102
+ const query$ = queryDb(
103
+ (get) => ({
104
+ query: `select * from todos ${get(filter)}`,
105
+ schema: Schema.Array(tables.todos.rowSchema).pipe(Schema.headOrElse(() => defaultTodo)),
106
+ }),
107
+ { label: 'all todos' },
108
+ )
109
+
110
+ expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot()
111
+
112
+ expect(store.query(query$)).toMatchInlineSnapshot(`
113
+ {
114
+ "completed": false,
115
+ "id": "",
116
+ "text": "",
117
+ }
118
+ `)
119
+
120
+ expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot()
121
+
122
+ store.commit(rawSqlEvent({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
123
+
124
+ expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot()
125
+
126
+ expect(store.query(query$)).toMatchInlineSnapshot(`
127
+ {
128
+ "completed": false,
129
+ "id": "t1",
130
+ "text": "buy milk",
131
+ }
132
+ `)
133
+
134
+ expect(store.reactivityGraph.getSnapshot({ includeResults: true })).toMatchSnapshot()
135
+
136
+ span.end()
137
+
138
+ return { exporter, provider }
139
+ }).pipe(
140
+ Effect.scoped,
141
+ Effect.tap(({ exporter, provider }) =>
142
+ Effect.promise(async () => {
143
+ await provider.forceFlush()
144
+ expect(getSimplifiedRootSpan(exporter, mapAttributes)).toMatchSnapshot()
145
+ await provider.shutdown()
146
+ }),
147
+ ),
148
+ ),
149
+ )
150
+
151
+ Vitest.scopedLive('with thunks with query builder and without labels', () =>
152
+ Effect.gen(function* () {
153
+ const { store, exporter, span, provider } = yield* makeQuery
154
+
155
+ const defaultTodo = { id: '', text: '', completed: false }
156
+
157
+ const filter = computed(() => ({ completed: false }))
158
+ const query$ = queryDb((get) => tables.todos.where(get(filter)).first({ fallback: () => defaultTodo }))
159
+
160
+ expect(store.query(query$)).toMatchInlineSnapshot(`
161
+ {
162
+ "completed": false,
163
+ "id": "",
164
+ "text": "",
165
+ }
166
+ `)
167
+
168
+ store.commit(rawSqlEvent({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
169
+
170
+ expect(store.query(query$)).toMatchInlineSnapshot(`
171
+ {
172
+ "completed": false,
173
+ "id": "t1",
174
+ "text": "buy milk",
175
+ }
176
+ `)
177
+
178
+ span.end()
179
+
180
+ return { exporter, provider }
181
+ }).pipe(
182
+ Effect.scoped,
183
+ Effect.tap(({ exporter, provider }) =>
184
+ Effect.promise(async () => {
185
+ await provider.forceFlush()
186
+ expect(getSimplifiedRootSpan(exporter, mapAttributes)).toMatchSnapshot()
187
+ await provider.shutdown()
188
+ }),
189
+ ),
190
+ ),
191
+ )
192
+ })