@livestore/livestore 0.0.46-dev.2 → 0.0.46

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 (114) hide show
  1. package/README.md +10 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/react/fixture.d.ts +17 -1
  4. package/dist/__tests__/react/fixture.d.ts.map +1 -1
  5. package/dist/__tests__/react/fixture.js +27 -3
  6. package/dist/__tests__/react/fixture.js.map +1 -1
  7. package/dist/__tests__/react/utils/otel.d.ts +10 -0
  8. package/dist/__tests__/react/utils/otel.d.ts.map +1 -0
  9. package/dist/__tests__/react/utils/otel.js +42 -0
  10. package/dist/__tests__/react/utils/otel.js.map +1 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/react/LiveStoreProvider.js +39 -6
  15. package/dist/react/LiveStoreProvider.js.map +1 -1
  16. package/dist/react/LiveStoreProvider.test.d.ts +2 -0
  17. package/dist/react/LiveStoreProvider.test.d.ts.map +1 -0
  18. package/dist/react/LiveStoreProvider.test.js +51 -0
  19. package/dist/react/LiveStoreProvider.test.js.map +1 -0
  20. package/dist/react/components/DiffableList copy.d.ts +19 -0
  21. package/dist/react/components/DiffableList copy.d.ts.map +1 -0
  22. package/dist/react/components/DiffableList copy.js +62 -0
  23. package/dist/react/components/DiffableList copy.js.map +1 -0
  24. package/dist/react/components/DiffableList.d.ts +13 -0
  25. package/dist/react/components/DiffableList.d.ts.map +1 -0
  26. package/dist/react/components/DiffableList.js +21 -0
  27. package/dist/react/components/DiffableList.js.map +1 -0
  28. package/dist/react/components/DiffableList2.d.ts +20 -0
  29. package/dist/react/components/DiffableList2.d.ts.map +1 -0
  30. package/dist/react/components/DiffableList2.js +119 -0
  31. package/dist/react/components/DiffableList2.js.map +1 -0
  32. package/dist/react/components/DiffableList3.d.ts +19 -0
  33. package/dist/react/components/DiffableList3.d.ts.map +1 -0
  34. package/dist/react/components/DiffableList3.js +62 -0
  35. package/dist/react/components/DiffableList3.js.map +1 -0
  36. package/dist/react/components/LiveList.d.ts +21 -0
  37. package/dist/react/components/LiveList.d.ts.map +1 -0
  38. package/dist/react/components/LiveList.js +31 -0
  39. package/dist/react/components/LiveList.js.map +1 -0
  40. package/dist/react/index.d.ts +1 -0
  41. package/dist/react/index.d.ts.map +1 -1
  42. package/dist/react/index.js +1 -0
  43. package/dist/react/index.js.map +1 -1
  44. package/dist/react/useAtom.d.ts +1 -1
  45. package/dist/react/useAtom.d.ts.map +1 -1
  46. package/dist/react/useAtom.js.map +1 -1
  47. package/dist/react/useQuery.d.ts +4 -1
  48. package/dist/react/useQuery.d.ts.map +1 -1
  49. package/dist/react/useQuery.js +24 -19
  50. package/dist/react/useQuery.js.map +1 -1
  51. package/dist/react/useQuery.test.js +11 -11
  52. package/dist/react/useQuery.test.js.map +1 -1
  53. package/dist/react/useRow.d.ts.map +1 -1
  54. package/dist/react/useRow.js +14 -69
  55. package/dist/react/useRow.js.map +1 -1
  56. package/dist/react/useRow.test.js +440 -28
  57. package/dist/react/useRow.test.js.map +1 -1
  58. package/dist/react/useRowOld.d.ts +40 -0
  59. package/dist/react/useRowOld.d.ts.map +1 -0
  60. package/dist/react/useRowOld.js +134 -0
  61. package/dist/react/useRowOld.js.map +1 -0
  62. package/dist/react/useTemporaryQuery.d.ts +15 -3
  63. package/dist/react/useTemporaryQuery.d.ts.map +1 -1
  64. package/dist/react/useTemporaryQuery.js +60 -27
  65. package/dist/react/useTemporaryQuery.js.map +1 -1
  66. package/dist/react/useTemporaryQuery.test.js +10 -9
  67. package/dist/react/useTemporaryQuery.test.js.map +1 -1
  68. package/dist/reactive.d.ts +23 -5
  69. package/dist/reactive.d.ts.map +1 -1
  70. package/dist/reactive.js +44 -11
  71. package/dist/reactive.js.map +1 -1
  72. package/dist/reactive.test.js +1 -1
  73. package/dist/reactive.test.js.map +1 -1
  74. package/dist/reactiveQueries/base-class.d.ts +1 -1
  75. package/dist/reactiveQueries/base-class.d.ts.map +1 -1
  76. package/dist/reactiveQueries/base-class.js.map +1 -1
  77. package/dist/reactiveQueries/graphql.d.ts +2 -2
  78. package/dist/reactiveQueries/graphql.d.ts.map +1 -1
  79. package/dist/reactiveQueries/graphql.js +16 -10
  80. package/dist/reactiveQueries/graphql.js.map +1 -1
  81. package/dist/reactiveQueries/sql.d.ts +1 -1
  82. package/dist/reactiveQueries/sql.d.ts.map +1 -1
  83. package/dist/reactiveQueries/sql.js +15 -11
  84. package/dist/reactiveQueries/sql.js.map +1 -1
  85. package/dist/reactiveQueries/sql.test.js +1 -40
  86. package/dist/reactiveQueries/sql.test.js.map +1 -1
  87. package/dist/store.d.ts +2 -2
  88. package/dist/store.d.ts.map +1 -1
  89. package/dist/store.js +10 -7
  90. package/dist/store.js.map +1 -1
  91. package/package.json +6 -6
  92. package/src/__tests__/react/fixture.tsx +35 -2
  93. package/src/__tests__/react/utils/otel.ts +61 -0
  94. package/src/index.ts +12 -1
  95. package/src/react/LiveStoreProvider.test.tsx +82 -0
  96. package/src/react/LiveStoreProvider.tsx +42 -7
  97. package/src/react/components/LiveList.tsx +84 -0
  98. package/src/react/index.ts +2 -0
  99. package/src/react/useAtom.ts +1 -1
  100. package/src/react/useQuery.test.tsx +11 -11
  101. package/src/react/useQuery.ts +29 -22
  102. package/src/react/useRow.test.tsx +502 -30
  103. package/src/react/useRow.ts +19 -107
  104. package/src/react/useTemporaryQuery.test.tsx +17 -16
  105. package/src/react/useTemporaryQuery.ts +96 -28
  106. package/src/reactive.test.ts +1 -1
  107. package/src/reactive.ts +76 -15
  108. package/src/reactiveQueries/base-class.ts +2 -1
  109. package/src/reactiveQueries/graphql.ts +21 -15
  110. package/src/reactiveQueries/sql.test.ts +1 -54
  111. package/src/reactiveQueries/sql.ts +20 -14
  112. package/src/store.ts +12 -8
  113. package/tsconfig.json +6 -1
  114. package/src/react/utils/useCleanup.ts +0 -25
@@ -1,9 +1,9 @@
1
1
  import * as otel from '@opentelemetry/api'
2
- import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'
3
2
  import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
4
3
  import { describe, expect, it } from 'vitest'
5
4
 
6
5
  import { makeTodoMvc, todos } from '../__tests__/react/fixture.js'
6
+ import { getSimplifiedRootSpan } from '../__tests__/react/utils/otel.js'
7
7
  import { computed, ParseUtils, querySQL, rawSqlMutation, sql } from '../index.js'
8
8
 
9
9
  /*
@@ -299,56 +299,3 @@ describe('otel', () => {
299
299
  `)
300
300
  })
301
301
  })
302
-
303
- const compareHrTime = (a: [number, number], b: [number, number]) => {
304
- if (a[0] !== b[0]) return a[0] - b[0]
305
- return a[1] - b[1]
306
- }
307
-
308
- const omitEmpty = (obj: any) => {
309
- const result: any = {}
310
- for (const key in obj) {
311
- if (
312
- obj[key] !== undefined &&
313
- !(Array.isArray(obj[key]) && obj[key].length === 0) &&
314
- Object.keys(obj[key]).length > 0
315
- ) {
316
- result[key] = obj[key]
317
- }
318
- }
319
- return result
320
- }
321
-
322
- const getSimplifiedRootSpan = (exporter: InMemorySpanExporter) => {
323
- const spans = exporter.getFinishedSpans()
324
- const spansMap = new Map<string, NestedSpan>(spans.map((span) => [span.spanContext().spanId, { span, children: [] }]))
325
-
326
- spansMap.forEach((nestedSpan) => {
327
- const parentSpan = nestedSpan.span.parentSpanId ? spansMap.get(nestedSpan.span.parentSpanId) : undefined
328
- if (parentSpan) {
329
- parentSpan.children.push(nestedSpan)
330
- }
331
- })
332
-
333
- type NestedSpan = { span: ReadableSpan; children: NestedSpan[] }
334
- const rootSpan = spansMap.get(spans.find((_) => _.name === 'test')!.spanContext().spanId)!
335
-
336
- type SimplifiedNestedSpan = { _name: string; attributes: any; children: SimplifiedNestedSpan[] }
337
-
338
- const simplifySpan = (span: NestedSpan): SimplifiedNestedSpan =>
339
- omitEmpty({
340
- _name: span.span.name,
341
- attributes: span.span.attributes,
342
- children: span.children
343
- .filter((_) => _.span.name !== 'createStore')
344
- .sort((a, b) => compareHrTime(a.span.startTime, b.span.startTime))
345
- .map(simplifySpan),
346
- })
347
-
348
- // console.dir(
349
- // spans.map((_) => [_.spanContext().spanId, _.name, _.attributes, _.parentSpanId]),
350
- // { depth: 10 },
351
- // )
352
-
353
- return simplifySpan(rootSpan)
354
- }
@@ -49,7 +49,7 @@ export class LiveStoreSQLQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo
49
49
  _tag: 'sql' = 'sql'
50
50
 
51
51
  /** A reactive thunk representing the query text */
52
- queryString$: Thunk<string, DbContext, RefreshReason>
52
+ queryString$: Thunk<string, DbContext, RefreshReason> | undefined
53
53
 
54
54
  /** A reactive thunk representing the query results */
55
55
  results$: Thunk<TResult, DbContext, RefreshReason>
@@ -126,23 +126,23 @@ Result:`,
126
126
  ? map
127
127
  : shouldNeverHappen(`Invalid map function ${map}`)
128
128
 
129
- // TODO don't even create a thunk if query string is static
130
- const queryString$ = this.dbGraph.makeThunk(
131
- (get, setDebugInfo, { rootOtelContext }, otelContext) => {
132
- if (typeof genQueryString === 'function') {
129
+ let queryString$OrQueryString: string | Thunk<string, DbContext, RefreshReason>
130
+ if (typeof genQueryString === 'function') {
131
+ queryString$OrQueryString = this.dbGraph.makeThunk(
132
+ (get, setDebugInfo, { rootOtelContext }, otelContext) => {
133
133
  const startMs = performance.now()
134
134
  const queryString = genQueryString(makeGetAtomResult(get, otelContext ?? rootOtelContext))
135
135
  const durationMs = performance.now() - startMs
136
136
  setDebugInfo({ _tag: 'js', label: `${label}:queryString`, query: queryString, durationMs })
137
137
  return queryString
138
- } else {
139
- return genQueryString
140
- }
141
- },
142
- { label: `${label}:queryString`, meta: { liveStoreThunkType: 'sqlQueryString' } },
143
- )
138
+ },
139
+ { label: `${label}:queryString`, meta: { liveStoreThunkType: 'sqlQueryString' } },
140
+ )
144
141
 
145
- this.queryString$ = queryString$
142
+ this.queryString$ = queryString$OrQueryString
143
+ } else {
144
+ queryString$OrQueryString = genQueryString
145
+ }
146
146
 
147
147
  const queryLabel = `${label}:results`
148
148
 
@@ -162,7 +162,10 @@ Result:`,
162
162
  this.execBeforeFirstRun = undefined
163
163
  }
164
164
 
165
- const sqlString = get(queryString$, otelContext)
165
+ const sqlString =
166
+ typeof queryString$OrQueryString === 'string'
167
+ ? queryString$OrQueryString
168
+ : get(queryString$OrQueryString, otelContext)
166
169
 
167
170
  if (queriedTablesRef.current === undefined) {
168
171
  queriedTablesRef.current = store.mainDbWrapper.getTablesUsed(sqlString)
@@ -238,7 +241,10 @@ Result:`,
238
241
  // })
239
242
 
240
243
  destroy = () => {
241
- this.dbGraph.destroyNode(this.queryString$)
244
+ if (this.queryString$ !== undefined) {
245
+ this.dbGraph.destroyNode(this.queryString$)
246
+ }
247
+
242
248
  this.dbGraph.destroyNode(this.results$)
243
249
  }
244
250
  }
package/src/store.ts CHANGED
@@ -184,22 +184,23 @@ export class Store<
184
184
  * Returns a function to cancel the subscription.
185
185
  */
186
186
  subscribe = <TResult>(
187
- query: LiveQuery<TResult, any>,
187
+ query$: LiveQuery<TResult, any>,
188
188
  onNewValue: (value: TResult) => void,
189
189
  onUnsubsubscribe?: () => void,
190
190
  options?: { label?: string; otelContext?: otel.Context; skipInitialRun?: boolean } | undefined,
191
191
  ): (() => void) =>
192
192
  this.otel.tracer.startActiveSpan(
193
193
  `LiveStore.subscribe`,
194
- { attributes: { label: options?.label, queryLabel: query.label } },
194
+ { attributes: { label: options?.label, queryLabel: query$.label } },
195
195
  options?.otelContext ?? this.otel.queriesSpanContext,
196
196
  (span) => {
197
+ // console.log('store sub', query$.label)
197
198
  const otelContext = otel.trace.setSpan(otel.context.active(), span)
198
199
 
199
200
  const label = `subscribe:${options?.label}`
200
- const effect = this.graph.makeEffect((get) => onNewValue(get(query.results$)), { label })
201
+ const effect = this.graph.makeEffect((get) => onNewValue(get(query$.results$)), { label })
201
202
 
202
- this.activeQueries.add(query as LiveQuery<TResult>)
203
+ this.activeQueries.add(query$ as LiveQuery<TResult>)
203
204
 
204
205
  // Running effect right away to get initial value (unless `skipInitialRun` is set)
205
206
  if (options?.skipInitialRun !== true) {
@@ -207,9 +208,10 @@ export class Store<
207
208
  }
208
209
 
209
210
  const unsubscribe = () => {
211
+ // console.log('store unsub', query$.label)
210
212
  try {
211
213
  this.graph.destroyNode(effect)
212
- this.activeQueries.remove(query as LiveQuery<TResult>)
214
+ this.activeQueries.remove(query$ as LiveQuery<TResult>)
213
215
  onUnsubsubscribe?.()
214
216
  } finally {
215
217
  span.end()
@@ -225,7 +227,7 @@ export class Store<
225
227
  *
226
228
  * Currently only used when shutting down the app for debugging purposes (e.g. to close Otel spans).
227
229
  */
228
- destroy = () => {
230
+ destroy = async () => {
229
231
  for (const tableRef of Object.values(this.tableRefs)) {
230
232
  for (const superComp of tableRef.super) {
231
233
  this.graph.removeEdge(superComp, tableRef)
@@ -234,6 +236,8 @@ export class Store<
234
236
 
235
237
  otel.trace.getSpan(this.otel.mutationsSpanContext)!.end()
236
238
  otel.trace.getSpan(this.otel.queriesSpanContext)!.end()
239
+
240
+ await this.db.storageDb.shutdown()
237
241
  }
238
242
 
239
243
  mutate: {
@@ -540,11 +544,11 @@ export const createStore = async <
540
544
 
541
545
  db.mainDb.execute('COMMIT', undefined)
542
546
 
543
- db.storageDb.execute('BEGIN', undefined, undefined)
547
+ // db.storageDb.execute('BEGIN', undefined, undefined)
544
548
  for (const [queryStr, bindValues] of txnExecuteStmnts) {
545
549
  db.storageDb.execute(queryStr, bindValues, undefined)
546
550
  }
547
- db.storageDb.execute('COMMIT', undefined, undefined)
551
+ // db.storageDb.execute('COMMIT', undefined, undefined)
548
552
  } catch (e: any) {
549
553
  db.mainDb.execute('ROLLBACK', undefined)
550
554
  throw e
package/tsconfig.json CHANGED
@@ -9,5 +9,10 @@
9
9
  "tsBuildInfoFile": "./dist/.tsbuildinfo"
10
10
  },
11
11
  "include": ["./src"],
12
- "references": [{ "path": "../../effect-db-schema" }, { "path": "../common" }, { "path": "../web" }, { "path": "../utils" }]
12
+ "references": [
13
+ { "path": "../../effect-db-schema" },
14
+ { "path": "../common" },
15
+ { "path": "../web" },
16
+ { "path": "../utils" }
17
+ ]
13
18
  }
@@ -1,25 +0,0 @@
1
- import React from 'react'
2
-
3
- /**
4
- * Like cleanup callback of `React.useEffect` but running as part of the render loop.
5
- *
6
- * NOTE: This hook should not be used with React strict mode.
7
- */
8
- export const useCleanup = (
9
- /** Needs to be a `React.useCallback` value */
10
- cleanupCallback: () => void,
11
- ) => {
12
- const callbackRef = React.useRef(cleanupCallback)
13
-
14
- if (callbackRef.current !== cleanupCallback) {
15
- callbackRef.current()
16
- callbackRef.current = cleanupCallback
17
- }
18
-
19
- React.useEffect(
20
- () => () => {
21
- callbackRef.current()
22
- },
23
- [],
24
- )
25
- }