@livestore/livestore 0.4.0 → 0.5.0-dev.0
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 +7 -5
- package/dist/SqliteDbWrapper.js.map +1 -1
- package/dist/SqliteDbWrapper.test.js +20 -3
- package/dist/SqliteDbWrapper.test.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +15 -15
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +17 -17
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/effect/LiveStore.test.js +5 -6
- package/dist/effect/LiveStore.test.js.map +1 -1
- package/dist/live-queries/base-class.d.ts +19 -2
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js +28 -2
- package/dist/live-queries/base-class.js.map +1 -1
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +4 -4
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts +2 -2
- package/dist/live-queries/db-query.d.ts.map +1 -1
- package/dist/live-queries/db-query.js +26 -17
- package/dist/live-queries/db-query.js.map +1 -1
- package/dist/live-queries/db-query.test.js +9 -9
- package/dist/live-queries/db-query.test.js.map +1 -1
- package/dist/live-queries/signal.d.ts.map +1 -1
- package/dist/live-queries/signal.js +2 -2
- package/dist/live-queries/signal.js.map +1 -1
- package/dist/live-queries/signal.test.js +2 -2
- package/dist/live-queries/signal.test.js.map +1 -1
- package/dist/reactive.d.ts +1 -1
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +20 -1
- package/dist/reactive.js.map +1 -1
- package/dist/store/StoreRegistry.d.ts +12 -12
- package/dist/store/StoreRegistry.d.ts.map +1 -1
- package/dist/store/StoreRegistry.js +24 -24
- package/dist/store/StoreRegistry.js.map +1 -1
- package/dist/store/StoreRegistry.test.js +62 -59
- package/dist/store/StoreRegistry.test.js.map +1 -1
- package/dist/store/create-store.d.ts +12 -15
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +43 -24
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts +1 -2
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +3 -2
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-eventstream.test.js +5 -5
- package/dist/store/store-eventstream.test.js.map +1 -1
- package/dist/store/store-types.d.ts +10 -28
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store-types.js +2 -38
- package/dist/store/store-types.js.map +1 -1
- package/dist/store/store-types.test.js +1 -1
- package/dist/store/store.d.ts +2 -2
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +114 -56
- package/dist/store/store.js.map +1 -1
- package/dist/utils/dev.js +1 -1
- package/dist/utils/dev.js.map +1 -1
- package/dist/utils/stack-info.d.ts.map +1 -1
- package/dist/utils/stack-info.js +2 -1
- package/dist/utils/stack-info.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +26 -34
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/package.json +14 -24
- package/src/SqliteDbWrapper.test.ts +25 -3
- package/src/SqliteDbWrapper.ts +12 -9
- package/src/effect/LiveStore.test.ts +16 -16
- package/src/effect/LiveStore.ts +79 -50
- package/src/live-queries/__snapshots__/db-query.test.ts.snap +273 -49
- package/src/live-queries/base-class.ts +38 -6
- package/src/live-queries/computed.ts +5 -5
- package/src/live-queries/db-query.test.ts +9 -9
- package/src/live-queries/db-query.ts +42 -30
- package/src/live-queries/signal.test.ts +2 -2
- package/src/live-queries/signal.ts +3 -3
- package/src/reactive.ts +45 -35
- package/src/store/StoreRegistry.test.ts +62 -59
- package/src/store/StoreRegistry.ts +49 -38
- package/src/store/create-store.ts +85 -51
- package/src/store/devtools.ts +283 -283
- package/src/store/store-eventstream.test.ts +16 -7
- package/src/store/store-types.test.ts +1 -1
- package/src/store/store-types.ts +10 -56
- package/src/store/store.ts +148 -71
- package/src/utils/dev.ts +1 -1
- package/src/utils/stack-info.ts +4 -1
|
@@ -54,7 +54,7 @@ Vitest.describe('otel', () => {
|
|
|
54
54
|
}
|
|
55
55
|
})
|
|
56
56
|
|
|
57
|
-
Vitest.
|
|
57
|
+
Vitest.live('otel', () =>
|
|
58
58
|
Effect.gen(function* () {
|
|
59
59
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
60
60
|
|
|
@@ -93,7 +93,7 @@ Vitest.describe('otel', () => {
|
|
|
93
93
|
),
|
|
94
94
|
)
|
|
95
95
|
|
|
96
|
-
Vitest.
|
|
96
|
+
Vitest.live('with thunks', () =>
|
|
97
97
|
Effect.gen(function* () {
|
|
98
98
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
99
99
|
|
|
@@ -150,7 +150,7 @@ Vitest.describe('otel', () => {
|
|
|
150
150
|
),
|
|
151
151
|
)
|
|
152
152
|
|
|
153
|
-
Vitest.
|
|
153
|
+
Vitest.live('with thunks with query builder and without labels', () =>
|
|
154
154
|
Effect.gen(function* () {
|
|
155
155
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
156
156
|
|
|
@@ -195,7 +195,7 @@ Vitest.describe('otel', () => {
|
|
|
195
195
|
),
|
|
196
196
|
)
|
|
197
197
|
|
|
198
|
-
Vitest.
|
|
198
|
+
Vitest.live('QueryBuilder subscription - basic functionality', () =>
|
|
199
199
|
Effect.gen(function* () {
|
|
200
200
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
201
201
|
|
|
@@ -239,7 +239,7 @@ Vitest.describe('otel', () => {
|
|
|
239
239
|
),
|
|
240
240
|
)
|
|
241
241
|
|
|
242
|
-
Vitest.
|
|
242
|
+
Vitest.live('QueryBuilder subscription - skipInitialRun', () =>
|
|
243
243
|
Effect.gen(function* () {
|
|
244
244
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
245
245
|
|
|
@@ -286,7 +286,7 @@ Vitest.describe('otel', () => {
|
|
|
286
286
|
),
|
|
287
287
|
)
|
|
288
288
|
|
|
289
|
-
Vitest.
|
|
289
|
+
Vitest.live('QueryBuilder subscription - unsubscribe functionality', () =>
|
|
290
290
|
Effect.gen(function* () {
|
|
291
291
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
292
292
|
|
|
@@ -338,7 +338,7 @@ Vitest.describe('otel', () => {
|
|
|
338
338
|
),
|
|
339
339
|
)
|
|
340
340
|
|
|
341
|
-
Vitest.
|
|
341
|
+
Vitest.live('QueryBuilder subscription - async iterator', () =>
|
|
342
342
|
Effect.gen(function* () {
|
|
343
343
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
344
344
|
|
|
@@ -386,7 +386,7 @@ Vitest.describe('otel', () => {
|
|
|
386
386
|
),
|
|
387
387
|
)
|
|
388
388
|
|
|
389
|
-
Vitest.
|
|
389
|
+
Vitest.live('QueryBuilder subscription - async iterator with skipInitialRun', () =>
|
|
390
390
|
Effect.gen(function* () {
|
|
391
391
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
392
392
|
|
|
@@ -435,7 +435,7 @@ Vitest.describe('otel', () => {
|
|
|
435
435
|
),
|
|
436
436
|
)
|
|
437
437
|
|
|
438
|
-
Vitest.
|
|
438
|
+
Vitest.live('QueryBuilder subscription - direct table subscription', () =>
|
|
439
439
|
Effect.gen(function* () {
|
|
440
440
|
const { store, exporter, span, provider } = yield* makeQuery
|
|
441
441
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import * as otel from '@opentelemetry/api'
|
|
2
|
+
|
|
1
3
|
import type { Bindable, QueryBuilder } from '@livestore/common'
|
|
2
4
|
import {
|
|
3
|
-
getDurationMsFromSpan,
|
|
4
5
|
getResultSchema,
|
|
5
6
|
isQueryBuilder,
|
|
6
7
|
prepareBindValues,
|
|
7
8
|
QueryBuilderAstSymbol,
|
|
8
|
-
|
|
9
|
+
resolveSessionIdSymbolInBindValues,
|
|
9
10
|
SessionIdSymbol,
|
|
10
11
|
UnknownError,
|
|
11
12
|
} from '@livestore/common'
|
|
12
13
|
import { deepEqual, objectToString, omitUndefineds, shouldNeverHappen } from '@livestore/utils'
|
|
13
|
-
import { Equal, Hash, Predicate, Schema,
|
|
14
|
-
import * as otel from '@opentelemetry/api'
|
|
14
|
+
import { Equal, Hash, Predicate, Result, Schema, SchemaIssue } from '@livestore/utils/effect'
|
|
15
15
|
|
|
16
16
|
import type { Thunk } from '../reactive.ts'
|
|
17
17
|
import { isThunk, NOT_REFRESHED_YET } from '../reactive.ts'
|
|
@@ -19,12 +19,12 @@ import type { RefreshReason } from '../store/store-types.ts'
|
|
|
19
19
|
import { StoreInternalsSymbol } from '../store/store-types.ts'
|
|
20
20
|
import { isValidFunctionString } from '../utils/function-string.ts'
|
|
21
21
|
import type { DepKey, GetAtomResult, LiveQueryDef, ReactivityGraph, ReactivityGraphContext } from './base-class.ts'
|
|
22
|
-
import { depsToString, LiveStoreQueryBase, makeGetAtomResult, withRCMap } from './base-class.ts'
|
|
22
|
+
import { depsToString, isLiveQueryDef, LiveStoreQueryBase, makeGetAtomResult, withRCMap } from './base-class.ts'
|
|
23
23
|
import { makeExecBeforeFirstRun, rowQueryLabel } from './client-document-get-query.ts'
|
|
24
24
|
|
|
25
25
|
export type QueryInputRaw<TDecoded, TEncoded> = {
|
|
26
26
|
query: string
|
|
27
|
-
schema: Schema.
|
|
27
|
+
schema: Schema.Codec<TDecoded, TEncoded>
|
|
28
28
|
bindValues?: Bindable
|
|
29
29
|
/**
|
|
30
30
|
* Can be provided explicitly to slightly speed up initial query performance
|
|
@@ -103,7 +103,11 @@ export const queryDb: {
|
|
|
103
103
|
} = (queryInput, options) => {
|
|
104
104
|
const { queryString, extraDeps } = getQueryStringAndExtraDeps(queryInput)
|
|
105
105
|
|
|
106
|
-
const hash = [
|
|
106
|
+
const hash = [
|
|
107
|
+
queryString,
|
|
108
|
+
options?.deps !== undefined ? depsToString(options.deps) : undefined,
|
|
109
|
+
depsToString(extraDeps),
|
|
110
|
+
]
|
|
107
111
|
.filter(Boolean)
|
|
108
112
|
.join('-')
|
|
109
113
|
|
|
@@ -112,7 +116,7 @@ export const queryDb: {
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
if (hash.trim() === '') {
|
|
115
|
-
|
|
119
|
+
return shouldNeverHappen('Invalid query hash for query:', objectToString(queryInput))
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
const label = options?.label ?? queryString
|
|
@@ -131,8 +135,8 @@ export const queryDb: {
|
|
|
131
135
|
}),
|
|
132
136
|
label,
|
|
133
137
|
hash,
|
|
134
|
-
[Equal.symbol](that:
|
|
135
|
-
return this.hash === that.hash
|
|
138
|
+
[Equal.symbol](that: Equal.Equal): boolean {
|
|
139
|
+
return isLiveQueryDef(that) && that._tag === 'def' && this.hash === that.hash
|
|
136
140
|
},
|
|
137
141
|
[Hash.symbol](): number {
|
|
138
142
|
return Hash.string(this.hash)
|
|
@@ -214,9 +218,13 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
214
218
|
|
|
215
219
|
this.mapResult = map === undefined ? (rows: any) => rows as TResult : map
|
|
216
220
|
|
|
217
|
-
const schemaRef: { current: Schema.
|
|
221
|
+
const schemaRef: { current: Schema.Codec<any, any> | undefined } = {
|
|
218
222
|
current:
|
|
219
|
-
typeof queryInput === 'function'
|
|
223
|
+
typeof queryInput === 'function'
|
|
224
|
+
? undefined
|
|
225
|
+
: isQueryBuilder(queryInput) === true
|
|
226
|
+
? undefined
|
|
227
|
+
: queryInput.schema,
|
|
220
228
|
}
|
|
221
229
|
|
|
222
230
|
const execBeforeFirstRunRef: {
|
|
@@ -232,7 +240,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
232
240
|
const fromQueryBuilder = (qb: QueryBuilder.Any, otelContext: otel.Context | undefined) => {
|
|
233
241
|
try {
|
|
234
242
|
const qbRes = qb.asSql()
|
|
235
|
-
const schema = getResultSchema(qb) as Schema.
|
|
243
|
+
const schema = getResultSchema(qb) as Schema.Codec<TResultSchema, ReadonlyArray<any>>
|
|
236
244
|
const ast = qb[QueryBuilderAstSymbol]
|
|
237
245
|
|
|
238
246
|
return {
|
|
@@ -320,9 +328,9 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
320
328
|
|
|
321
329
|
const queriedTablesRef: { current: Set<string> | undefined } = { current: undefined }
|
|
322
330
|
|
|
323
|
-
const makeResultsEqual = (resultSchema: Schema.
|
|
331
|
+
const makeResultsEqual = (resultSchema: Schema.Codec<any, any>) => {
|
|
324
332
|
// Creating the equivalence function eagerly in outer scope as it might be expensive
|
|
325
|
-
const eq = Schema.
|
|
333
|
+
const eq = Schema.toEquivalence(resultSchema)
|
|
326
334
|
return (a: TResult, b: TResult) => (a === NOT_REFRESHED_YET || b === NOT_REFRESHED_YET ? false : eq(a, b))
|
|
327
335
|
}
|
|
328
336
|
|
|
@@ -342,13 +350,15 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
342
350
|
'db:...', // NOTE span name will be overridden further down
|
|
343
351
|
{
|
|
344
352
|
attributes: {
|
|
345
|
-
'livestore.debugRefreshReason':
|
|
346
|
-
|
|
347
|
-
|
|
353
|
+
'livestore.debugRefreshReason':
|
|
354
|
+
Predicate.hasProperty(debugRefreshReason, 'label') === true
|
|
355
|
+
? (debugRefreshReason.label as string)
|
|
356
|
+
: debugRefreshReason?._tag,
|
|
348
357
|
},
|
|
349
358
|
},
|
|
350
359
|
otelContext ?? queryContext.rootOtelContext,
|
|
351
360
|
(span) => {
|
|
361
|
+
const startTimePerfNow = performance.now()
|
|
352
362
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
353
363
|
const { store } = queryContext
|
|
354
364
|
|
|
@@ -357,9 +367,10 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
357
367
|
execBeforeFirstRunRef.current = undefined
|
|
358
368
|
}
|
|
359
369
|
|
|
360
|
-
const queryInputResult =
|
|
361
|
-
|
|
362
|
-
|
|
370
|
+
const queryInputResult =
|
|
371
|
+
isThunk(queryInputRaw$OrQueryInputRaw) === true
|
|
372
|
+
? (get(queryInputRaw$OrQueryInputRaw, otelContext, debugRefreshReason) as TQueryInputRaw)
|
|
373
|
+
: (queryInputRaw$OrQueryInputRaw as TQueryInputRaw)
|
|
363
374
|
|
|
364
375
|
const sqlString = queryInputResult.query
|
|
365
376
|
const bindValues = queryInputResult.bindValues
|
|
@@ -368,9 +379,10 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
368
379
|
queriedTablesRef.current = store[StoreInternalsSymbol].sqliteDbWrapper.getTablesUsed(sqlString)
|
|
369
380
|
}
|
|
370
381
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
382
|
+
// Live query inputs may be cached and re-run as reactive dependencies change.
|
|
383
|
+
// Resolve SessionIdSymbol per execution so the cached input stays symbolic and session-agnostic.
|
|
384
|
+
const resolvedBindValues =
|
|
385
|
+
bindValues === undefined ? undefined : resolveSessionIdSymbolInBindValues(bindValues, store.sessionId)
|
|
374
386
|
|
|
375
387
|
// Establish a reactive dependency on the tables used in the query
|
|
376
388
|
for (const tableName of queriedTablesRef.current) {
|
|
@@ -385,7 +397,7 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
385
397
|
|
|
386
398
|
const rawDbResults = store[StoreInternalsSymbol].sqliteDbWrapper.cachedSelect(
|
|
387
399
|
sqlString,
|
|
388
|
-
|
|
400
|
+
resolvedBindValues !== undefined ? prepareBindValues(resolvedBindValues, sqlString) : undefined,
|
|
389
401
|
{
|
|
390
402
|
otelContext,
|
|
391
403
|
...(queriedTablesRef.current !== undefined ? { queriedTables: queriedTablesRef.current } : {}),
|
|
@@ -394,10 +406,10 @@ export class LiveStoreDbQuery<TResultSchema, TResult = TResultSchema> extends Li
|
|
|
394
406
|
|
|
395
407
|
span.setAttribute('sql.rowsCount', rawDbResults.length)
|
|
396
408
|
|
|
397
|
-
const parsedResult = Schema.
|
|
409
|
+
const parsedResult = Schema.decodeResult(schemaRef.current!)(rawDbResults)
|
|
398
410
|
|
|
399
|
-
if (parsedResult
|
|
400
|
-
const parseErrorStr =
|
|
411
|
+
if (Result.isFailure(parsedResult) === true) {
|
|
412
|
+
const parseErrorStr = SchemaIssue.makeFormatterDefault()(parsedResult.failure.issue)
|
|
401
413
|
const expectedSchemaStr = String(schemaRef.current!.ast)
|
|
402
414
|
const bindValuesStr = bindValues === undefined ? '' : `\nBind values: ${JSON.stringify(bindValues)}`
|
|
403
415
|
|
|
@@ -418,11 +430,11 @@ Result:`,
|
|
|
418
430
|
)
|
|
419
431
|
}
|
|
420
432
|
|
|
421
|
-
const result = this.mapResult(parsedResult.
|
|
433
|
+
const result = this.mapResult(parsedResult.success)
|
|
422
434
|
|
|
423
435
|
span.end()
|
|
424
436
|
|
|
425
|
-
const durationMs =
|
|
437
|
+
const durationMs = performance.now() - startTimePerfNow
|
|
426
438
|
|
|
427
439
|
this.executionTimes.push(durationMs)
|
|
428
440
|
|
|
@@ -8,7 +8,7 @@ import { computed } from './computed.ts'
|
|
|
8
8
|
import { signal } from './signal.ts'
|
|
9
9
|
|
|
10
10
|
Vitest.describe('signal', () => {
|
|
11
|
-
Vitest.
|
|
11
|
+
Vitest.live('should be able to create a signal', () =>
|
|
12
12
|
Effect.gen(function* () {
|
|
13
13
|
const num$ = signal(0, { label: 'num$' })
|
|
14
14
|
|
|
@@ -24,7 +24,7 @@ Vitest.describe('signal', () => {
|
|
|
24
24
|
}),
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
-
Vitest.
|
|
27
|
+
Vitest.live('counter example', () =>
|
|
28
28
|
Effect.gen(function* () {
|
|
29
29
|
const count$ = signal(0, { label: 'count$' })
|
|
30
30
|
|
|
@@ -4,7 +4,7 @@ import { nanoid } from '@livestore/utils/nanoid'
|
|
|
4
4
|
import type * as RG from '../reactive.ts'
|
|
5
5
|
import type { RefreshReason } from '../store/store-types.ts'
|
|
6
6
|
import type { ISignal, ReactivityGraph, ReactivityGraphContext, SignalDef } from './base-class.ts'
|
|
7
|
-
import { LiveStoreQueryBase, withRCMap } from './base-class.ts'
|
|
7
|
+
import { isSignalDef, LiveStoreQueryBase, withRCMap } from './base-class.ts'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates a reactive signal for ephemeral, local-only state that isn't persisted to the database.
|
|
@@ -70,8 +70,8 @@ export const signal = <T>(
|
|
|
70
70
|
def,
|
|
71
71
|
}),
|
|
72
72
|
),
|
|
73
|
-
[Equal.symbol](that:
|
|
74
|
-
return this.hash === that.hash
|
|
73
|
+
[Equal.symbol](that: Equal.Equal): boolean {
|
|
74
|
+
return isSignalDef(that) && this.hash === that.hash
|
|
75
75
|
},
|
|
76
76
|
[Hash.symbol](): number {
|
|
77
77
|
return Hash.string(this.hash)
|
package/src/reactive.ts
CHANGED
|
@@ -25,17 +25,13 @@ import type * as otel from '@opentelemetry/api'
|
|
|
25
25
|
|
|
26
26
|
import { BoundArray } from '@livestore/common'
|
|
27
27
|
import { deepEqual, omitUndefineds, shouldNeverHappen } from '@livestore/utils'
|
|
28
|
-
import type
|
|
28
|
+
import { Schema, type Types } from '@livestore/utils/effect'
|
|
29
29
|
// import { getDurationMsFromSpan } from './otel.ts'
|
|
30
30
|
|
|
31
31
|
export const NOT_REFRESHED_YET = Symbol.for('NOT_REFRESHED_YET')
|
|
32
32
|
export type NOT_REFRESHED_YET = typeof NOT_REFRESHED_YET
|
|
33
33
|
|
|
34
|
-
export type GetAtom = <T>(
|
|
35
|
-
atom: Atom<T, any, any>,
|
|
36
|
-
otelContext?: otel.Context ,
|
|
37
|
-
debugRefreshReason?: TODO ,
|
|
38
|
-
) => T
|
|
34
|
+
export type GetAtom = <T>(atom: Atom<T, any, any>, otelContext?: otel.Context, debugRefreshReason?: TODO) => T
|
|
39
35
|
|
|
40
36
|
export type Ref<T, TContext, TDebugRefreshReason extends DebugRefreshReason> = {
|
|
41
37
|
_tag: 'ref'
|
|
@@ -79,7 +75,7 @@ export type Effect<TDebugRefreshReason extends DebugRefreshReason> = {
|
|
|
79
75
|
_tag: 'effect'
|
|
80
76
|
id: string
|
|
81
77
|
isDestroyed: boolean
|
|
82
|
-
doEffect: (otelContext?: otel.Context
|
|
78
|
+
doEffect: (otelContext?: otel.Context, debugRefreshReason?: TDebugRefreshReason) => void
|
|
83
79
|
sub: Set<Atom<any, TODO, TODO>>
|
|
84
80
|
label?: string | undefined
|
|
85
81
|
invocations: number
|
|
@@ -246,13 +242,11 @@ export class ReactiveGraph<
|
|
|
246
242
|
otelContext: otel.Context | undefined,
|
|
247
243
|
debugRefreshReason: TDebugRefreshReason | undefined,
|
|
248
244
|
) => T,
|
|
249
|
-
options?:
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
,
|
|
245
|
+
options?: {
|
|
246
|
+
label?: string
|
|
247
|
+
meta?: any
|
|
248
|
+
equal?: (a: T, b: T) => boolean
|
|
249
|
+
},
|
|
256
250
|
): Thunk<T, TContext, TDebugRefreshReason> {
|
|
257
251
|
const thunk: Thunk<T, TContext, TDebugRefreshReason> = {
|
|
258
252
|
_tag: 'thunk',
|
|
@@ -291,7 +285,7 @@ export class ReactiveGraph<
|
|
|
291
285
|
debugRefreshReason,
|
|
292
286
|
)
|
|
293
287
|
|
|
294
|
-
const resultChanged = !
|
|
288
|
+
const resultChanged = !thunk.equal(thunk.previousResult as T, result)
|
|
295
289
|
|
|
296
290
|
const debugInfoForAtom = {
|
|
297
291
|
atom: serializeAtom(thunk, false),
|
|
@@ -384,7 +378,7 @@ export class ReactiveGraph<
|
|
|
384
378
|
otelContext: otel.Context | undefined,
|
|
385
379
|
debugRefreshReason: DebugRefreshReason | undefined,
|
|
386
380
|
) => void,
|
|
387
|
-
options?: { label?: string }
|
|
381
|
+
options?: { label?: string },
|
|
388
382
|
): Effect<TDebugRefreshReason> {
|
|
389
383
|
const effect: Effect<TDebugRefreshReason> = {
|
|
390
384
|
_tag: 'effect',
|
|
@@ -422,26 +416,22 @@ export class ReactiveGraph<
|
|
|
422
416
|
setRef<T>(
|
|
423
417
|
ref: Ref<T, TContext, TDebugRefreshReason>,
|
|
424
418
|
val: T,
|
|
425
|
-
options?:
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
,
|
|
419
|
+
options?: {
|
|
420
|
+
skipRefresh?: boolean
|
|
421
|
+
debugRefreshReason?: TDebugRefreshReason
|
|
422
|
+
otelContext?: otel.Context
|
|
423
|
+
},
|
|
432
424
|
) {
|
|
433
425
|
this.setRefs([[ref, val]], options)
|
|
434
426
|
}
|
|
435
427
|
|
|
436
428
|
setRefs<T>(
|
|
437
429
|
refs: [Ref<T, TContext, TDebugRefreshReason>, T][],
|
|
438
|
-
options?:
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
,
|
|
430
|
+
options?: {
|
|
431
|
+
skipRefresh?: boolean
|
|
432
|
+
debugRefreshReason?: TDebugRefreshReason
|
|
433
|
+
otelContext?: otel.Context
|
|
434
|
+
},
|
|
445
435
|
) {
|
|
446
436
|
const effectsToRefresh = new Set<Effect<TDebugRefreshReason>>()
|
|
447
437
|
for (const [ref, val] of refs) {
|
|
@@ -640,11 +630,31 @@ const serializeAtom = (atom: Atom<any, unknown, any>, includeResult: boolean): S
|
|
|
640
630
|
super_.push(a.id)
|
|
641
631
|
}
|
|
642
632
|
|
|
643
|
-
const previousResult: EncodedOption<string> =
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
633
|
+
const previousResult: EncodedOption<string> =
|
|
634
|
+
includeResult === true
|
|
635
|
+
? encodedOptionSome(
|
|
636
|
+
atom.previousResult === NOT_REFRESHED_YET
|
|
637
|
+
? '"SYMBOL_NOT_REFRESHED_YET"'
|
|
638
|
+
: JSON.stringify(atom.previousResult, (key, nestedValue) => {
|
|
639
|
+
if (Schema.isSchema(nestedValue) === false) return nestedValue
|
|
640
|
+
|
|
641
|
+
// Query inputs carry schemas for result decoding, but graph snapshots use previousResult
|
|
642
|
+
// to explain reactive data flow. Omitting that field preserves the stable query shape
|
|
643
|
+
// without embedding Effect full schema object graph.
|
|
644
|
+
if (key === 'schema') return undefined
|
|
645
|
+
|
|
646
|
+
const annotations = Schema.resolveAnnotations(nestedValue)
|
|
647
|
+
|
|
648
|
+
return omitUndefineds({
|
|
649
|
+
_tag: 'Schema',
|
|
650
|
+
ast: nestedValue.ast._tag,
|
|
651
|
+
identifier: annotations?.identifier,
|
|
652
|
+
title: annotations?.title,
|
|
653
|
+
hash: Schema.hash(nestedValue),
|
|
654
|
+
})
|
|
655
|
+
}),
|
|
656
|
+
)
|
|
657
|
+
: encodedOptionNone()
|
|
648
658
|
|
|
649
659
|
if (atom._tag === 'ref') {
|
|
650
660
|
return {
|