@livestore/livestore 0.3.0-dev.11 → 0.3.0-dev.5
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/SynchronousDatabaseWrapper.d.ts +5 -14
- package/dist/SynchronousDatabaseWrapper.d.ts.map +1 -1
- package/dist/SynchronousDatabaseWrapper.js +4 -24
- package/dist/SynchronousDatabaseWrapper.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +8 -12
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +3 -13
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/live-queries/base-class.d.ts +21 -64
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js +13 -56
- package/dist/live-queries/base-class.js.map +1 -1
- package/dist/live-queries/computed.d.ts +7 -7
- package/dist/live-queries/computed.d.ts.map +1 -1
- package/dist/live-queries/computed.js +11 -35
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db.d.ts +15 -12
- package/dist/live-queries/db.d.ts.map +1 -1
- package/dist/live-queries/db.js +25 -44
- package/dist/live-queries/db.js.map +1 -1
- package/dist/live-queries/db.test.js +14 -16
- package/dist/live-queries/db.test.js.map +1 -1
- package/dist/live-queries/graphql.d.ts +8 -8
- package/dist/live-queries/graphql.d.ts.map +1 -1
- package/dist/live-queries/graphql.js +9 -35
- package/dist/live-queries/graphql.js.map +1 -1
- package/dist/reactive.d.ts +13 -15
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +9 -15
- package/dist/reactive.js.map +1 -1
- package/dist/row-query-utils.d.ts +4 -4
- package/dist/row-query-utils.d.ts.map +1 -1
- package/dist/row-query-utils.js +10 -14
- package/dist/row-query-utils.js.map +1 -1
- package/dist/store/create-store.d.ts +4 -3
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/create-store.js +7 -7
- package/dist/store/create-store.js.map +1 -1
- package/dist/store/devtools.d.ts +2 -2
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js +15 -15
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +5 -10
- 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 +16 -34
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +77 -129
- package/dist/store/store.js.map +1 -1
- package/dist/utils/stack-info.d.ts.map +1 -1
- package/dist/utils/stack-info.js +1 -6
- package/dist/utils/stack-info.js.map +1 -1
- package/dist/utils/stack-info.test.js +1 -54
- package/dist/utils/stack-info.test.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +6 -2
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/dist/utils/tests/fixture.js +5 -3
- package/dist/utils/tests/fixture.js.map +1 -1
- package/dist/utils/tests/mod.d.ts +0 -1
- package/dist/utils/tests/mod.d.ts.map +1 -1
- package/dist/utils/tests/mod.js +0 -1
- package/dist/utils/tests/mod.js.map +1 -1
- package/package.json +12 -12
- package/src/{SqliteDbWrapper.ts → SynchronousDatabaseWrapper.ts} +11 -41
- package/src/effect/LiveStore.ts +15 -26
- package/src/global-state.ts +20 -0
- package/src/index.ts +7 -14
- package/src/live-queries/__snapshots__/{db-query.test.ts.snap → db.test.ts.snap} +42 -196
- package/src/live-queries/base-class.ts +40 -160
- package/src/live-queries/computed.ts +19 -45
- package/src/live-queries/{db-query.test.ts → db.test.ts} +11 -21
- package/src/live-queries/{db-query.ts → db.ts} +39 -97
- package/src/live-queries/graphql.ts +21 -47
- package/src/reactive.ts +27 -52
- package/src/row-query-utils.ts +18 -29
- package/src/store/create-store.ts +23 -20
- package/src/store/devtools.ts +17 -17
- package/src/store/store-types.ts +5 -7
- package/src/store/store.ts +122 -231
- package/src/utils/stack-info.test.ts +1 -58
- package/src/utils/stack-info.ts +1 -6
- package/src/utils/tests/fixture.ts +7 -2
- package/src/utils/tests/mod.ts +0 -1
- package/dist/SqliteDbWrapper.d.ts +0 -54
- package/dist/SqliteDbWrapper.d.ts.map +0 -1
- package/dist/SqliteDbWrapper.js +0 -212
- package/dist/SqliteDbWrapper.js.map +0 -1
- package/dist/__tests__/fixture.d.ts +0 -252
- package/dist/__tests__/fixture.d.ts.map +0 -1
- package/dist/__tests__/fixture.js +0 -18
- package/dist/__tests__/fixture.js.map +0 -1
- package/dist/live-queries/db-query.d.ts +0 -67
- package/dist/live-queries/db-query.d.ts.map +0 -1
- package/dist/live-queries/db-query.js +0 -244
- package/dist/live-queries/db-query.js.map +0 -1
- package/dist/live-queries/db-query.test.d.ts +0 -2
- package/dist/live-queries/db-query.test.d.ts.map +0 -1
- package/dist/live-queries/db-query.test.js +0 -123
- package/dist/live-queries/db-query.test.js.map +0 -1
- package/dist/live-queries/make-ref.d.ts +0 -20
- package/dist/live-queries/make-ref.d.ts.map +0 -1
- package/dist/live-queries/make-ref.js +0 -33
- package/dist/live-queries/make-ref.js.map +0 -1
- package/dist/store/store.test.d.ts +0 -2
- package/dist/store/store.test.d.ts.map +0 -1
- package/dist/store/store.test.js +0 -27
- package/dist/store/store.test.js.map +0 -1
- package/dist/utils/expo.d.ts +0 -2
- package/dist/utils/expo.d.ts.map +0 -1
- package/dist/utils/expo.js +0 -8
- package/dist/utils/expo.js.map +0 -1
- package/dist/utils/function-string.d.ts +0 -7
- package/dist/utils/function-string.d.ts.map +0 -1
- package/dist/utils/function-string.js +0 -9
- package/dist/utils/function-string.js.map +0 -1
- package/src/live-queries/make-ref.ts +0 -47
- package/src/utils/function-string.ts +0 -12
@@ -11,14 +11,14 @@ import { deepEqual, shouldNeverHappen } from '@livestore/utils'
|
|
11
11
|
import { Predicate, Schema, TreeFormatter } from '@livestore/utils/effect'
|
12
12
|
import * as otel from '@opentelemetry/api'
|
13
13
|
|
14
|
+
import { globalReactivityGraph } from '../global-state.js'
|
14
15
|
import type { Thunk } from '../reactive.js'
|
15
16
|
import { isThunk, NOT_REFRESHED_YET } from '../reactive.js'
|
16
17
|
import { makeExecBeforeFirstRun, rowQueryLabel } from '../row-query-utils.js'
|
17
18
|
import type { RefreshReason } from '../store/store-types.js'
|
18
|
-
import { isValidFunctionString } from '../utils/function-string.js'
|
19
19
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
20
|
-
import type {
|
21
|
-
import {
|
20
|
+
import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
|
21
|
+
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
22
22
|
|
23
23
|
export type QueryInputRaw<TDecoded, TEncoded, TQueryInfo extends QueryInfo> = {
|
24
24
|
query: string
|
@@ -31,12 +31,9 @@ export type QueryInputRaw<TDecoded, TEncoded, TQueryInfo extends QueryInfo> = {
|
|
31
31
|
*/
|
32
32
|
queriedTables?: Set<string>
|
33
33
|
queryInfo?: TQueryInfo
|
34
|
-
execBeforeFirstRun?: (ctx:
|
34
|
+
execBeforeFirstRun?: (ctx: QueryContext) => void
|
35
35
|
}
|
36
36
|
|
37
|
-
export const isQueryInputRaw = (value: unknown): value is QueryInputRaw<any, any, any> =>
|
38
|
-
Predicate.hasProperty(value, 'query') && Predicate.hasProperty(value, 'schema')
|
39
|
-
|
40
37
|
export type QueryInput<TDecoded, TEncoded, TQueryInfo extends QueryInfo> =
|
41
38
|
| QueryInputRaw<TDecoded, TEncoded, TQueryInfo>
|
42
39
|
| QueryBuilder<TDecoded, any, any, TQueryInfo>
|
@@ -55,10 +52,10 @@ export const queryDb: {
|
|
55
52
|
* Used for debugging / devtools
|
56
53
|
*/
|
57
54
|
label?: string
|
58
|
-
|
59
|
-
|
55
|
+
reactivityGraph?: ReactivityGraph
|
56
|
+
otelContext?: otel.Context
|
60
57
|
},
|
61
|
-
):
|
58
|
+
): LiveQuery<TResult, TQueryInfo>
|
62
59
|
// NOTE in this "thunk case", we can't directly derive label/queryInfo from the queryInput,
|
63
60
|
// so the caller needs to provide them explicitly otherwise queryInfo will be set to `None`,
|
64
61
|
// and label will be set during the query execution
|
@@ -72,47 +69,20 @@ export const queryDb: {
|
|
72
69
|
* Used for debugging / devtools
|
73
70
|
*/
|
74
71
|
label?: string
|
75
|
-
|
72
|
+
reactivityGraph?: ReactivityGraph
|
76
73
|
queryInfo?: TQueryInfo
|
74
|
+
otelContext?: otel.Context
|
77
75
|
},
|
78
|
-
):
|
79
|
-
} = (queryInput, options) =>
|
80
|
-
|
81
|
-
|
82
|
-
:
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
const hash = options?.deps ? queryString + '-' + depsToString(options.deps) : queryString
|
89
|
-
if (isValidFunctionString(hash)._tag === 'invalid') {
|
90
|
-
throw new Error(`On Expo/React Native, db queries must provide a \`deps\` option`)
|
91
|
-
}
|
92
|
-
|
93
|
-
const label = options?.label ?? queryString
|
94
|
-
|
95
|
-
return {
|
96
|
-
_tag: 'def',
|
97
|
-
id: ++defCounterRef.current,
|
98
|
-
make: withRCMap(hash, (ctx, otelContext) => {
|
99
|
-
// TODO onDestroy
|
100
|
-
return new LiveStoreDbQuery({
|
101
|
-
reactivityGraph: ctx.reactivityGraph.deref()!,
|
102
|
-
queryInput,
|
103
|
-
label,
|
104
|
-
map: options?.map,
|
105
|
-
// We're not falling back to `None` here as the queryInfo will be set dynamically
|
106
|
-
queryInfo: options?.queryInfo,
|
107
|
-
otelContext,
|
108
|
-
})
|
109
|
-
}),
|
110
|
-
label,
|
111
|
-
hash,
|
112
|
-
queryInfo:
|
113
|
-
options?.queryInfo ?? (isQueryBuilder(queryInput) ? queryInfoFromQueryBuilder(queryInput) : { _tag: 'None' }),
|
114
|
-
}
|
115
|
-
}
|
76
|
+
): LiveQuery<TResult, TQueryInfo>
|
77
|
+
} = (queryInput, options) =>
|
78
|
+
new LiveStoreDbQuery({
|
79
|
+
queryInput,
|
80
|
+
label: options?.label,
|
81
|
+
reactivityGraph: options?.reactivityGraph,
|
82
|
+
map: options?.map,
|
83
|
+
queryInfo: Predicate.hasProperty(options, 'queryInfo') ? (options.queryInfo as QueryInfo) : undefined,
|
84
|
+
otelContext: options?.otelContext,
|
85
|
+
})
|
116
86
|
|
117
87
|
/* An object encapsulating a reactive SQL query */
|
118
88
|
export class LiveStoreDbQuery<
|
@@ -123,16 +93,16 @@ export class LiveStoreDbQuery<
|
|
123
93
|
_tag: 'db' = 'db'
|
124
94
|
|
125
95
|
/** A reactive thunk representing the query text */
|
126
|
-
queryInput$: Thunk<
|
96
|
+
queryInput$: Thunk<QueryInput<TResultSchema, ReadonlyArray<any>, TQueryInfo>, QueryContext, RefreshReason> | undefined
|
127
97
|
|
128
98
|
/** A reactive thunk representing the query results */
|
129
|
-
results$: Thunk<TResult,
|
99
|
+
results$: Thunk<TResult, QueryContext, RefreshReason>
|
130
100
|
|
131
101
|
label: string
|
132
102
|
|
133
103
|
queryInfo: TQueryInfo
|
134
104
|
|
135
|
-
|
105
|
+
protected reactivityGraph
|
136
106
|
|
137
107
|
private mapResult: (rows: TResultSchema) => TResult
|
138
108
|
|
@@ -147,18 +117,17 @@ export class LiveStoreDbQuery<
|
|
147
117
|
label?: string
|
148
118
|
queryInput:
|
149
119
|
| QueryInput<TResultSchema, ReadonlyArray<any>, TQueryInfo>
|
150
|
-
| ((get: GetAtomResult, ctx:
|
151
|
-
reactivityGraph
|
120
|
+
| ((get: GetAtomResult, ctx: QueryContext) => QueryInput<TResultSchema, ReadonlyArray<any>, TQueryInfo>)
|
121
|
+
reactivityGraph?: ReactivityGraph
|
152
122
|
map?: (rows: TResultSchema) => TResult
|
153
123
|
queryInfo?: TQueryInfo
|
154
|
-
/** Only used for the initial query execution */
|
155
124
|
otelContext?: otel.Context
|
156
125
|
}) {
|
157
126
|
super()
|
158
127
|
|
159
128
|
let label = inputLabel ?? 'db(unknown)'
|
160
129
|
let queryInfo = inputQueryInfo ?? ({ _tag: 'None' } as TQueryInfo)
|
161
|
-
this.reactivityGraph = reactivityGraph
|
130
|
+
this.reactivityGraph = reactivityGraph ?? globalReactivityGraph
|
162
131
|
|
163
132
|
this.mapResult = map === undefined ? (rows: any) => rows as TResult : map
|
164
133
|
|
@@ -167,15 +136,13 @@ export class LiveStoreDbQuery<
|
|
167
136
|
typeof queryInput === 'function' ? undefined : isQueryBuilder(queryInput) ? undefined : queryInput.schema,
|
168
137
|
}
|
169
138
|
|
170
|
-
const execBeforeFirstRunRef: {
|
171
|
-
current: ((ctx: ReactivityGraphContext, otelContext: otel.Context) => void) | undefined
|
172
|
-
} = {
|
139
|
+
const execBeforeFirstRunRef: { current: ((ctx: QueryContext, otelContext: otel.Context) => void) | undefined } = {
|
173
140
|
current: undefined,
|
174
141
|
}
|
175
142
|
|
176
143
|
type TQueryInputRaw = QueryInputRaw<any, any, QueryInfo>
|
177
144
|
|
178
|
-
let queryInputRaw$OrQueryInputRaw: TQueryInputRaw | Thunk<TQueryInputRaw,
|
145
|
+
let queryInputRaw$OrQueryInputRaw: TQueryInputRaw | Thunk<TQueryInputRaw, QueryContext, RefreshReason>
|
179
146
|
|
180
147
|
const fromQueryBuilder = (qb: QueryBuilder.Any, otelContext: otel.Context | undefined) => {
|
181
148
|
try {
|
@@ -189,7 +156,7 @@ export class LiveStoreDbQuery<
|
|
189
156
|
schema,
|
190
157
|
bindValues: qbRes.bindValues,
|
191
158
|
queriedTables: new Set([ast.tableDef.sqliteDef.name]),
|
192
|
-
queryInfo:
|
159
|
+
queryInfo: ast._tag === 'RowQuery' ? { _tag: 'Row', table: ast.tableDef, id: ast.id } : { _tag: 'None' },
|
193
160
|
} satisfies TQueryInputRaw,
|
194
161
|
label: ast._tag === 'RowQuery' ? rowQueryLabel(ast.tableDef, ast.id) : qb.toString(),
|
195
162
|
execBeforeFirstRun:
|
@@ -211,10 +178,7 @@ export class LiveStoreDbQuery<
|
|
211
178
|
queryInputRaw$OrQueryInputRaw = this.reactivityGraph.makeThunk(
|
212
179
|
(get, setDebugInfo, ctx, otelContext) => {
|
213
180
|
const startMs = performance.now()
|
214
|
-
const queryInputResult = queryInput(
|
215
|
-
makeGetAtomResult(get, ctx, otelContext ?? ctx.rootOtelContext, this.dependencyQueriesRef),
|
216
|
-
ctx,
|
217
|
-
)
|
181
|
+
const queryInputResult = queryInput(makeGetAtomResult(get, otelContext ?? ctx.rootOtelContext), ctx)
|
218
182
|
const durationMs = performance.now() - startMs
|
219
183
|
|
220
184
|
let queryInputRaw: TQueryInputRaw
|
@@ -246,8 +210,6 @@ export class LiveStoreDbQuery<
|
|
246
210
|
equal: (a, b) => a.query === b.query && deepEqual(a.bindValues, b.bindValues),
|
247
211
|
},
|
248
212
|
)
|
249
|
-
|
250
|
-
this.queryInput$ = queryInputRaw$OrQueryInputRaw
|
251
213
|
} else {
|
252
214
|
let queryInputRaw: TQueryInputRaw
|
253
215
|
if (isQueryBuilder(queryInput)) {
|
@@ -291,16 +253,10 @@ export class LiveStoreDbQuery<
|
|
291
253
|
: undefined
|
292
254
|
|
293
255
|
const results$ = this.reactivityGraph.makeThunk<TResult>(
|
294
|
-
(get, setDebugInfo, queryContext, otelContext
|
256
|
+
(get, setDebugInfo, queryContext, otelContext) =>
|
295
257
|
queryContext.otelTracer.startActiveSpan(
|
296
258
|
'db:...', // NOTE span name will be overridden further down
|
297
|
-
{
|
298
|
-
attributes: {
|
299
|
-
'livestore.debugRefreshReason': Predicate.hasProperty(debugRefreshReason, 'label')
|
300
|
-
? (debugRefreshReason.label as string)
|
301
|
-
: debugRefreshReason?._tag,
|
302
|
-
},
|
303
|
-
},
|
259
|
+
{},
|
304
260
|
otelContext ?? queryContext.rootOtelContext,
|
305
261
|
(span) => {
|
306
262
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
@@ -312,14 +268,14 @@ export class LiveStoreDbQuery<
|
|
312
268
|
}
|
313
269
|
|
314
270
|
const queryInputResult = isThunk(queryInputRaw$OrQueryInputRaw)
|
315
|
-
? (get(queryInputRaw$OrQueryInputRaw, otelContext
|
271
|
+
? (get(queryInputRaw$OrQueryInputRaw, otelContext) as TQueryInputRaw)
|
316
272
|
: (queryInputRaw$OrQueryInputRaw as TQueryInputRaw)
|
317
273
|
|
318
274
|
const sqlString = queryInputResult.query
|
319
275
|
const bindValues = queryInputResult.bindValues
|
320
276
|
|
321
277
|
if (queriedTablesRef.current === undefined) {
|
322
|
-
queriedTablesRef.current = store.
|
278
|
+
queriedTablesRef.current = store.syncDbWrapper.getTablesUsed(sqlString)
|
323
279
|
}
|
324
280
|
|
325
281
|
if (bindValues !== undefined) {
|
@@ -329,20 +285,17 @@ export class LiveStoreDbQuery<
|
|
329
285
|
// Establish a reactive dependency on the tables used in the query
|
330
286
|
for (const tableName of queriedTablesRef.current) {
|
331
287
|
const tableRef = store.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`)
|
332
|
-
get(tableRef, otelContext
|
288
|
+
get(tableRef, otelContext)
|
333
289
|
}
|
334
290
|
|
335
291
|
span.setAttribute('sql.query', sqlString)
|
336
292
|
span.updateName(`db:${sqlString.slice(0, 50)}`)
|
337
293
|
|
338
|
-
const rawDbResults = store.
|
339
|
-
|
340
|
-
bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
|
341
|
-
|
342
|
-
|
343
|
-
otelContext,
|
344
|
-
},
|
345
|
-
)
|
294
|
+
const rawDbResults = store.syncDbWrapper.select<any>(sqlString, {
|
295
|
+
queriedTables: queriedTablesRef.current,
|
296
|
+
bindValues: bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
|
297
|
+
otelContext,
|
298
|
+
})
|
346
299
|
|
347
300
|
span.setAttribute('sql.rowsCount', rawDbResults.length)
|
348
301
|
|
@@ -393,21 +346,10 @@ Result:`,
|
|
393
346
|
}
|
394
347
|
|
395
348
|
destroy = () => {
|
396
|
-
this.isDestroyed = true
|
397
|
-
|
398
349
|
if (this.queryInput$ !== undefined) {
|
399
350
|
this.reactivityGraph.destroyNode(this.queryInput$)
|
400
351
|
}
|
401
352
|
|
402
353
|
this.reactivityGraph.destroyNode(this.results$)
|
403
|
-
|
404
|
-
for (const query of this.dependencyQueriesRef) {
|
405
|
-
query.deref()
|
406
|
-
}
|
407
354
|
}
|
408
355
|
}
|
409
|
-
|
410
|
-
const queryInfoFromQueryBuilder = (qb: QueryBuilder.Any): QueryInfo.Row | QueryInfo.None => {
|
411
|
-
const ast = qb[QueryBuilderAstSymbol]
|
412
|
-
return ast._tag === 'RowQuery' ? { _tag: 'Row', table: ast.tableDef, id: ast.id } : { _tag: 'None' }
|
413
|
-
}
|
@@ -5,12 +5,13 @@ import { Schema, TreeFormatter } from '@livestore/utils/effect'
|
|
5
5
|
import * as otel from '@opentelemetry/api'
|
6
6
|
import * as graphql from 'graphql'
|
7
7
|
|
8
|
+
import { globalReactivityGraph } from '../global-state.js'
|
8
9
|
import { isThunk, type Thunk } from '../reactive.js'
|
9
10
|
import type { Store } from '../store/store.js'
|
10
11
|
import type { BaseGraphQLContext, RefreshReason } from '../store/store-types.js'
|
11
12
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
12
|
-
import type {
|
13
|
-
import {
|
13
|
+
import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
|
14
|
+
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
14
15
|
|
15
16
|
export type MapResult<To, From> = ((res: From, get: GetAtomResult) => To) | Schema.Schema<To, From>
|
16
17
|
|
@@ -21,37 +22,17 @@ export const queryGraphQL = <
|
|
21
22
|
>(
|
22
23
|
document: DocumentNode<TResult, TVariableValues>,
|
23
24
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues),
|
24
|
-
|
25
|
+
{
|
26
|
+
label,
|
27
|
+
reactivityGraph,
|
28
|
+
map,
|
29
|
+
}: {
|
25
30
|
label?: string
|
26
|
-
|
31
|
+
reactivityGraph?: ReactivityGraph
|
27
32
|
map?: MapResult<TResultMapped, TResult>
|
28
|
-
deps?: DepKey
|
29
33
|
} = {},
|
30
|
-
):
|
31
|
-
|
32
|
-
const hash = options.deps
|
33
|
-
? depsToString(options.deps)
|
34
|
-
: (documentName ?? shouldNeverHappen('No document name found and no deps provided'))
|
35
|
-
const label = options.label ?? documentName ?? 'graphql'
|
36
|
-
const map = options.map
|
37
|
-
|
38
|
-
return {
|
39
|
-
_tag: 'def',
|
40
|
-
id: ++defCounterRef.current,
|
41
|
-
make: withRCMap(hash, (ctx, _otelContext) => {
|
42
|
-
return new LiveStoreGraphQLQuery({
|
43
|
-
document,
|
44
|
-
genVariableValues,
|
45
|
-
label,
|
46
|
-
map,
|
47
|
-
reactivityGraph: ctx.reactivityGraph.deref()!,
|
48
|
-
})
|
49
|
-
}),
|
50
|
-
label,
|
51
|
-
hash,
|
52
|
-
queryInfo: { _tag: 'None' },
|
53
|
-
}
|
54
|
-
}
|
34
|
+
): LiveQuery<TResultMapped, QueryInfo.None> =>
|
35
|
+
new LiveStoreGraphQLQuery({ document, genVariableValues, label, reactivityGraph, map })
|
55
36
|
|
56
37
|
export class LiveStoreGraphQLQuery<
|
57
38
|
TResult extends Record<string, any>,
|
@@ -65,13 +46,13 @@ export class LiveStoreGraphQLQuery<
|
|
65
46
|
document: DocumentNode<TResult, TVariableValues>
|
66
47
|
|
67
48
|
/** A reactive thunk representing the query results */
|
68
|
-
results$: Thunk<TResultMapped,
|
49
|
+
results$: Thunk<TResultMapped, QueryContext, RefreshReason>
|
69
50
|
|
70
|
-
variableValues$: Thunk<TVariableValues,
|
51
|
+
variableValues$: Thunk<TVariableValues, QueryContext, RefreshReason> | undefined
|
71
52
|
|
72
53
|
label: string
|
73
54
|
|
74
|
-
reactivityGraph: ReactivityGraph
|
55
|
+
protected reactivityGraph: ReactivityGraph
|
75
56
|
|
76
57
|
queryInfo: QueryInfo.None = { _tag: 'None' }
|
77
58
|
|
@@ -87,7 +68,7 @@ export class LiveStoreGraphQLQuery<
|
|
87
68
|
document: DocumentNode<TResult, TVariableValues>
|
88
69
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues)
|
89
70
|
label?: string
|
90
|
-
reactivityGraph
|
71
|
+
reactivityGraph?: ReactivityGraph
|
91
72
|
map?: MapResult<TResultMapped, TResult>
|
92
73
|
}) {
|
93
74
|
super()
|
@@ -97,7 +78,7 @@ export class LiveStoreGraphQLQuery<
|
|
97
78
|
this.label = labelWithDefault
|
98
79
|
this.document = document
|
99
80
|
|
100
|
-
this.reactivityGraph = reactivityGraph
|
81
|
+
this.reactivityGraph = reactivityGraph ?? globalReactivityGraph
|
101
82
|
|
102
83
|
this.mapResult =
|
103
84
|
map === undefined
|
@@ -121,10 +102,8 @@ export class LiveStoreGraphQLQuery<
|
|
121
102
|
|
122
103
|
if (typeof genVariableValues === 'function') {
|
123
104
|
variableValues$OrvariableValues = this.reactivityGraph.makeThunk(
|
124
|
-
(get, _setDebugInfo,
|
125
|
-
return genVariableValues(
|
126
|
-
makeGetAtomResult(get, ctx, otelContext ?? ctx.rootOtelContext, this.dependencyQueriesRef),
|
127
|
-
)
|
105
|
+
(get, _setDebugInfo, { rootOtelContext }, otelContext) => {
|
106
|
+
return genVariableValues(makeGetAtomResult(get, otelContext ?? rootOtelContext))
|
128
107
|
},
|
129
108
|
{ label: `${labelWithDefault}:variableValues`, meta: { liveStoreThunkType: 'graphql.variables' } },
|
130
109
|
)
|
@@ -135,10 +114,9 @@ export class LiveStoreGraphQLQuery<
|
|
135
114
|
|
136
115
|
const resultsLabel = `${labelWithDefault}:results`
|
137
116
|
this.results$ = this.reactivityGraph.makeThunk<TResultMapped>(
|
138
|
-
(get, setDebugInfo,
|
139
|
-
const { store, otelTracer, rootOtelContext } = ctx
|
117
|
+
(get, setDebugInfo, { store, otelTracer, rootOtelContext }, otelContext) => {
|
140
118
|
const variableValues = isThunk(variableValues$OrvariableValues)
|
141
|
-
? (get(variableValues$OrvariableValues
|
119
|
+
? (get(variableValues$OrvariableValues) as TVariableValues)
|
142
120
|
: (variableValues$OrvariableValues as TVariableValues)
|
143
121
|
const { result, queriedTables, durationMs } = this.queryOnce({
|
144
122
|
document,
|
@@ -146,7 +124,7 @@ export class LiveStoreGraphQLQuery<
|
|
146
124
|
otelContext: otelContext ?? rootOtelContext,
|
147
125
|
otelTracer,
|
148
126
|
store: store as Store<TContext>,
|
149
|
-
get: makeGetAtomResult(get,
|
127
|
+
get: makeGetAtomResult(get, otelContext ?? rootOtelContext),
|
150
128
|
})
|
151
129
|
|
152
130
|
// Add dependencies on any tables that were used
|
@@ -237,9 +215,5 @@ export class LiveStoreGraphQLQuery<
|
|
237
215
|
}
|
238
216
|
|
239
217
|
this.reactivityGraph.destroyNode(this.results$)
|
240
|
-
|
241
|
-
for (const query of this.dependencyQueriesRef) {
|
242
|
-
query.deref()
|
243
|
-
}
|
244
218
|
}
|
245
219
|
}
|
package/src/reactive.ts
CHANGED
@@ -32,11 +32,7 @@ import type * as otel from '@opentelemetry/api'
|
|
32
32
|
export const NOT_REFRESHED_YET = Symbol.for('NOT_REFRESHED_YET')
|
33
33
|
export type NOT_REFRESHED_YET = typeof NOT_REFRESHED_YET
|
34
34
|
|
35
|
-
export type GetAtom = <T>(
|
36
|
-
atom: Atom<T, any, any>,
|
37
|
-
otelContext?: otel.Context | undefined,
|
38
|
-
debugRefreshReason?: TODO | undefined,
|
39
|
-
) => T
|
35
|
+
export type GetAtom = <T>(atom: Atom<T, any, any>, otelContext?: otel.Context) => T
|
40
36
|
|
41
37
|
export type Ref<T, TContext, TDebugRefreshReason extends DebugRefreshReason> = {
|
42
38
|
_tag: 'ref'
|
@@ -46,7 +42,7 @@ export type Ref<T, TContext, TDebugRefreshReason extends DebugRefreshReason> = {
|
|
46
42
|
previousResult: T
|
47
43
|
computeResult: () => T
|
48
44
|
sub: Set<Atom<any, TContext, TDebugRefreshReason>> // always empty
|
49
|
-
super: Set<Thunk<any, TContext, TDebugRefreshReason> | Effect
|
45
|
+
super: Set<Thunk<any, TContext, TDebugRefreshReason> | Effect>
|
50
46
|
label?: string
|
51
47
|
/** Container for meta information (e.g. the LiveStore Store) */
|
52
48
|
meta?: any
|
@@ -62,7 +58,7 @@ export type Thunk<TResult, TContext, TDebugRefreshReason extends DebugRefreshRea
|
|
62
58
|
computeResult: (otelContext?: otel.Context, debugRefreshReason?: TDebugRefreshReason) => TResult
|
63
59
|
previousResult: TResult | NOT_REFRESHED_YET
|
64
60
|
sub: Set<Atom<any, TContext, TDebugRefreshReason>>
|
65
|
-
super: Set<Thunk<any, TContext, TDebugRefreshReason> | Effect
|
61
|
+
super: Set<Thunk<any, TContext, TDebugRefreshReason> | Effect>
|
66
62
|
label?: string
|
67
63
|
/** Container for meta information (e.g. the LiveStore Store) */
|
68
64
|
meta?: any
|
@@ -76,11 +72,11 @@ export type Atom<T, TContext, TDebugRefreshReason extends DebugRefreshReason> =
|
|
76
72
|
| Ref<T, TContext, TDebugRefreshReason>
|
77
73
|
| Thunk<T, TContext, TDebugRefreshReason>
|
78
74
|
|
79
|
-
export type Effect
|
75
|
+
export type Effect = {
|
80
76
|
_tag: 'effect'
|
81
77
|
id: string
|
82
78
|
isDestroyed: boolean
|
83
|
-
doEffect: (otelContext?: otel.Context
|
79
|
+
doEffect: (otelContext?: otel.Context) => void
|
84
80
|
sub: Set<Atom<any, TODO, TODO>>
|
85
81
|
label?: string
|
86
82
|
invocations: number
|
@@ -88,7 +84,7 @@ export type Effect<TDebugRefreshReason extends DebugRefreshReason> = {
|
|
88
84
|
|
89
85
|
export type Node<T, TContext, TDebugRefreshReason extends DebugRefreshReason> =
|
90
86
|
| Atom<T, TContext, TDebugRefreshReason>
|
91
|
-
| Effect
|
87
|
+
| Effect
|
92
88
|
|
93
89
|
export const isThunk = <T, TContext, TDebugRefreshReason extends DebugRefreshReason>(
|
94
90
|
obj: unknown,
|
@@ -170,7 +166,7 @@ export type SerializedThunk = Readonly<
|
|
170
166
|
|
171
167
|
export type SerializedEffect = Readonly<
|
172
168
|
PrettifyFlat<
|
173
|
-
Pick<Effect
|
169
|
+
Pick<Effect, '_tag' | 'id' | 'label' | 'invocations' | 'isDestroyed'> & {
|
174
170
|
sub: ReadonlyArray<string>
|
175
171
|
}
|
176
172
|
>
|
@@ -191,13 +187,6 @@ const uniqueRefreshInfoId = () => `refresh-info-${++refreshInfoIdCounter}`
|
|
191
187
|
let globalGraphIdCounter = 0
|
192
188
|
const uniqueGraphId = () => `graph-${++globalGraphIdCounter}`
|
193
189
|
|
194
|
-
/** Used for testing */
|
195
|
-
export const __resetIds = () => {
|
196
|
-
nodeIdCounter = 0
|
197
|
-
refreshInfoIdCounter = 0
|
198
|
-
globalGraphIdCounter = 0
|
199
|
-
}
|
200
|
-
|
201
190
|
export class ReactiveGraph<
|
202
191
|
TDebugRefreshReason extends DebugRefreshReason,
|
203
192
|
TDebugThunkInfo extends DebugThunkInfo,
|
@@ -206,7 +195,7 @@ export class ReactiveGraph<
|
|
206
195
|
id = uniqueGraphId()
|
207
196
|
|
208
197
|
readonly atoms: Set<Atom<any, TContext, TDebugRefreshReason>> = new Set()
|
209
|
-
readonly effects: Set<Effect
|
198
|
+
readonly effects: Set<Effect> = new Set()
|
210
199
|
|
211
200
|
context: TContext | undefined
|
212
201
|
|
@@ -216,7 +205,7 @@ export class ReactiveGraph<
|
|
216
205
|
| { refreshedAtoms: AtomDebugInfo<TDebugThunkInfo>[]; startMs: DOMHighResTimeStamp }
|
217
206
|
| undefined
|
218
207
|
|
219
|
-
private deferredEffects: Map<Effect
|
208
|
+
private deferredEffects: Map<Effect, Set<TDebugRefreshReason>> = new Map()
|
220
209
|
|
221
210
|
private refreshCallbacks: Set<() => void> = new Set()
|
222
211
|
|
@@ -250,7 +239,6 @@ export class ReactiveGraph<
|
|
250
239
|
setDebugInfo: (debugInfo: TDebugThunkInfo) => void,
|
251
240
|
ctx: TContext,
|
252
241
|
otelContext: otel.Context | undefined,
|
253
|
-
debugRefreshReason: TDebugRefreshReason | undefined,
|
254
242
|
) => T,
|
255
243
|
options?:
|
256
244
|
| {
|
@@ -278,7 +266,7 @@ export class ReactiveGraph<
|
|
278
266
|
|
279
267
|
const getAtom = (atom: Atom<T, TContext, TDebugRefreshReason>, otelContext: otel.Context) => {
|
280
268
|
this.addEdge(thunk, atom)
|
281
|
-
return compute(atom, otelContext
|
269
|
+
return compute(atom, otelContext)
|
282
270
|
}
|
283
271
|
|
284
272
|
let debugInfo: TDebugThunkInfo | undefined = undefined
|
@@ -291,7 +279,6 @@ export class ReactiveGraph<
|
|
291
279
|
setDebugInfo,
|
292
280
|
this.context ?? throwContextNotSetError(this),
|
293
281
|
otelContext,
|
294
|
-
debugRefreshReason,
|
295
282
|
)
|
296
283
|
|
297
284
|
const resultChanged = thunk.equal(thunk.previousResult as T, result) === false
|
@@ -378,18 +365,14 @@ export class ReactiveGraph<
|
|
378
365
|
}
|
379
366
|
|
380
367
|
makeEffect(
|
381
|
-
doEffect: (
|
382
|
-
get: GetAtom,
|
383
|
-
otelContext: otel.Context | undefined,
|
384
|
-
debugRefreshReason: DebugRefreshReason | undefined,
|
385
|
-
) => void,
|
368
|
+
doEffect: (get: GetAtom, otelContext?: otel.Context) => void,
|
386
369
|
options?: { label?: string } | undefined,
|
387
|
-
): Effect
|
388
|
-
const effect: Effect
|
370
|
+
): Effect {
|
371
|
+
const effect: Effect = {
|
389
372
|
_tag: 'effect',
|
390
373
|
id: uniqueNodeId(),
|
391
374
|
isDestroyed: false,
|
392
|
-
doEffect: (otelContext
|
375
|
+
doEffect: (otelContext) => {
|
393
376
|
effect.invocations++
|
394
377
|
|
395
378
|
// NOTE we're not tracking any debug refresh info for effects as they're tracked by the thunks they depend on
|
@@ -397,16 +380,12 @@ export class ReactiveGraph<
|
|
397
380
|
// Reset previous subcomputations as we're about to re-add them as part of the `doEffect` call below
|
398
381
|
effect.sub = new Set()
|
399
382
|
|
400
|
-
const getAtom = (
|
401
|
-
atom: Atom<any, TContext, TDebugRefreshReason>,
|
402
|
-
otelContext: otel.Context,
|
403
|
-
debugRefreshReason: DebugRefreshReason | undefined,
|
404
|
-
) => {
|
383
|
+
const getAtom = (atom: Atom<any, TContext, TDebugRefreshReason>, otelContext: otel.Context) => {
|
405
384
|
this.addEdge(effect, atom)
|
406
|
-
return compute(atom, otelContext
|
385
|
+
return compute(atom, otelContext)
|
407
386
|
}
|
408
387
|
|
409
|
-
doEffect(getAtom as GetAtom, otelContext
|
388
|
+
doEffect(getAtom as GetAtom, otelContext)
|
410
389
|
},
|
411
390
|
sub: new Set(),
|
412
391
|
label: options?.label,
|
@@ -442,7 +421,7 @@ export class ReactiveGraph<
|
|
442
421
|
}
|
443
422
|
| undefined,
|
444
423
|
) {
|
445
|
-
const effectsToRefresh = new Set<Effect
|
424
|
+
const effectsToRefresh = new Set<Effect>()
|
446
425
|
for (const [ref, val] of refs) {
|
447
426
|
ref.previousResult = val
|
448
427
|
ref.refreshes++
|
@@ -469,7 +448,7 @@ export class ReactiveGraph<
|
|
469
448
|
}
|
470
449
|
|
471
450
|
private runEffects = (
|
472
|
-
effectsToRefresh: Set<Effect
|
451
|
+
effectsToRefresh: Set<Effect>,
|
473
452
|
options: {
|
474
453
|
debugRefreshReason: TDebugRefreshReason
|
475
454
|
otelContext?: otel.Context
|
@@ -480,7 +459,7 @@ export class ReactiveGraph<
|
|
480
459
|
this.currentDebugRefresh = { refreshedAtoms: [], startMs: performance.now() }
|
481
460
|
|
482
461
|
for (const effect of effectsToRefresh) {
|
483
|
-
effect.doEffect(options?.otelContext
|
462
|
+
effect.doEffect(options?.otelContext)
|
484
463
|
}
|
485
464
|
|
486
465
|
const refreshedAtoms = this.currentDebugRefresh.refreshedAtoms
|
@@ -525,7 +504,7 @@ export class ReactiveGraph<
|
|
525
504
|
}
|
526
505
|
|
527
506
|
addEdge(
|
528
|
-
superComp: Thunk<any, TContext, TDebugRefreshReason> | Effect
|
507
|
+
superComp: Thunk<any, TContext, TDebugRefreshReason> | Effect,
|
529
508
|
subComp: Atom<any, TContext, TDebugRefreshReason>,
|
530
509
|
) {
|
531
510
|
superComp.sub.add(subComp)
|
@@ -537,11 +516,11 @@ export class ReactiveGraph<
|
|
537
516
|
}
|
538
517
|
|
539
518
|
removeEdge(
|
540
|
-
superComp: Thunk<any, TContext, TDebugRefreshReason> | Effect
|
519
|
+
superComp: Thunk<any, TContext, TDebugRefreshReason> | Effect,
|
541
520
|
subComp: Atom<any, TContext, TDebugRefreshReason>,
|
542
521
|
) {
|
543
522
|
superComp.sub.delete(subComp)
|
544
|
-
const effectsToRefresh = new Set<Effect
|
523
|
+
const effectsToRefresh = new Set<Effect>()
|
545
524
|
markSuperCompDirtyRec(subComp, effectsToRefresh)
|
546
525
|
|
547
526
|
for (const effect of effectsToRefresh) {
|
@@ -584,11 +563,7 @@ export class ReactiveGraph<
|
|
584
563
|
}
|
585
564
|
}
|
586
565
|
|
587
|
-
const compute = <T>(
|
588
|
-
atom: Atom<T, unknown, any>,
|
589
|
-
otelContext: otel.Context,
|
590
|
-
debugRefreshReason: DebugRefreshReason | undefined,
|
591
|
-
): T => {
|
566
|
+
const compute = <T>(atom: Atom<T, unknown, any>, otelContext: otel.Context): T => {
|
592
567
|
// const __getResult = atom._tag === 'thunk' ? atom.__getResult.toString() : ''
|
593
568
|
if (atom.isDestroyed) {
|
594
569
|
shouldNeverHappen(`LiveStore Error: Attempted to compute destroyed ${atom._tag} (${atom.id}): ${atom.label ?? ''}`)
|
@@ -596,7 +571,7 @@ const compute = <T>(
|
|
596
571
|
|
597
572
|
if (atom.isDirty) {
|
598
573
|
// console.log('atom is dirty', atom.id, atom.label ?? '', atom._tag, __getResult)
|
599
|
-
const result = atom.computeResult(otelContext
|
574
|
+
const result = atom.computeResult(otelContext)
|
600
575
|
atom.isDirty = false
|
601
576
|
atom.previousResult = result
|
602
577
|
return result
|
@@ -606,7 +581,7 @@ const compute = <T>(
|
|
606
581
|
}
|
607
582
|
}
|
608
583
|
|
609
|
-
const markSuperCompDirtyRec = <T>(atom: Atom<T, unknown, any>, effectsToRefresh: Set<Effect
|
584
|
+
const markSuperCompDirtyRec = <T>(atom: Atom<T, unknown, any>, effectsToRefresh: Set<Effect>) => {
|
610
585
|
for (const superComp of atom.super) {
|
611
586
|
if (superComp._tag === 'thunk') {
|
612
587
|
superComp.isDirty = true
|
@@ -669,7 +644,7 @@ const serializeAtom = (atom: Atom<any, unknown, any>, includeResult: boolean): S
|
|
669
644
|
}
|
670
645
|
|
671
646
|
// NOTE This function is performance-optimized (i.e. not using `pick` and `Array.from`)
|
672
|
-
const serializeEffect = (effect: Effect
|
647
|
+
const serializeEffect = (effect: Effect): SerializedEffect => {
|
673
648
|
const sub: string[] = []
|
674
649
|
for (const a of effect.sub) {
|
675
650
|
sub.push(a.id)
|