@livestore/livestore 0.4.0-dev.10 → 0.4.0-dev.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.
- package/dist/.tsbuildinfo +1 -1
- 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/db-query.test.js +40 -17
- package/dist/live-queries/db-query.test.js.map +1 -1
- package/dist/mod.d.ts +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js.map +1 -1
- package/dist/store/store-types.d.ts +12 -1
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store.d.ts +25 -28
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +34 -15
- package/dist/store/store.js.map +1 -1
- package/package.json +5 -5
- package/src/live-queries/__snapshots__/db-query.test.ts.snap +87 -0
- package/src/live-queries/base-class.ts +6 -3
- package/src/live-queries/db-query.test.ts +57 -17
- package/src/mod.ts +8 -1
- package/src/store/store-types.ts +18 -0
- package/src/store/store.ts +61 -51
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/livestore",
|
|
3
|
-
"version": "0.4.0-dev.
|
|
3
|
+
"version": "0.4.0-dev.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@opentelemetry/api": "1.9.0",
|
|
14
|
-
"@livestore/
|
|
15
|
-
"@livestore/
|
|
14
|
+
"@livestore/common": "0.4.0-dev.12",
|
|
15
|
+
"@livestore/utils": "0.4.0-dev.12"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@opentelemetry/sdk-trace-base": "^2.0.1",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"typescript": "5.9.2",
|
|
21
21
|
"vite": "7.1.7",
|
|
22
22
|
"vitest": "3.2.4",
|
|
23
|
-
"@livestore/
|
|
24
|
-
"@livestore/
|
|
23
|
+
"@livestore/utils-dev": "0.4.0-dev.12",
|
|
24
|
+
"@livestore/adapter-web": "0.4.0-dev.12"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"package.json",
|
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
2
|
|
|
3
|
+
exports[`otel > QueryBuilder subscription - async iterator 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"_name": "createStore",
|
|
6
|
+
"attributes": {
|
|
7
|
+
"debugInstanceId": "test",
|
|
8
|
+
"storeId": "default",
|
|
9
|
+
},
|
|
10
|
+
"children": [
|
|
11
|
+
{
|
|
12
|
+
"_name": "livestore.in-memory-db:execute",
|
|
13
|
+
"attributes": {
|
|
14
|
+
"sql.query": "
|
|
15
|
+
PRAGMA page_size=32768;
|
|
16
|
+
PRAGMA cache_size=10000;
|
|
17
|
+
PRAGMA synchronous='OFF';
|
|
18
|
+
PRAGMA temp_store='MEMORY';
|
|
19
|
+
PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
|
|
20
|
+
",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"_name": "@livestore/common:LeaderSyncProcessor:push",
|
|
25
|
+
"attributes": {
|
|
26
|
+
"batch": "undefined",
|
|
27
|
+
"batchSize": 1,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"_name": "client-session-sync-processor:pull",
|
|
32
|
+
"attributes": {
|
|
33
|
+
"code.stacktrace": "<STACKTRACE>",
|
|
34
|
+
"span.label": "⚠︎ Interrupted",
|
|
35
|
+
"status.interrupted": true,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"_name": "LiveStore:sync",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"_name": "LiveStore:commits",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"_name": "LiveStore:queries",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
exports[`otel > QueryBuilder subscription - async iterator 2`] = `
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
"_name": "LiveStore:commit",
|
|
55
|
+
"attributes": {
|
|
56
|
+
"livestore.eventTags": "[
|
|
57
|
+
"todo.created"
|
|
58
|
+
]",
|
|
59
|
+
"livestore.eventsCount": 1,
|
|
60
|
+
},
|
|
61
|
+
"children": [
|
|
62
|
+
{
|
|
63
|
+
"_name": "client-session-sync-processor:push",
|
|
64
|
+
"attributes": {
|
|
65
|
+
"batchSize": 1,
|
|
66
|
+
"eventCounts": "{
|
|
67
|
+
"todo.created": 1
|
|
68
|
+
}",
|
|
69
|
+
"mergeResultTag": "advance",
|
|
70
|
+
},
|
|
71
|
+
"children": [
|
|
72
|
+
{
|
|
73
|
+
"_name": "client-session-sync-processor:materialize-event",
|
|
74
|
+
"children": [
|
|
75
|
+
{
|
|
76
|
+
"_name": "livestore.in-memory-db:execute",
|
|
77
|
+
"attributes": {
|
|
78
|
+
"sql.query": "INSERT INTO 'todos' (id, text, completed) VALUES (?, ?, ?)",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
]
|
|
88
|
+
`;
|
|
89
|
+
|
|
3
90
|
exports[`otel > QueryBuilder subscription - basic functionality 1`] = `
|
|
4
91
|
{
|
|
5
92
|
"_name": "createStore",
|
|
@@ -166,10 +166,13 @@ export abstract class LiveStoreQueryBase<TResult> implements LiveQuery<TResult>
|
|
|
166
166
|
|
|
167
167
|
// subscribe = (
|
|
168
168
|
// onNewValue: (value: TResult) => void,
|
|
169
|
-
//
|
|
170
|
-
//
|
|
169
|
+
// options?: {
|
|
170
|
+
// label?: string
|
|
171
|
+
// otelContext?: otel.Context
|
|
172
|
+
// onUnsubsubscribe?: () => void
|
|
173
|
+
// },
|
|
171
174
|
// ): (() => void) =>
|
|
172
|
-
// this.reactivityGraph.context?.store.subscribe(this, onNewValue,
|
|
175
|
+
// this.reactivityGraph.context?.store.subscribe(this, onNewValue, options) ??
|
|
173
176
|
// RG.throwContextNotSetError(this.reactivityGraph)
|
|
174
177
|
}
|
|
175
178
|
|
|
@@ -2,7 +2,7 @@ import { Effect, ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
|
|
2
2
|
import { Vitest } from '@livestore/utils-dev/node-vitest'
|
|
3
3
|
import * as otel from '@opentelemetry/api'
|
|
4
4
|
import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
5
|
-
import { expect } from 'vitest'
|
|
5
|
+
import { assert, expect } from 'vitest'
|
|
6
6
|
|
|
7
7
|
import * as RG from '../reactive.ts'
|
|
8
8
|
import { events, makeTodoMvc, tables } from '../utils/tests/fixture.ts'
|
|
@@ -204,10 +204,8 @@ Vitest.describe('otel', () => {
|
|
|
204
204
|
.where({ completed: false })
|
|
205
205
|
.first({ behaviour: 'fallback', fallback: () => defaultTodo })
|
|
206
206
|
|
|
207
|
-
const unsubscribe = store.subscribe(queryBuilder, {
|
|
208
|
-
|
|
209
|
-
callbackResults.push(result)
|
|
210
|
-
},
|
|
207
|
+
const unsubscribe = store.subscribe(queryBuilder, (result) => {
|
|
208
|
+
callbackResults.push(result)
|
|
211
209
|
})
|
|
212
210
|
|
|
213
211
|
expect(callbackResults).toHaveLength(1)
|
|
@@ -251,16 +249,12 @@ Vitest.describe('otel', () => {
|
|
|
251
249
|
.where({ completed: false })
|
|
252
250
|
.first({ behaviour: 'fallback', fallback: () => defaultTodo })
|
|
253
251
|
|
|
254
|
-
const unsubscribe1 = store.subscribe(queryBuilder, {
|
|
255
|
-
|
|
256
|
-
callbackResults1.push(result)
|
|
257
|
-
},
|
|
252
|
+
const unsubscribe1 = store.subscribe(queryBuilder, (result) => {
|
|
253
|
+
callbackResults1.push(result)
|
|
258
254
|
})
|
|
259
255
|
|
|
260
|
-
const unsubscribe2 = store.subscribe(queryBuilder, {
|
|
261
|
-
|
|
262
|
-
callbackResults2.push(result)
|
|
263
|
-
},
|
|
256
|
+
const unsubscribe2 = store.subscribe(queryBuilder, (result) => {
|
|
257
|
+
callbackResults2.push(result)
|
|
264
258
|
})
|
|
265
259
|
|
|
266
260
|
expect(callbackResults1).toHaveLength(1)
|
|
@@ -295,16 +289,62 @@ Vitest.describe('otel', () => {
|
|
|
295
289
|
),
|
|
296
290
|
)
|
|
297
291
|
|
|
292
|
+
Vitest.scopedLive('QueryBuilder subscription - async iterator', () =>
|
|
293
|
+
Effect.gen(function* () {
|
|
294
|
+
const { store, exporter, span, provider } = yield* makeQuery
|
|
295
|
+
|
|
296
|
+
const defaultTodo = { id: '', text: '', completed: false }
|
|
297
|
+
|
|
298
|
+
const queryBuilder = tables.todos
|
|
299
|
+
.where({ completed: false })
|
|
300
|
+
.first({ behaviour: 'fallback', fallback: () => defaultTodo })
|
|
301
|
+
|
|
302
|
+
yield* Effect.promise(async () => {
|
|
303
|
+
const iterator = store.subscribe(queryBuilder)[Symbol.asyncIterator]()
|
|
304
|
+
|
|
305
|
+
const initial = await iterator.next()
|
|
306
|
+
expect(initial.done).toBe(false)
|
|
307
|
+
expect(initial.value).toMatchObject(defaultTodo)
|
|
308
|
+
|
|
309
|
+
store.commit(events.todoCreated({ id: 't-async', text: 'write tests', completed: false }))
|
|
310
|
+
|
|
311
|
+
const update = await iterator.next()
|
|
312
|
+
expect(update.done).toBe(false)
|
|
313
|
+
expect(update.value).toMatchObject({
|
|
314
|
+
id: 't-async',
|
|
315
|
+
text: 'write tests',
|
|
316
|
+
completed: false,
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
const doneResult = await iterator.return?.()
|
|
320
|
+
assert(doneResult)
|
|
321
|
+
expect(doneResult.done).toBe(true)
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
span.end()
|
|
325
|
+
|
|
326
|
+
return { exporter, provider }
|
|
327
|
+
}).pipe(
|
|
328
|
+
Effect.scoped,
|
|
329
|
+
Effect.tap(({ exporter, provider }) =>
|
|
330
|
+
Effect.promise(async () => {
|
|
331
|
+
await provider.forceFlush()
|
|
332
|
+
expect(getSimplifiedRootSpan(exporter, 'createStore', mapAttributes)).toMatchSnapshot()
|
|
333
|
+
expect(getAllSimplifiedRootSpans(exporter, 'LiveStore:commit', mapAttributes)).toMatchSnapshot()
|
|
334
|
+
await provider.shutdown()
|
|
335
|
+
}),
|
|
336
|
+
),
|
|
337
|
+
),
|
|
338
|
+
)
|
|
339
|
+
|
|
298
340
|
Vitest.scopedLive('QueryBuilder subscription - direct table subscription', () =>
|
|
299
341
|
Effect.gen(function* () {
|
|
300
342
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
301
343
|
|
|
302
344
|
const callbackResults: any[] = []
|
|
303
345
|
|
|
304
|
-
const unsubscribe = store.subscribe(tables.todos, {
|
|
305
|
-
|
|
306
|
-
callbackResults.push(result)
|
|
307
|
-
},
|
|
346
|
+
const unsubscribe = store.subscribe(tables.todos, (result) => {
|
|
347
|
+
callbackResults.push(result)
|
|
308
348
|
})
|
|
309
349
|
|
|
310
350
|
expect(callbackResults).toHaveLength(1)
|
package/src/mod.ts
CHANGED
|
@@ -37,7 +37,14 @@ export {
|
|
|
37
37
|
export { emptyDebugInfo, SqliteDbWrapper } from './SqliteDbWrapper.ts'
|
|
38
38
|
export { type CreateStoreOptions, createStore, createStorePromise } from './store/create-store.ts'
|
|
39
39
|
export { Store } from './store/store.ts'
|
|
40
|
-
export type {
|
|
40
|
+
export type {
|
|
41
|
+
OtelOptions,
|
|
42
|
+
Queryable,
|
|
43
|
+
QueryDebugInfo,
|
|
44
|
+
RefreshReason,
|
|
45
|
+
SubscribeOptions,
|
|
46
|
+
Unsubscribe,
|
|
47
|
+
} from './store/store-types.ts'
|
|
41
48
|
export {
|
|
42
49
|
type LiveStoreContext,
|
|
43
50
|
type LiveStoreContextRunning,
|
package/src/store/store-types.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
InvalidPullError,
|
|
6
6
|
IsOfflineError,
|
|
7
7
|
MaterializeError,
|
|
8
|
+
QueryBuilder,
|
|
8
9
|
StoreInterrupted,
|
|
9
10
|
SyncError,
|
|
10
11
|
UnexpectedError,
|
|
@@ -14,6 +15,7 @@ import type { Effect, Runtime, Scope } from '@livestore/utils/effect'
|
|
|
14
15
|
import { Deferred } from '@livestore/utils/effect'
|
|
15
16
|
import type * as otel from '@opentelemetry/api'
|
|
16
17
|
|
|
18
|
+
import type { LiveQuery, LiveQueryDef, SignalDef } from '../live-queries/base-class.ts'
|
|
17
19
|
import type { DebugRefreshReasonBase } from '../reactive.ts'
|
|
18
20
|
import type { StackInfo } from '../utils/stack-info.ts'
|
|
19
21
|
import type { Store } from './store.ts'
|
|
@@ -135,3 +137,19 @@ export type StoreEventsOptions<TSchema extends LiveStoreSchema> = {
|
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
export type Unsubscribe = () => void
|
|
140
|
+
|
|
141
|
+
export type SubscribeOptions<TResult> = {
|
|
142
|
+
onSubscribe?: (query$: LiveQuery<TResult>) => void
|
|
143
|
+
onUnsubsubscribe?: () => void
|
|
144
|
+
label?: string
|
|
145
|
+
skipInitialRun?: boolean
|
|
146
|
+
otelContext?: otel.Context
|
|
147
|
+
stackInfo?: StackInfo
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** All query definitions or instances the store can execute or subscribe to. */
|
|
151
|
+
export type Queryable<TResult> =
|
|
152
|
+
| LiveQueryDef<TResult>
|
|
153
|
+
| SignalDef<TResult>
|
|
154
|
+
| LiveQuery<TResult>
|
|
155
|
+
| QueryBuilder<TResult, any, any>
|
package/src/store/store.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
makeClientSessionSyncProcessor,
|
|
15
15
|
type PreparedBindValues,
|
|
16
16
|
prepareBindValues,
|
|
17
|
-
type QueryBuilder,
|
|
18
17
|
QueryBuilderAstSymbol,
|
|
19
18
|
replaceSessionIdSymbol,
|
|
20
19
|
UnexpectedError,
|
|
@@ -38,13 +37,7 @@ import {
|
|
|
38
37
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
39
38
|
import * as otel from '@opentelemetry/api'
|
|
40
39
|
|
|
41
|
-
import type {
|
|
42
|
-
LiveQuery,
|
|
43
|
-
LiveQueryDef,
|
|
44
|
-
ReactivityGraph,
|
|
45
|
-
ReactivityGraphContext,
|
|
46
|
-
SignalDef,
|
|
47
|
-
} from '../live-queries/base-class.ts'
|
|
40
|
+
import type { LiveQuery, ReactivityGraph, ReactivityGraphContext, SignalDef } from '../live-queries/base-class.ts'
|
|
48
41
|
import { makeReactivityGraph } from '../live-queries/base-class.ts'
|
|
49
42
|
import { makeExecBeforeFirstRun } from '../live-queries/client-document-get-query.ts'
|
|
50
43
|
import { queryDb } from '../live-queries/db-query.ts'
|
|
@@ -52,16 +45,26 @@ import type { Ref } from '../reactive.ts'
|
|
|
52
45
|
import { SqliteDbWrapper } from '../SqliteDbWrapper.ts'
|
|
53
46
|
import { ReferenceCountedSet } from '../utils/data-structures.ts'
|
|
54
47
|
import { downloadBlob, exposeDebugUtils } from '../utils/dev.ts'
|
|
55
|
-
import type { StackInfo } from '../utils/stack-info.ts'
|
|
56
48
|
import type {
|
|
49
|
+
Queryable,
|
|
57
50
|
RefreshReason,
|
|
58
51
|
StoreCommitOptions,
|
|
59
52
|
StoreEventsOptions,
|
|
60
53
|
StoreOptions,
|
|
61
54
|
StoreOtel,
|
|
55
|
+
SubscribeOptions,
|
|
62
56
|
Unsubscribe,
|
|
63
57
|
} from './store-types.ts'
|
|
64
58
|
|
|
59
|
+
type SubscribeFn = {
|
|
60
|
+
<TResult>(
|
|
61
|
+
query: Queryable<TResult>,
|
|
62
|
+
onUpdate: (value: TResult) => void,
|
|
63
|
+
options?: SubscribeOptions<TResult>,
|
|
64
|
+
): Unsubscribe
|
|
65
|
+
<TResult>(query: Queryable<TResult>, options?: SubscribeOptions<TResult>): AsyncIterable<TResult>
|
|
66
|
+
}
|
|
67
|
+
|
|
65
68
|
if (isDevEnv()) {
|
|
66
69
|
exposeDebugUtils()
|
|
67
70
|
}
|
|
@@ -349,32 +352,39 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
349
352
|
}
|
|
350
353
|
|
|
351
354
|
/**
|
|
352
|
-
* Subscribe to the results of a query
|
|
353
|
-
*
|
|
355
|
+
* Subscribe to the results of a query.
|
|
356
|
+
*
|
|
357
|
+
* - When providing an `onUpdate` callback it returns an {@link Unsubscribe} function.
|
|
358
|
+
* - Without a callback it returns an {@link AsyncIterable} that yields query results.
|
|
354
359
|
*
|
|
355
360
|
* @example
|
|
356
361
|
* ```ts
|
|
357
|
-
* const unsubscribe = store.subscribe(query$,
|
|
362
|
+
* const unsubscribe = store.subscribe(query$, (result) => console.log(result))
|
|
363
|
+
* ```
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* for await (const result of store.subscribe(query$)) {
|
|
368
|
+
* console.log(result)
|
|
369
|
+
* }
|
|
358
370
|
* ```
|
|
359
371
|
*/
|
|
360
|
-
subscribe = <TResult>(
|
|
361
|
-
query:
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
stackInfo?: StackInfo
|
|
377
|
-
},
|
|
372
|
+
subscribe = (<TResult>(
|
|
373
|
+
query: Queryable<TResult>,
|
|
374
|
+
onUpdateOrOptions?: ((value: TResult) => void) | SubscribeOptions<TResult>,
|
|
375
|
+
maybeOptions?: SubscribeOptions<TResult>,
|
|
376
|
+
): Unsubscribe | AsyncIterable<TResult> => {
|
|
377
|
+
if (typeof onUpdateOrOptions === 'function') {
|
|
378
|
+
return this.subscribeWithCallback(query, onUpdateOrOptions, maybeOptions)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return this.subscribeAsAsyncIterable(query, onUpdateOrOptions)
|
|
382
|
+
}) as SubscribeFn
|
|
383
|
+
|
|
384
|
+
private subscribeWithCallback = <TResult>(
|
|
385
|
+
query: Queryable<TResult>,
|
|
386
|
+
onUpdate: (value: TResult) => void,
|
|
387
|
+
options?: SubscribeOptions<TResult>,
|
|
378
388
|
): Unsubscribe => {
|
|
379
389
|
this.checkShutdown('subscribe')
|
|
380
390
|
|
|
@@ -383,7 +393,6 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
383
393
|
{ attributes: { label: options?.label, queryLabel: isQueryBuilder(query) ? query.toString() : query.label } },
|
|
384
394
|
options?.otelContext ?? this.otel.queriesSpanContext,
|
|
385
395
|
(span) => {
|
|
386
|
-
// console.debug('store sub', query$.id, query$.label)
|
|
387
396
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
388
397
|
|
|
389
398
|
const queryRcRef = isQueryBuilder(query)
|
|
@@ -398,8 +407,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
398
407
|
|
|
399
408
|
const label = `subscribe:${options?.label}`
|
|
400
409
|
const effect = this.reactivityGraph.makeEffect(
|
|
401
|
-
(get, _otelContext, debugRefreshReason) =>
|
|
402
|
-
options.onUpdate(get(query$.results$, otelContext, debugRefreshReason)),
|
|
410
|
+
(get, _otelContext, debugRefreshReason) => onUpdate(get(query$.results$, otelContext, debugRefreshReason)),
|
|
403
411
|
{ label },
|
|
404
412
|
)
|
|
405
413
|
|
|
@@ -411,13 +419,14 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
411
419
|
|
|
412
420
|
this.activeQueries.add(query$ as LiveQuery<TResult>)
|
|
413
421
|
|
|
414
|
-
// Running effect right away to get initial value (unless `skipInitialRun` is set)
|
|
415
422
|
if (options?.skipInitialRun !== true && !query$.isDestroyed) {
|
|
416
|
-
effect.doEffect(otelContext, {
|
|
423
|
+
effect.doEffect(otelContext, {
|
|
424
|
+
_tag: 'subscribe.initial',
|
|
425
|
+
label: `subscribe-initial-run:${options?.label}`,
|
|
426
|
+
})
|
|
417
427
|
}
|
|
418
428
|
|
|
419
429
|
const unsubscribe = () => {
|
|
420
|
-
// console.debug('store unsub', query$.id, query$.label)
|
|
421
430
|
try {
|
|
422
431
|
this.reactivityGraph.destroyNode(effect)
|
|
423
432
|
this.activeQueries.remove(query$ as LiveQuery<TResult>)
|
|
@@ -439,10 +448,16 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
439
448
|
)
|
|
440
449
|
}
|
|
441
450
|
|
|
442
|
-
|
|
443
|
-
query
|
|
444
|
-
options?:
|
|
445
|
-
):
|
|
451
|
+
private subscribeAsAsyncIterable = <TResult>(
|
|
452
|
+
query: Queryable<TResult>,
|
|
453
|
+
options?: SubscribeOptions<TResult>,
|
|
454
|
+
): AsyncIterable<TResult> => {
|
|
455
|
+
this.checkShutdown('subscribe')
|
|
456
|
+
|
|
457
|
+
return Stream.toAsyncIterable(this.subscribeStream(query, options))
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
subscribeStream = <TResult>(query: Queryable<TResult>, options?: SubscribeOptions<TResult>): Stream.Stream<TResult> =>
|
|
446
461
|
Stream.asyncPush<TResult>((emit) =>
|
|
447
462
|
Effect.gen(this, function* () {
|
|
448
463
|
const otelSpan = yield* OtelTracer.currentOtelSpan.pipe(
|
|
@@ -452,9 +467,9 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
452
467
|
|
|
453
468
|
yield* Effect.acquireRelease(
|
|
454
469
|
Effect.sync(() =>
|
|
455
|
-
this.subscribe(query
|
|
456
|
-
|
|
457
|
-
|
|
470
|
+
this.subscribe(query, (result) => emit.single(result), {
|
|
471
|
+
...(options ?? {}),
|
|
472
|
+
otelContext,
|
|
458
473
|
}),
|
|
459
474
|
),
|
|
460
475
|
(unsub) => Effect.sync(() => unsub()),
|
|
@@ -477,12 +492,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
477
492
|
* ```
|
|
478
493
|
*/
|
|
479
494
|
query = <TResult>(
|
|
480
|
-
query:
|
|
481
|
-
| QueryBuilder<TResult, any, any>
|
|
482
|
-
| LiveQuery<TResult>
|
|
483
|
-
| LiveQueryDef<TResult>
|
|
484
|
-
| SignalDef<TResult>
|
|
485
|
-
| { query: string; bindValues: Bindable; schema?: Schema.Schema<TResult> },
|
|
495
|
+
query: Queryable<TResult> | { query: string; bindValues: Bindable; schema?: Schema.Schema<TResult> },
|
|
486
496
|
options?: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason },
|
|
487
497
|
): TResult => {
|
|
488
498
|
this.checkShutdown('query')
|
|
@@ -847,7 +857,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
847
857
|
syncStates: () =>
|
|
848
858
|
Effect.gen(this, function* () {
|
|
849
859
|
const session = yield* this.syncProcessor.syncState
|
|
850
|
-
const leader = yield* this.clientSession.leaderThread.
|
|
860
|
+
const leader = yield* this.clientSession.leaderThread.syncState
|
|
851
861
|
return { session, leader }
|
|
852
862
|
}).pipe(this.runEffectPromise),
|
|
853
863
|
|
|
@@ -858,7 +868,7 @@ export class Store<TSchema extends LiveStoreSchema = LiveStoreSchema.Any, TConte
|
|
|
858
868
|
`Session sync state: ${session.localHead} (upstream: ${session.upstreamHead})`,
|
|
859
869
|
session.toJSON(),
|
|
860
870
|
)
|
|
861
|
-
const leader = yield* this.clientSession.leaderThread.
|
|
871
|
+
const leader = yield* this.clientSession.leaderThread.syncState
|
|
862
872
|
yield* Effect.log(`Leader sync state: ${leader.localHead} (upstream: ${leader.upstreamHead})`, leader.toJSON())
|
|
863
873
|
}).pipe(this.runEffectFork)
|
|
864
874
|
},
|