@livestore/livestore 0.3.0-dev.28 → 0.3.0-dev.30
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/SqliteDbWrapper.d.ts.map +1 -1
- package/dist/SqliteDbWrapper.js +4 -1
- package/dist/SqliteDbWrapper.js.map +1 -1
- package/dist/live-queries/base-class.d.ts +8 -12
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js.map +1 -1
- package/dist/live-queries/client-document-get-query.d.ts +12 -0
- package/dist/live-queries/client-document-get-query.d.ts.map +1 -0
- package/dist/live-queries/client-document-get-query.js +18 -0
- package/dist/live-queries/client-document-get-query.js.map +1 -0
- package/dist/live-queries/computed.d.ts +4 -8
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +1 -6
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts +13 -18
- package/dist/live-queries/db-query.d.ts.map +1 -1
- package/dist/live-queries/db-query.js +34 -34
- package/dist/live-queries/db-query.js.map +1 -1
- package/dist/live-queries/db-query.test.js +32 -23
- package/dist/live-queries/db-query.test.js.map +1 -1
- package/dist/live-queries/make-ref.d.ts.map +1 -1
- package/dist/live-queries/make-ref.js +1 -0
- package/dist/live-queries/make-ref.js.map +1 -1
- package/dist/mod.d.ts +0 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +0 -1
- package/dist/mod.js.map +1 -1
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +1 -1
- package/dist/reactive.js.map +1 -1
- package/dist/store/create-store.js +2 -2
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/store-types.d.ts +5 -5
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store.d.ts +27 -26
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +74 -69
- package/dist/store/store.js.map +1 -1
- package/dist/utils/stack-info.test.js +6 -6
- package/dist/utils/tests/fixture.d.ts +54 -207
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/dist/utils/tests/fixture.js +20 -13
- package/dist/utils/tests/fixture.js.map +1 -1
- package/dist/utils/tests/otel.d.ts.map +1 -1
- package/dist/utils/tests/otel.js +8 -3
- package/dist/utils/tests/otel.js.map +1 -1
- package/package.json +7 -7
- package/src/SqliteDbWrapper.ts +4 -1
- package/src/live-queries/__snapshots__/db-query.test.ts.snap +9 -9
- package/src/live-queries/base-class.ts +8 -25
- package/src/live-queries/client-document-get-query.ts +52 -0
- package/src/live-queries/computed.ts +4 -18
- package/src/live-queries/db-query.test.ts +38 -24
- package/src/live-queries/db-query.ts +60 -66
- package/src/live-queries/make-ref.ts +2 -0
- package/src/mod.ts +0 -2
- package/src/reactive.ts +1 -1
- package/src/store/create-store.ts +2 -2
- package/src/store/store-types.ts +5 -5
- package/src/store/store.ts +97 -91
- package/src/utils/stack-info.test.ts +6 -6
- package/src/utils/tests/fixture.ts +21 -25
- package/src/utils/tests/otel.ts +10 -3
- package/tmp/pack.tgz +0 -0
- package/dist/row-query-utils.d.ts +0 -17
- package/dist/row-query-utils.d.ts.map +0 -1
- package/dist/row-query-utils.js +0 -34
- package/dist/row-query-utils.js.map +0 -1
- package/src/row-query-utils.ts +0 -76
package/src/store/store.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
import {
|
|
10
10
|
Devtools,
|
|
11
11
|
getDurationMsFromSpan,
|
|
12
|
-
|
|
12
|
+
getExecArgsFromEvent,
|
|
13
13
|
getResultSchema,
|
|
14
14
|
IntentionalShutdownCause,
|
|
15
15
|
isQueryBuilder,
|
|
@@ -21,16 +21,16 @@ import {
|
|
|
21
21
|
} from '@livestore/common'
|
|
22
22
|
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
23
23
|
import {
|
|
24
|
-
|
|
24
|
+
getEventDef,
|
|
25
25
|
LEADER_MERGE_COUNTER_TABLE,
|
|
26
|
-
|
|
26
|
+
LiveStoreEvent,
|
|
27
|
+
SCHEMA_EVENT_DEFS_META_TABLE,
|
|
27
28
|
SCHEMA_META_TABLE,
|
|
28
|
-
SCHEMA_MUTATIONS_META_TABLE,
|
|
29
29
|
SESSION_CHANGESET_META_TABLE,
|
|
30
30
|
} from '@livestore/common/schema'
|
|
31
31
|
import { assertNever, isDevEnv } from '@livestore/utils'
|
|
32
32
|
import type { Scope } from '@livestore/utils/effect'
|
|
33
|
-
import { Cause, Effect, Inspectable, OtelTracer,
|
|
33
|
+
import { Cause, Effect, Inspectable, OtelTracer, Runtime, Schema, Stream } from '@livestore/utils/effect'
|
|
34
34
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
35
35
|
import * as otel from '@opentelemetry/api'
|
|
36
36
|
|
|
@@ -42,13 +42,13 @@ import type {
|
|
|
42
42
|
ReactivityGraphContext,
|
|
43
43
|
} from '../live-queries/base-class.js'
|
|
44
44
|
import { makeReactivityGraph } from '../live-queries/base-class.js'
|
|
45
|
+
import { makeExecBeforeFirstRun } from '../live-queries/client-document-get-query.js'
|
|
45
46
|
import type { Ref } from '../reactive.js'
|
|
46
|
-
import { makeExecBeforeFirstRun } from '../row-query-utils.js'
|
|
47
47
|
import { SqliteDbWrapper } from '../SqliteDbWrapper.js'
|
|
48
48
|
import { ReferenceCountedSet } from '../utils/data-structures.js'
|
|
49
49
|
import { downloadBlob, exposeDebugUtils } from '../utils/dev.js'
|
|
50
50
|
import type { StackInfo } from '../utils/stack-info.js'
|
|
51
|
-
import type { RefreshReason,
|
|
51
|
+
import type { RefreshReason, StoreCommitOptions, StoreOptions, StoreOtel, Unsubscribe } from './store-types.js'
|
|
52
52
|
|
|
53
53
|
if (isDevEnv()) {
|
|
54
54
|
exposeDebugUtils()
|
|
@@ -76,8 +76,8 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
76
76
|
/** RC-based set to see which queries are currently subscribed to */
|
|
77
77
|
activeQueries: ReferenceCountedSet<LiveQuery<any>>
|
|
78
78
|
|
|
79
|
-
// NOTE this is currently exposed for the Devtools databrowser to
|
|
80
|
-
readonly
|
|
79
|
+
// NOTE this is currently exposed for the Devtools databrowser to commit events
|
|
80
|
+
readonly __eventSchema
|
|
81
81
|
readonly syncProcessor: ClientSessionSyncProcessor
|
|
82
82
|
|
|
83
83
|
readonly boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
|
|
@@ -114,12 +114,12 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
114
114
|
schema,
|
|
115
115
|
clientSession,
|
|
116
116
|
runtime: effectContext.runtime,
|
|
117
|
-
|
|
118
|
-
const
|
|
117
|
+
applyEvent: (eventDecoded, { otelContext, withChangeset }) => {
|
|
118
|
+
const eventDef = getEventDef(schema, eventDecoded.name)
|
|
119
119
|
|
|
120
|
-
const execArgsArr =
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
const execArgsArr = getExecArgsFromEvent({
|
|
121
|
+
eventDef,
|
|
122
|
+
event: { decoded: eventDecoded, encoded: undefined },
|
|
123
123
|
})
|
|
124
124
|
|
|
125
125
|
const writeTablesForEvent = new Set<string>()
|
|
@@ -168,14 +168,14 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
168
168
|
confirmUnsavedChanges,
|
|
169
169
|
})
|
|
170
170
|
|
|
171
|
-
this.
|
|
171
|
+
this.__eventSchema = LiveStoreEvent.makeEventDefSchemaMemo(schema)
|
|
172
172
|
|
|
173
173
|
// TODO generalize the `tableRefs` concept to allow finer-grained refs
|
|
174
174
|
this.tableRefs = {}
|
|
175
175
|
this.activeQueries = new ReferenceCountedSet()
|
|
176
176
|
|
|
177
|
-
const
|
|
178
|
-
const otelMuationsSpanContext = otel.trace.setSpan(otel.context.active(),
|
|
177
|
+
const commitsSpan = otelOptions.tracer.startSpan('LiveStore:commits', {}, otelOptions.rootSpanContext)
|
|
178
|
+
const otelMuationsSpanContext = otel.trace.setSpan(otel.context.active(), commitsSpan)
|
|
179
179
|
|
|
180
180
|
const queriesSpan = otelOptions.tracer.startSpan('LiveStore:queries', {}, otelOptions.rootSpanContext)
|
|
181
181
|
const otelQueriesSpanContext = otel.trace.setSpan(otel.context.active(), queriesSpan)
|
|
@@ -192,20 +192,20 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
192
192
|
|
|
193
193
|
this.otel = {
|
|
194
194
|
tracer: otelOptions.tracer,
|
|
195
|
-
|
|
195
|
+
commitsSpanContext: otelMuationsSpanContext,
|
|
196
196
|
queriesSpanContext: otelQueriesSpanContext,
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// Need a set here since `schema.tables` might contain duplicates and some componentStateTables
|
|
200
200
|
const allTableNames = new Set(
|
|
201
|
-
// NOTE we're excluding the LiveStore schema and
|
|
201
|
+
// NOTE we're excluding the LiveStore schema and events tables as they are not user-facing
|
|
202
202
|
// unless LiveStore is running in the devtools
|
|
203
203
|
__runningInDevtools
|
|
204
204
|
? this.schema.tables.keys()
|
|
205
205
|
: Array.from(this.schema.tables.keys()).filter(
|
|
206
206
|
(_) =>
|
|
207
207
|
_ !== SCHEMA_META_TABLE &&
|
|
208
|
-
_ !==
|
|
208
|
+
_ !== SCHEMA_EVENT_DEFS_META_TABLE &&
|
|
209
209
|
_ !== SESSION_CHANGESET_META_TABLE &&
|
|
210
210
|
_ !== LEADER_MERGE_COUNTER_TABLE,
|
|
211
211
|
),
|
|
@@ -231,7 +231,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
231
231
|
|
|
232
232
|
// End the otel spans
|
|
233
233
|
syncSpan.end()
|
|
234
|
-
|
|
234
|
+
commitsSpan.end()
|
|
235
235
|
queriesSpan.end()
|
|
236
236
|
}),
|
|
237
237
|
)
|
|
@@ -259,11 +259,11 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
259
259
|
* ```
|
|
260
260
|
*/
|
|
261
261
|
subscribe = <TResult>(
|
|
262
|
-
query: LiveQueryDef<TResult
|
|
262
|
+
query: LiveQueryDef<TResult> | LiveQuery<TResult>,
|
|
263
263
|
options: {
|
|
264
264
|
/** Called when the query result has changed */
|
|
265
265
|
onUpdate: (value: TResult) => void
|
|
266
|
-
onSubscribe?: (query$: LiveQuery<TResult
|
|
266
|
+
onSubscribe?: (query$: LiveQuery<TResult>) => void
|
|
267
267
|
/** Gets called after the query subscription has been removed */
|
|
268
268
|
onUnsubsubscribe?: () => void
|
|
269
269
|
label?: string
|
|
@@ -337,7 +337,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
337
337
|
)
|
|
338
338
|
|
|
339
339
|
subscribeStream = <TResult>(
|
|
340
|
-
query$: LiveQueryDef<TResult
|
|
340
|
+
query$: LiveQueryDef<TResult>,
|
|
341
341
|
options?: { label?: string; skipInitialRun?: boolean } | undefined,
|
|
342
342
|
): Stream.Stream<TResult> =>
|
|
343
343
|
Stream.asyncPush<TResult>((emit) =>
|
|
@@ -377,8 +377,8 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
377
377
|
query = <TResult>(
|
|
378
378
|
query:
|
|
379
379
|
| QueryBuilder<TResult, any, any>
|
|
380
|
-
| LiveQuery<TResult
|
|
381
|
-
| LiveQueryDef<TResult
|
|
380
|
+
| LiveQuery<TResult>
|
|
381
|
+
| LiveQueryDef<TResult>
|
|
382
382
|
| { query: string; bindValues: ParamsObject },
|
|
383
383
|
options?: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason },
|
|
384
384
|
): TResult => {
|
|
@@ -392,7 +392,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
392
392
|
makeExecBeforeFirstRun({
|
|
393
393
|
table: ast.tableDef,
|
|
394
394
|
id: ast.id,
|
|
395
|
-
|
|
395
|
+
explicitDefaultValues: ast.explicitDefaultValues,
|
|
396
396
|
otelContext: options?.otelContext,
|
|
397
397
|
})(this.reactivityGraph.context!)
|
|
398
398
|
}
|
|
@@ -415,6 +415,8 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
+
atom = (): TODO => {}
|
|
419
|
+
|
|
418
420
|
// makeLive: {
|
|
419
421
|
// <T>(def: LiveQueryDef<T, any>): LiveQuery<T, any>
|
|
420
422
|
// <T>(def: ILiveQueryRefDef<T>): ILiveQueryRef<T>
|
|
@@ -434,42 +436,42 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
434
436
|
|
|
435
437
|
// #region commit
|
|
436
438
|
/**
|
|
437
|
-
* Commit a list of
|
|
438
|
-
* and sync the
|
|
439
|
+
* Commit a list of events to the store which will immediately update the local database
|
|
440
|
+
* and sync the events across other clients (similar to a `git commit`).
|
|
439
441
|
*
|
|
440
442
|
* @example
|
|
441
443
|
* ```ts
|
|
442
|
-
* store.commit(
|
|
444
|
+
* store.commit(events.todoCreated({ id: nanoid(), text: 'Make coffee' }))
|
|
443
445
|
* ```
|
|
444
446
|
*
|
|
445
|
-
* You can call `commit` with multiple
|
|
447
|
+
* You can call `commit` with multiple events to apply them in a single database transaction.
|
|
446
448
|
*
|
|
447
449
|
* @example
|
|
448
450
|
* ```ts
|
|
449
451
|
* const todoId = nanoid()
|
|
450
452
|
* store.commit(
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
+
* events.todoCreated({ id: todoId, text: 'Make coffee' }),
|
|
454
|
+
* events.todoCompleted({ id: todoId }))
|
|
453
455
|
* ```
|
|
454
456
|
*
|
|
455
457
|
* For more advanced transaction scenarios, you can pass a synchronous function to `commit` which will receive a callback
|
|
456
|
-
* to which you can pass multiple
|
|
457
|
-
* Under the hood this will simply collect all
|
|
458
|
+
* to which you can pass multiple events to be committed in the same database transaction.
|
|
459
|
+
* Under the hood this will simply collect all events and apply them in a single database transaction.
|
|
458
460
|
*
|
|
459
461
|
* @example
|
|
460
462
|
* ```ts
|
|
461
463
|
* store.commit((commit) => {
|
|
462
464
|
* const todoId = nanoid()
|
|
463
465
|
* if (Math.random() > 0.5) {
|
|
464
|
-
* commit(
|
|
466
|
+
* commit(events.todoCreated({ id: todoId, text: 'Make coffee' }))
|
|
465
467
|
* } else {
|
|
466
|
-
* commit(
|
|
468
|
+
* commit(events.todoCompleted({ id: todoId }))
|
|
467
469
|
* }
|
|
468
470
|
* })
|
|
469
471
|
* ```
|
|
470
472
|
*
|
|
471
|
-
* When committing a large batch of
|
|
472
|
-
* and call `store.manualRefresh()` after all
|
|
473
|
+
* When committing a large batch of events, you can also skip the database refresh to improve performance
|
|
474
|
+
* and call `store.manualRefresh()` after all events have been committed.
|
|
473
475
|
*
|
|
474
476
|
* @example
|
|
475
477
|
* ```ts
|
|
@@ -479,44 +481,44 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
479
481
|
* // ... 1000 more todos
|
|
480
482
|
* ]
|
|
481
483
|
* for (const todo of todos) {
|
|
482
|
-
* store.commit({ skipRefresh: true },
|
|
484
|
+
* store.commit({ skipRefresh: true }, events.todoCreated({ id: todo.id, text: todo.text }))
|
|
483
485
|
* }
|
|
484
486
|
* store.manualRefresh()
|
|
485
487
|
* ```
|
|
486
488
|
*/
|
|
487
489
|
commit: {
|
|
488
|
-
<const
|
|
490
|
+
<const TCommitArg extends ReadonlyArray<LiveStoreEvent.PartialForSchema<TSchema>>>(...list: TCommitArg): void
|
|
489
491
|
(
|
|
490
|
-
txn: <const
|
|
491
|
-
...list:
|
|
492
|
+
txn: <const TCommitArg extends ReadonlyArray<LiveStoreEvent.PartialForSchema<TSchema>>>(
|
|
493
|
+
...list: TCommitArg
|
|
492
494
|
) => void,
|
|
493
495
|
): void
|
|
494
|
-
<const
|
|
495
|
-
options:
|
|
496
|
-
...list:
|
|
496
|
+
<const TCommitArg extends ReadonlyArray<LiveStoreEvent.PartialForSchema<TSchema>>>(
|
|
497
|
+
options: StoreCommitOptions,
|
|
498
|
+
...list: TCommitArg
|
|
497
499
|
): void
|
|
498
500
|
(
|
|
499
|
-
options:
|
|
500
|
-
txn: <const
|
|
501
|
-
...list:
|
|
501
|
+
options: StoreCommitOptions,
|
|
502
|
+
txn: <const TCommitArg extends ReadonlyArray<LiveStoreEvent.PartialForSchema<TSchema>>>(
|
|
503
|
+
...list: TCommitArg
|
|
502
504
|
) => void,
|
|
503
505
|
): void
|
|
504
|
-
} = (
|
|
505
|
-
const {
|
|
506
|
+
} = (firstEventOrTxnFnOrOptions: any, ...restEvents: any[]) => {
|
|
507
|
+
const { events, options } = this.getCommitArgs(firstEventOrTxnFnOrOptions, restEvents)
|
|
506
508
|
|
|
507
|
-
for (const
|
|
508
|
-
replaceSessionIdSymbol(
|
|
509
|
+
for (const event of events) {
|
|
510
|
+
replaceSessionIdSymbol(event.args, this.clientSession.sessionId)
|
|
509
511
|
}
|
|
510
512
|
|
|
511
|
-
if (
|
|
513
|
+
if (events.length === 0) return
|
|
512
514
|
|
|
513
515
|
const skipRefresh = options?.skipRefresh ?? false
|
|
514
516
|
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
+
const commitsSpan = otel.trace.getSpan(this.otel.commitsSpanContext)!
|
|
518
|
+
commitsSpan.addEvent('commit')
|
|
517
519
|
|
|
518
520
|
// console.group('LiveStore.commit', { skipRefresh, wasSyncMessage, label })
|
|
519
|
-
//
|
|
521
|
+
// events.forEach((_) => console.debug(_.name, _.id, _.args))
|
|
520
522
|
// console.groupEnd()
|
|
521
523
|
|
|
522
524
|
let durationMs: number
|
|
@@ -525,26 +527,26 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
525
527
|
'LiveStore:commit',
|
|
526
528
|
{
|
|
527
529
|
attributes: {
|
|
528
|
-
'livestore.
|
|
529
|
-
'livestore.
|
|
530
|
+
'livestore.eventsCount': events.length,
|
|
531
|
+
'livestore.eventTags': events.map((_) => _.name),
|
|
530
532
|
'livestore.commitLabel': options?.label,
|
|
531
533
|
},
|
|
532
534
|
links: options?.spanLinks,
|
|
533
535
|
},
|
|
534
|
-
options?.otelContext ?? this.otel.
|
|
536
|
+
options?.otelContext ?? this.otel.commitsSpanContext,
|
|
535
537
|
(span) => {
|
|
536
538
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
537
539
|
|
|
538
540
|
try {
|
|
539
541
|
const { writeTables } = (() => {
|
|
540
542
|
try {
|
|
541
|
-
const
|
|
543
|
+
const applyEvents = () => this.syncProcessor.push(events, { otelContext })
|
|
542
544
|
|
|
543
|
-
if (
|
|
545
|
+
if (events.length > 1) {
|
|
544
546
|
// TODO: what to do about leader transaction here?
|
|
545
|
-
return this.sqliteDbWrapper.txn(
|
|
547
|
+
return this.sqliteDbWrapper.txn(applyEvents)
|
|
546
548
|
} else {
|
|
547
|
-
return
|
|
549
|
+
return applyEvents()
|
|
548
550
|
}
|
|
549
551
|
} catch (e: any) {
|
|
550
552
|
console.error(e)
|
|
@@ -564,7 +566,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
564
566
|
|
|
565
567
|
const debugRefreshReason = {
|
|
566
568
|
_tag: 'commit' as const,
|
|
567
|
-
|
|
569
|
+
events,
|
|
568
570
|
writeTables: Array.from(writeTables),
|
|
569
571
|
}
|
|
570
572
|
|
|
@@ -587,7 +589,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
587
589
|
// #endregion commit
|
|
588
590
|
|
|
589
591
|
/**
|
|
590
|
-
* This can be used in combination with `skipRefresh` when
|
|
592
|
+
* This can be used in combination with `skipRefresh` when committing events.
|
|
591
593
|
* We might need a better solution for this. Let's see.
|
|
592
594
|
*/
|
|
593
595
|
manualRefresh = (options?: { label?: string }) => {
|
|
@@ -595,7 +597,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
595
597
|
this.otel.tracer.startActiveSpan(
|
|
596
598
|
'LiveStore:manualRefresh',
|
|
597
599
|
{ attributes: { 'livestore.manualRefreshLabel': label } },
|
|
598
|
-
this.otel.
|
|
600
|
+
this.otel.commitsSpanContext,
|
|
599
601
|
(span) => {
|
|
600
602
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
601
603
|
this.reactivityGraph.runDeferredEffects({ otelContext })
|
|
@@ -624,10 +626,10 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
624
626
|
}).pipe(this.runEffectFork)
|
|
625
627
|
},
|
|
626
628
|
|
|
627
|
-
|
|
629
|
+
downloadEventlogDb: () => {
|
|
628
630
|
Effect.gen(this, function* () {
|
|
629
|
-
const data = yield* this.clientSession.leaderThread.
|
|
630
|
-
downloadBlob(data, `livestore-
|
|
631
|
+
const data = yield* this.clientSession.leaderThread.getEventlogData
|
|
632
|
+
downloadBlob(data, `livestore-eventlog-${Date.now()}.db`)
|
|
631
633
|
}).pipe(this.runEffectFork)
|
|
632
634
|
},
|
|
633
635
|
|
|
@@ -668,36 +670,40 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema, TContext =
|
|
|
668
670
|
Runtime.runFork(this.effectContext.runtime),
|
|
669
671
|
)
|
|
670
672
|
|
|
671
|
-
private
|
|
672
|
-
|
|
673
|
-
|
|
673
|
+
private getCommitArgs = (
|
|
674
|
+
firstEventOrTxnFnOrOptions: any,
|
|
675
|
+
restEvents: any[],
|
|
674
676
|
): {
|
|
675
|
-
|
|
676
|
-
options:
|
|
677
|
+
events: LiveStoreEvent.PartialForSchema<TSchema>[]
|
|
678
|
+
options: StoreCommitOptions | undefined
|
|
677
679
|
} => {
|
|
678
|
-
let
|
|
679
|
-
let options:
|
|
680
|
+
let events: LiveStoreEvent.PartialForSchema<TSchema>[]
|
|
681
|
+
let options: StoreCommitOptions | undefined
|
|
680
682
|
|
|
681
|
-
if (typeof
|
|
683
|
+
if (typeof firstEventOrTxnFnOrOptions === 'function') {
|
|
682
684
|
// TODO ensure that function is synchronous and isn't called in a async way (also write tests for this)
|
|
683
|
-
|
|
685
|
+
events = firstEventOrTxnFnOrOptions((arg: any) => events.push(arg))
|
|
684
686
|
} else if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
687
|
+
firstEventOrTxnFnOrOptions?.label !== undefined ||
|
|
688
|
+
firstEventOrTxnFnOrOptions?.skipRefresh !== undefined ||
|
|
689
|
+
firstEventOrTxnFnOrOptions?.otelContext !== undefined ||
|
|
690
|
+
firstEventOrTxnFnOrOptions?.spanLinks !== undefined
|
|
689
691
|
) {
|
|
690
|
-
options =
|
|
691
|
-
|
|
692
|
-
} else if (
|
|
693
|
-
// When `commit` is called with no arguments (which sometimes happens when dynamically filtering
|
|
694
|
-
|
|
692
|
+
options = firstEventOrTxnFnOrOptions
|
|
693
|
+
events = restEvents
|
|
694
|
+
} else if (firstEventOrTxnFnOrOptions === undefined) {
|
|
695
|
+
// When `commit` is called with no arguments (which sometimes happens when dynamically filtering events)
|
|
696
|
+
events = []
|
|
695
697
|
} else {
|
|
696
|
-
|
|
698
|
+
events = [firstEventOrTxnFnOrOptions, ...restEvents]
|
|
697
699
|
}
|
|
698
700
|
|
|
699
|
-
|
|
701
|
+
// for (const event of events) {
|
|
702
|
+
// if (event.args.id === SessionIdSymbol) {
|
|
703
|
+
// event.args.id = this.clientSession.sessionId
|
|
704
|
+
// }
|
|
705
|
+
// }
|
|
700
706
|
|
|
701
|
-
return {
|
|
707
|
+
return { events, options }
|
|
702
708
|
}
|
|
703
709
|
}
|
|
@@ -86,7 +86,7 @@ Error:
|
|
|
86
86
|
at Object.useMemo (/Users/schickling/Code/overtone/node_modules/.pnpm/react-dom@19.0.0_react@19.0.0/node_modules/react-dom/cjs/react-dom-client.development.js:22757:18)
|
|
87
87
|
at Object.process.env.NODE_ENV.exports.useMemo (/Users/schickling/Code/overtone/node_modules/.pnpm/react@19.0.0/node_modules/react/cjs/react.development.js:1488:34)
|
|
88
88
|
at Module.useQueryRef (/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/useQuery.ts:54:27)
|
|
89
|
-
at Module.
|
|
89
|
+
at Module.useClientDocument (/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/useClientDocument.ts:111:20)
|
|
90
90
|
at TestComponent (/Users/schickling/Code/overtone/node_modules/.pnpm/@testing-library+react@16.1.0_@testing-library+dom@10.4.0_@types+react-dom@19.0.3_@types+reac_2jaiibiag2sxou3wtzbuqx3r5a/node_modules/@testing-library/react/dist/pure.js:309:27)
|
|
91
91
|
at Object.react-stack-bottom-frame (/Users/schickling/Code/overtone/node_modules/.pnpm/react-dom@19.0.0_react@19.0.0/node_modules/react-dom/cjs/react-dom-client.development.js:22428:20)
|
|
92
92
|
at renderWithHooks (/Users/schickling/Code/overtone/node_modules/.pnpm/react-dom@19.0.0_react@19.0.0/node_modules/react-dom/cjs/react-dom-client.development.js:5757:22)
|
|
@@ -101,8 +101,8 @@ Error:
|
|
|
101
101
|
"name": "TestComponent",
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
|
-
"filePath": "/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/
|
|
105
|
-
"name": "
|
|
104
|
+
"filePath": "/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/useClientDocument.ts:111:20",
|
|
105
|
+
"name": "useClientDocument",
|
|
106
106
|
},
|
|
107
107
|
],
|
|
108
108
|
}
|
|
@@ -117,7 +117,7 @@ Error:
|
|
|
117
117
|
at Object.useMemo (/Users/schickling/Code/overtone/node_modules/.pnpm/react-dom@19.0.0_react@19.0.0/node_modules/react-dom/cjs/react-dom-client.development.js:22757:18)
|
|
118
118
|
at Object.process.env.NODE_ENV.exports.useMemo (/Users/schickling/Code/overtone/node_modules/.pnpm/react@19.0.0/node_modules/react/cjs/react.development.js:1488:34)
|
|
119
119
|
at Module.useQueryRef (/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/useQuery.ts:54:27)
|
|
120
|
-
at Module.
|
|
120
|
+
at Module.useClientDocument (/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/useClientDocument.ts:111:20)
|
|
121
121
|
at Object.react-stack-bottom-frame (/Users/schickling/Code/overtone/node_modules/.pnpm/react-dom@19.0.0_react@19.0.0/node_modules/react-dom/cjs/react-dom-client.development.js:22428:20)
|
|
122
122
|
at renderWithHooks (/Users/schickling/Code/overtone/node_modules/.pnpm/react-dom@19.0.0_react@19.0.0/node_modules/react-dom/cjs/react-dom-client.development.js:5757:22)
|
|
123
123
|
`
|
|
@@ -127,8 +127,8 @@ Error:
|
|
|
127
127
|
{
|
|
128
128
|
"frames": [
|
|
129
129
|
{
|
|
130
|
-
"filePath": "/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/
|
|
131
|
-
"name": "
|
|
130
|
+
"filePath": "/Users/schickling/Code/overtone/submodules/livestore/packages/@livestore/react/src/useClientDocument.ts:111:20",
|
|
131
|
+
"name": "useClientDocument",
|
|
132
132
|
},
|
|
133
133
|
],
|
|
134
134
|
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { makeInMemoryAdapter } from '@livestore/adapter-web'
|
|
2
2
|
import { provideOtel } from '@livestore/common'
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { createStore, DbSchema, makeSchema } from '@livestore/livestore'
|
|
6
|
-
import { Effect } from '@livestore/utils/effect'
|
|
3
|
+
import { createStore, makeSchema, State } from '@livestore/livestore'
|
|
4
|
+
import { Effect, Schema } from '@livestore/utils/effect'
|
|
7
5
|
import type * as otel from '@opentelemetry/api'
|
|
8
6
|
|
|
9
7
|
export type Todo = {
|
|
@@ -19,30 +17,28 @@ export type AppState = {
|
|
|
19
17
|
filter: Filter
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
export const todos =
|
|
23
|
-
'todos',
|
|
24
|
-
{
|
|
25
|
-
id:
|
|
26
|
-
text:
|
|
27
|
-
completed:
|
|
20
|
+
export const todos = State.SQLite.table({
|
|
21
|
+
name: 'todos',
|
|
22
|
+
columns: {
|
|
23
|
+
id: State.SQLite.text({ primaryKey: true }),
|
|
24
|
+
text: State.SQLite.text({ default: '', nullable: false }),
|
|
25
|
+
completed: State.SQLite.boolean({ default: false, nullable: false }),
|
|
28
26
|
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{ isSingleton: true },
|
|
40
|
-
)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export const app = State.SQLite.clientDocument({
|
|
30
|
+
name: 'app',
|
|
31
|
+
schema: Schema.Struct({
|
|
32
|
+
newTodoText: Schema.String,
|
|
33
|
+
filter: Schema.String,
|
|
34
|
+
}),
|
|
35
|
+
default: { value: { newTodoText: '', filter: 'all' } },
|
|
36
|
+
})
|
|
41
37
|
|
|
42
38
|
export const tables = { todos, app }
|
|
43
|
-
export const schema = makeSchema({ tables })
|
|
44
39
|
|
|
45
|
-
export
|
|
40
|
+
export const state = State.SQLite.makeState({ tables, materializers: {} })
|
|
41
|
+
export const schema = makeSchema({ state, events: {} })
|
|
46
42
|
|
|
47
43
|
export const makeTodoMvc = ({
|
|
48
44
|
otelTracer,
|
|
@@ -52,7 +48,7 @@ export const makeTodoMvc = ({
|
|
|
52
48
|
otelContext?: otel.Context
|
|
53
49
|
} = {}) =>
|
|
54
50
|
Effect.gen(function* () {
|
|
55
|
-
const store
|
|
51
|
+
const store = yield* createStore({
|
|
56
52
|
schema,
|
|
57
53
|
storeId: 'default',
|
|
58
54
|
adapter: makeInMemoryAdapter(),
|
package/src/utils/tests/otel.ts
CHANGED
|
@@ -13,14 +13,21 @@ export const getSimplifiedRootSpan = (
|
|
|
13
13
|
const mapAttributesfn = mapAttributes ?? identity
|
|
14
14
|
|
|
15
15
|
spansMap.forEach((nestedSpan) => {
|
|
16
|
-
const
|
|
16
|
+
const parentId = nestedSpan.span.parentSpanContext?.spanId
|
|
17
|
+
const parentSpan = parentId ? spansMap.get(parentId) : undefined
|
|
17
18
|
if (parentSpan) {
|
|
18
19
|
parentSpan.children.push(nestedSpan)
|
|
19
20
|
}
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
type NestedSpan = { span: ReadableSpan; children: NestedSpan[] }
|
|
23
|
-
const
|
|
24
|
+
const createStoreSpanData = spans.find((_) => _.name === 'createStore')
|
|
25
|
+
if (createStoreSpanData === undefined) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"Could not find the root span named 'createStore'. Available spans: " + spans.map((s) => s.name).join(', '),
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
const rootSpan = spansMap.get(createStoreSpanData.spanContext().spanId)!
|
|
24
31
|
|
|
25
32
|
const simplifySpanRec = (span: NestedSpan): SimplifiedNestedSpan =>
|
|
26
33
|
omitEmpty({
|
|
@@ -88,7 +95,7 @@ export const toTraceFile = (spans: ReadableSpan[]) => {
|
|
|
88
95
|
spans: spans.map((span) => ({
|
|
89
96
|
traceId: span.spanContext().traceId,
|
|
90
97
|
spanId: span.spanContext().spanId,
|
|
91
|
-
...(span.
|
|
98
|
+
...(span.parentSpanContext?.spanId ? { parentSpanId: span.parentSpanContext.spanId } : {}),
|
|
92
99
|
// traceState: span.spanContext().traceState ?? '',
|
|
93
100
|
name: span.name,
|
|
94
101
|
kind: 'SPAN_KIND_INTERNAL',
|
package/tmp/pack.tgz
CHANGED
|
Binary file
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { QueryInfo } from '@livestore/common';
|
|
2
|
-
import { SessionIdSymbol } from '@livestore/common';
|
|
3
|
-
import { DbSchema } from '@livestore/common/schema';
|
|
4
|
-
import type * as otel from '@opentelemetry/api';
|
|
5
|
-
import type { GetResult, LiveQueryDef, ReactivityGraphContext } from './live-queries/base-class.js';
|
|
6
|
-
export declare const rowQueryLabel: (table: DbSchema.TableDefBase, id: string | SessionIdSymbol | number | undefined) => string;
|
|
7
|
-
export declare const deriveColQuery: {
|
|
8
|
-
<TQueryDef extends LiveQueryDef<any, QueryInfo.None>, TCol extends keyof GetResult<TQueryDef> & string>(queryDef: TQueryDef, colName: TCol): LiveQueryDef<GetResult<TQueryDef>[TCol], QueryInfo.None>;
|
|
9
|
-
<TQueryDef extends LiveQueryDef<any, QueryInfo.Row>, TCol extends keyof GetResult<TQueryDef> & string>(queryDef: TQueryDef, colName: TCol): LiveQueryDef<GetResult<TQueryDef>[TCol], QueryInfo.Col>;
|
|
10
|
-
};
|
|
11
|
-
export declare const makeExecBeforeFirstRun: ({ id, insertValues, table, otelContext: otelContext_, }: {
|
|
12
|
-
id?: string | SessionIdSymbol | number;
|
|
13
|
-
insertValues?: any;
|
|
14
|
-
table: DbSchema.TableDefBase;
|
|
15
|
-
otelContext: otel.Context | undefined;
|
|
16
|
-
}) => ({ store }: ReactivityGraphContext) => undefined;
|
|
17
|
-
//# sourceMappingURL=row-query-utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-query-utils.d.ts","sourceRoot":"","sources":["../src/row-query-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEnD,OAAO,KAAK,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAE/C,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AAGnG,eAAO,MAAM,aAAa,GAAI,OAAO,QAAQ,CAAC,YAAY,EAAE,IAAI,MAAM,GAAG,eAAe,GAAG,MAAM,GAAG,SAAS,WACH,CAAA;AAE1G,eAAO,MAAM,cAAc,EAAE;IAC3B,CAAC,SAAS,SAAS,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,SAAS,MAAM,SAAS,CAAC,SAAS,CAAC,GAAG,MAAM,EACpG,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE,IAAI,GACZ,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAC3D,CAAC,SAAS,SAAS,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,SAAS,MAAM,SAAS,CAAC,SAAS,CAAC,GAAG,MAAM,EACnG,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE,IAAI,GACZ,YAAY,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAA;CAc3D,CAAA;AAED,eAAO,MAAM,sBAAsB,GAChC,yDAKE;IACD,EAAE,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,MAAM,CAAA;IACtC,YAAY,CAAC,EAAE,GAAG,CAAA;IAClB,KAAK,EAAE,QAAQ,CAAC,YAAY,CAAA;IAC5B,WAAW,EAAE,IAAI,CAAC,OAAO,GAAG,SAAS,CAAA;CACtC,MACA,WAAW,sBAAsB,cA2BjC,CAAA"}
|
package/dist/row-query-utils.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { SessionIdSymbol } from '@livestore/common';
|
|
2
|
-
import { DbSchema } from '@livestore/common/schema';
|
|
3
|
-
import { shouldNeverHappen } from '@livestore/utils';
|
|
4
|
-
import { computed } from './live-queries/computed.js';
|
|
5
|
-
export const rowQueryLabel = (table, id) => `row:${table.sqliteDef.name}${id === undefined ? '' : id === SessionIdSymbol ? `:sessionId` : `:${id}`}`;
|
|
6
|
-
export const deriveColQuery = (queryDef, colName) => {
|
|
7
|
-
return computed((get) => get(queryDef)[colName], {
|
|
8
|
-
label: `deriveColQuery:${queryDef.label}:${colName}`,
|
|
9
|
-
queryInfo: queryDef.queryInfo._tag === 'Row'
|
|
10
|
-
? { _tag: 'Col', table: queryDef.queryInfo.table, column: colName, id: queryDef.queryInfo.id }
|
|
11
|
-
: undefined,
|
|
12
|
-
deps: [
|
|
13
|
-
queryDef.queryInfo.table.sqliteDef.name,
|
|
14
|
-
queryDef.queryInfo.id === SessionIdSymbol ? 'sessionId' : queryDef.queryInfo.id,
|
|
15
|
-
queryDef.queryInfo._tag === 'Col' ? queryDef.queryInfo.column : undefined,
|
|
16
|
-
],
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
|
-
export const makeExecBeforeFirstRun = ({ id, insertValues, table, otelContext: otelContext_, }) => ({ store }) => {
|
|
20
|
-
const otelContext = otelContext_ ?? store.otel.queriesSpanContext;
|
|
21
|
-
if (table.options.isSingleton === false) {
|
|
22
|
-
const idVal = id === SessionIdSymbol ? store.sessionId : id;
|
|
23
|
-
const rowExists = store.sqliteDbWrapper.select(`SELECT 1 FROM '${table.sqliteDef.name}' WHERE id = ?`, [idVal], { otelContext }).length === 1;
|
|
24
|
-
if (rowExists)
|
|
25
|
-
return;
|
|
26
|
-
if (DbSchema.tableHasDerivedMutations(table) === false) {
|
|
27
|
-
return shouldNeverHappen(`Cannot insert row for table "${table.sqliteDef.name}" which does not have 'deriveMutations: true' set`);
|
|
28
|
-
}
|
|
29
|
-
// It's important that we only commit and don't refresh here, as this function might be called during a render
|
|
30
|
-
// and otherwise we might end up in a "reactive loop"
|
|
31
|
-
store.commit({ otelContext, skipRefresh: true, label: `rowQuery:${table.sqliteDef.name}:${idVal}` }, table.insert({ id, ...insertValues }));
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
//# sourceMappingURL=row-query-utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"row-query-utils.js","sourceRoot":"","sources":["../src/row-query-utils.ts"],"names":[],"mappings":"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"}
|