@livestore/livestore 0.3.0-dev.10 → 0.3.0-dev.11
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 +54 -0
- package/dist/SqliteDbWrapper.d.ts.map +1 -0
- package/dist/SqliteDbWrapper.js +212 -0
- package/dist/SqliteDbWrapper.js.map +1 -0
- package/dist/SynchronousDatabaseWrapper.d.ts +14 -5
- package/dist/SynchronousDatabaseWrapper.d.ts.map +1 -1
- package/dist/SynchronousDatabaseWrapper.js +24 -4
- package/dist/SynchronousDatabaseWrapper.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +12 -8
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +9 -2
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/index.d.ts +6 -7
- 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 +64 -21
- package/dist/live-queries/base-class.d.ts.map +1 -1
- package/dist/live-queries/base-class.js +56 -13
- 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 +35 -11
- package/dist/live-queries/computed.js.map +1 -1
- package/dist/live-queries/db-query.d.ts +67 -0
- package/dist/live-queries/db-query.d.ts.map +1 -0
- package/dist/live-queries/db-query.js +244 -0
- package/dist/live-queries/db-query.js.map +1 -0
- package/dist/live-queries/db-query.test.d.ts +2 -0
- package/dist/live-queries/db-query.test.d.ts.map +1 -0
- package/dist/live-queries/db-query.test.js +123 -0
- package/dist/live-queries/db-query.test.js.map +1 -0
- package/dist/live-queries/db.d.ts +12 -15
- package/dist/live-queries/db.d.ts.map +1 -1
- package/dist/live-queries/db.js +44 -25
- package/dist/live-queries/db.js.map +1 -1
- package/dist/live-queries/db.test.js +16 -14
- 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 +35 -9
- package/dist/live-queries/graphql.js.map +1 -1
- package/dist/live-queries/make-ref.d.ts +20 -0
- package/dist/live-queries/make-ref.d.ts.map +1 -0
- package/dist/live-queries/make-ref.js +33 -0
- package/dist/live-queries/make-ref.js.map +1 -0
- package/dist/reactive.d.ts +15 -13
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +15 -9
- 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 +14 -10
- package/dist/row-query-utils.js.map +1 -1
- package/dist/store/create-store.d.ts +3 -4
- 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 +9 -4
- 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 +34 -16
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +125 -75
- package/dist/store/store.js.map +1 -1
- package/dist/utils/expo.d.ts +2 -0
- package/dist/utils/expo.d.ts.map +1 -0
- package/dist/utils/expo.js +8 -0
- package/dist/utils/expo.js.map +1 -0
- package/dist/utils/function-string.d.ts +7 -0
- package/dist/utils/function-string.d.ts.map +1 -0
- package/dist/utils/function-string.js +9 -0
- package/dist/utils/function-string.js.map +1 -0
- package/dist/utils/stack-info.d.ts.map +1 -1
- package/dist/utils/stack-info.js +6 -1
- package/dist/utils/stack-info.js.map +1 -1
- package/dist/utils/stack-info.test.js +54 -1
- package/dist/utils/stack-info.test.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +2 -6
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/dist/utils/tests/fixture.js +3 -5
- package/dist/utils/tests/fixture.js.map +1 -1
- package/dist/utils/tests/mod.d.ts +1 -0
- package/dist/utils/tests/mod.d.ts.map +1 -1
- package/dist/utils/tests/mod.js +1 -0
- package/dist/utils/tests/mod.js.map +1 -1
- package/package.json +5 -5
- package/src/{SynchronousDatabaseWrapper.ts → SqliteDbWrapper.ts} +41 -11
- package/src/effect/LiveStore.ts +22 -14
- package/src/index.ts +14 -7
- package/src/live-queries/__snapshots__/{db.test.ts.snap → db-query.test.ts.snap} +196 -42
- package/src/live-queries/base-class.ts +160 -40
- package/src/live-queries/computed.ts +45 -19
- package/src/live-queries/{db.test.ts → db-query.test.ts} +21 -11
- package/src/live-queries/{db.ts → db-query.ts} +97 -39
- package/src/live-queries/graphql.ts +47 -21
- package/src/live-queries/make-ref.ts +47 -0
- package/src/reactive.ts +52 -27
- package/src/row-query-utils.ts +29 -18
- package/src/store/create-store.ts +20 -23
- package/src/store/devtools.ts +17 -17
- package/src/store/store-types.ts +6 -4
- package/src/store/store.ts +227 -120
- package/src/utils/function-string.ts +12 -0
- package/src/utils/stack-info.test.ts +58 -1
- package/src/utils/stack-info.ts +6 -1
- package/src/utils/tests/fixture.ts +2 -7
- package/src/utils/tests/mod.ts +1 -0
- package/src/global-state.ts +0 -20
|
@@ -21,9 +21,6 @@ exports[`otel > otel 3`] = `
|
|
|
21
21
|
",
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
|
-
{
|
|
25
|
-
"_name": "LiveStore:createStore",
|
|
26
|
-
},
|
|
27
24
|
{
|
|
28
25
|
"_name": "LiveStore:sync",
|
|
29
26
|
},
|
|
@@ -33,22 +30,17 @@ exports[`otel > otel 3`] = `
|
|
|
33
30
|
{
|
|
34
31
|
"_name": "LiveStore:mutate",
|
|
35
32
|
"attributes": {
|
|
36
|
-
"livestore.
|
|
33
|
+
"livestore.mutationEventTags": [
|
|
34
|
+
"livestore.RawSql",
|
|
35
|
+
],
|
|
36
|
+
"livestore.mutationEventsCount": 1,
|
|
37
37
|
},
|
|
38
38
|
"children": [
|
|
39
39
|
{
|
|
40
|
-
"_name": "
|
|
40
|
+
"_name": "livestore.in-memory-db:execute",
|
|
41
41
|
"attributes": {
|
|
42
|
-
"
|
|
42
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
43
43
|
},
|
|
44
|
-
"children": [
|
|
45
|
-
{
|
|
46
|
-
"_name": "livestore.in-memory-db:execute",
|
|
47
|
-
"attributes": {
|
|
48
|
-
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
49
|
-
},
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
44
|
},
|
|
53
45
|
],
|
|
54
46
|
},
|
|
@@ -97,7 +89,179 @@ exports[`otel > otel 3`] = `
|
|
|
97
89
|
}
|
|
98
90
|
`;
|
|
99
91
|
|
|
92
|
+
exports[`otel > with thunks 1`] = `
|
|
93
|
+
{
|
|
94
|
+
"atoms": [
|
|
95
|
+
{
|
|
96
|
+
"_tag": "ref",
|
|
97
|
+
"id": "node-1",
|
|
98
|
+
"isDestroyed": false,
|
|
99
|
+
"isDirty": false,
|
|
100
|
+
"label": "tableRef:todos",
|
|
101
|
+
"meta": {
|
|
102
|
+
"liveStoreRefType": "table",
|
|
103
|
+
},
|
|
104
|
+
"previousResult": {
|
|
105
|
+
"_tag": "Some",
|
|
106
|
+
"value": "null",
|
|
107
|
+
},
|
|
108
|
+
"refreshes": 0,
|
|
109
|
+
"sub": [],
|
|
110
|
+
"super": [],
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"_tag": "ref",
|
|
114
|
+
"id": "node-2",
|
|
115
|
+
"isDestroyed": false,
|
|
116
|
+
"isDirty": false,
|
|
117
|
+
"label": "tableRef:app",
|
|
118
|
+
"meta": {
|
|
119
|
+
"liveStoreRefType": "table",
|
|
120
|
+
},
|
|
121
|
+
"previousResult": {
|
|
122
|
+
"_tag": "Some",
|
|
123
|
+
"value": "null",
|
|
124
|
+
},
|
|
125
|
+
"refreshes": 0,
|
|
126
|
+
"sub": [],
|
|
127
|
+
"super": [],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
"deferredEffects": [],
|
|
131
|
+
"effects": [],
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
|
|
100
135
|
exports[`otel > with thunks 3`] = `
|
|
136
|
+
{
|
|
137
|
+
"atoms": [
|
|
138
|
+
{
|
|
139
|
+
"_tag": "ref",
|
|
140
|
+
"id": "node-1",
|
|
141
|
+
"isDestroyed": false,
|
|
142
|
+
"isDirty": false,
|
|
143
|
+
"label": "tableRef:todos",
|
|
144
|
+
"meta": {
|
|
145
|
+
"liveStoreRefType": "table",
|
|
146
|
+
},
|
|
147
|
+
"previousResult": {
|
|
148
|
+
"_tag": "Some",
|
|
149
|
+
"value": "null",
|
|
150
|
+
},
|
|
151
|
+
"refreshes": 0,
|
|
152
|
+
"sub": [],
|
|
153
|
+
"super": [],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"_tag": "ref",
|
|
157
|
+
"id": "node-2",
|
|
158
|
+
"isDestroyed": false,
|
|
159
|
+
"isDirty": false,
|
|
160
|
+
"label": "tableRef:app",
|
|
161
|
+
"meta": {
|
|
162
|
+
"liveStoreRefType": "table",
|
|
163
|
+
},
|
|
164
|
+
"previousResult": {
|
|
165
|
+
"_tag": "Some",
|
|
166
|
+
"value": "null",
|
|
167
|
+
},
|
|
168
|
+
"refreshes": 0,
|
|
169
|
+
"sub": [],
|
|
170
|
+
"super": [],
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
"deferredEffects": [],
|
|
174
|
+
"effects": [],
|
|
175
|
+
}
|
|
176
|
+
`;
|
|
177
|
+
|
|
178
|
+
exports[`otel > with thunks 4`] = `
|
|
179
|
+
{
|
|
180
|
+
"atoms": [
|
|
181
|
+
{
|
|
182
|
+
"_tag": "ref",
|
|
183
|
+
"id": "node-1",
|
|
184
|
+
"isDestroyed": false,
|
|
185
|
+
"isDirty": false,
|
|
186
|
+
"label": "tableRef:todos",
|
|
187
|
+
"meta": {
|
|
188
|
+
"liveStoreRefType": "table",
|
|
189
|
+
},
|
|
190
|
+
"previousResult": {
|
|
191
|
+
"_tag": "Some",
|
|
192
|
+
"value": "null",
|
|
193
|
+
},
|
|
194
|
+
"refreshes": 1,
|
|
195
|
+
"sub": [],
|
|
196
|
+
"super": [],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"_tag": "ref",
|
|
200
|
+
"id": "node-2",
|
|
201
|
+
"isDestroyed": false,
|
|
202
|
+
"isDirty": false,
|
|
203
|
+
"label": "tableRef:app",
|
|
204
|
+
"meta": {
|
|
205
|
+
"liveStoreRefType": "table",
|
|
206
|
+
},
|
|
207
|
+
"previousResult": {
|
|
208
|
+
"_tag": "Some",
|
|
209
|
+
"value": "null",
|
|
210
|
+
},
|
|
211
|
+
"refreshes": 0,
|
|
212
|
+
"sub": [],
|
|
213
|
+
"super": [],
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
"deferredEffects": [],
|
|
217
|
+
"effects": [],
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
220
|
+
|
|
221
|
+
exports[`otel > with thunks 6`] = `
|
|
222
|
+
{
|
|
223
|
+
"atoms": [
|
|
224
|
+
{
|
|
225
|
+
"_tag": "ref",
|
|
226
|
+
"id": "node-1",
|
|
227
|
+
"isDestroyed": false,
|
|
228
|
+
"isDirty": false,
|
|
229
|
+
"label": "tableRef:todos",
|
|
230
|
+
"meta": {
|
|
231
|
+
"liveStoreRefType": "table",
|
|
232
|
+
},
|
|
233
|
+
"previousResult": {
|
|
234
|
+
"_tag": "Some",
|
|
235
|
+
"value": "null",
|
|
236
|
+
},
|
|
237
|
+
"refreshes": 1,
|
|
238
|
+
"sub": [],
|
|
239
|
+
"super": [],
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"_tag": "ref",
|
|
243
|
+
"id": "node-2",
|
|
244
|
+
"isDestroyed": false,
|
|
245
|
+
"isDirty": false,
|
|
246
|
+
"label": "tableRef:app",
|
|
247
|
+
"meta": {
|
|
248
|
+
"liveStoreRefType": "table",
|
|
249
|
+
},
|
|
250
|
+
"previousResult": {
|
|
251
|
+
"_tag": "Some",
|
|
252
|
+
"value": "null",
|
|
253
|
+
},
|
|
254
|
+
"refreshes": 0,
|
|
255
|
+
"sub": [],
|
|
256
|
+
"super": [],
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
"deferredEffects": [],
|
|
260
|
+
"effects": [],
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
263
|
+
|
|
264
|
+
exports[`otel > with thunks 7`] = `
|
|
101
265
|
{
|
|
102
266
|
"_name": "createStore",
|
|
103
267
|
"attributes": {
|
|
@@ -118,9 +282,6 @@ exports[`otel > with thunks 3`] = `
|
|
|
118
282
|
",
|
|
119
283
|
},
|
|
120
284
|
},
|
|
121
|
-
{
|
|
122
|
-
"_name": "LiveStore:createStore",
|
|
123
|
-
},
|
|
124
285
|
{
|
|
125
286
|
"_name": "LiveStore:sync",
|
|
126
287
|
},
|
|
@@ -130,22 +291,17 @@ exports[`otel > with thunks 3`] = `
|
|
|
130
291
|
{
|
|
131
292
|
"_name": "LiveStore:mutate",
|
|
132
293
|
"attributes": {
|
|
133
|
-
"livestore.
|
|
294
|
+
"livestore.mutationEventTags": [
|
|
295
|
+
"livestore.RawSql",
|
|
296
|
+
],
|
|
297
|
+
"livestore.mutationEventsCount": 1,
|
|
134
298
|
},
|
|
135
299
|
"children": [
|
|
136
300
|
{
|
|
137
|
-
"_name": "
|
|
301
|
+
"_name": "livestore.in-memory-db:execute",
|
|
138
302
|
"attributes": {
|
|
139
|
-
"
|
|
303
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
140
304
|
},
|
|
141
|
-
"children": [
|
|
142
|
-
{
|
|
143
|
-
"_name": "livestore.in-memory-db:execute",
|
|
144
|
-
"attributes": {
|
|
145
|
-
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
146
|
-
},
|
|
147
|
-
},
|
|
148
|
-
],
|
|
149
305
|
},
|
|
150
306
|
],
|
|
151
307
|
},
|
|
@@ -181,6 +337,9 @@ exports[`otel > with thunks 3`] = `
|
|
|
181
337
|
"sql.rowsCount": 1,
|
|
182
338
|
},
|
|
183
339
|
"children": [
|
|
340
|
+
{
|
|
341
|
+
"_name": "js:where-filter",
|
|
342
|
+
},
|
|
184
343
|
{
|
|
185
344
|
"_name": "sql-in-memory-select",
|
|
186
345
|
"attributes": {
|
|
@@ -218,9 +377,6 @@ exports[`otel > with thunks with query builder and without labels 3`] = `
|
|
|
218
377
|
",
|
|
219
378
|
},
|
|
220
379
|
},
|
|
221
|
-
{
|
|
222
|
-
"_name": "LiveStore:createStore",
|
|
223
|
-
},
|
|
224
380
|
{
|
|
225
381
|
"_name": "LiveStore:sync",
|
|
226
382
|
},
|
|
@@ -230,22 +386,17 @@ exports[`otel > with thunks with query builder and without labels 3`] = `
|
|
|
230
386
|
{
|
|
231
387
|
"_name": "LiveStore:mutate",
|
|
232
388
|
"attributes": {
|
|
233
|
-
"livestore.
|
|
389
|
+
"livestore.mutationEventTags": [
|
|
390
|
+
"livestore.RawSql",
|
|
391
|
+
],
|
|
392
|
+
"livestore.mutationEventsCount": 1,
|
|
234
393
|
},
|
|
235
394
|
"children": [
|
|
236
395
|
{
|
|
237
|
-
"_name": "
|
|
396
|
+
"_name": "livestore.in-memory-db:execute",
|
|
238
397
|
"attributes": {
|
|
239
|
-
"
|
|
398
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
240
399
|
},
|
|
241
|
-
"children": [
|
|
242
|
-
{
|
|
243
|
-
"_name": "livestore.in-memory-db:execute",
|
|
244
|
-
"attributes": {
|
|
245
|
-
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
246
|
-
},
|
|
247
|
-
},
|
|
248
|
-
],
|
|
249
400
|
},
|
|
250
401
|
],
|
|
251
402
|
},
|
|
@@ -281,6 +432,9 @@ exports[`otel > with thunks with query builder and without labels 3`] = `
|
|
|
281
432
|
"sql.rowsCount": 1,
|
|
282
433
|
},
|
|
283
434
|
"children": [
|
|
435
|
+
{
|
|
436
|
+
"_name": "js:() => ({ completed: false })",
|
|
437
|
+
},
|
|
284
438
|
{
|
|
285
439
|
"_name": "sql-in-memory-select",
|
|
286
440
|
"attributes": {
|
|
@@ -1,59 +1,119 @@
|
|
|
1
1
|
import type { QueryInfo } from '@livestore/common'
|
|
2
|
+
import { isNotNil } from '@livestore/utils'
|
|
3
|
+
import { GlobalValue } from '@livestore/utils/effect'
|
|
2
4
|
import type * as otel from '@opentelemetry/api'
|
|
3
5
|
|
|
4
|
-
import
|
|
6
|
+
import * as RG from '../reactive.js'
|
|
5
7
|
import type { Store } from '../store/store.js'
|
|
6
8
|
import type { QueryDebugInfo, RefreshReason } from '../store/store-types.js'
|
|
7
9
|
import type { StackInfo } from '../utils/stack-info.js'
|
|
8
10
|
|
|
9
|
-
export type ReactivityGraph = ReactiveGraph<RefreshReason, QueryDebugInfo,
|
|
11
|
+
export type ReactivityGraph = RG.ReactiveGraph<RefreshReason, QueryDebugInfo, ReactivityGraphContext>
|
|
10
12
|
|
|
11
13
|
export const makeReactivityGraph = (): ReactivityGraph =>
|
|
12
|
-
new ReactiveGraph<RefreshReason, QueryDebugInfo,
|
|
14
|
+
new RG.ReactiveGraph<RefreshReason, QueryDebugInfo, ReactivityGraphContext>()
|
|
13
15
|
|
|
14
|
-
export
|
|
16
|
+
export const defCounterRef = GlobalValue.globalValue('livestore-def-counter', () => ({ current: 0 }))
|
|
17
|
+
|
|
18
|
+
type LiveQueryDefHash = string
|
|
19
|
+
|
|
20
|
+
export type LiveQueryRCMap = Map<LiveQueryDefHash, RcRef<LiveQueryAny | ILiveQueryRef<any>>>
|
|
21
|
+
|
|
22
|
+
export type ReactivityGraphContext = {
|
|
15
23
|
store: Store
|
|
24
|
+
liveQueryRCMap: LiveQueryRCMap
|
|
25
|
+
/** Back-reference to the reactivity graph for convenience */
|
|
26
|
+
reactivityGraph: WeakRef<ReactivityGraph>
|
|
16
27
|
otelTracer: otel.Tracer
|
|
17
28
|
rootOtelContext: otel.Context
|
|
18
29
|
effectsWrapper: (run: () => void) => void
|
|
19
30
|
}
|
|
20
31
|
|
|
21
|
-
export type
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
export type GetResult<TQuery extends LiveQueryDefAny | LiveQueryAny> =
|
|
33
|
+
TQuery extends LiveQuery<infer TResult, infer _1>
|
|
34
|
+
? TResult
|
|
35
|
+
: TQuery extends LiveQueryDef<infer TResult, infer _1>
|
|
36
|
+
? TResult
|
|
37
|
+
: unknown
|
|
25
38
|
|
|
26
39
|
let queryIdCounter = 0
|
|
27
40
|
|
|
28
41
|
export type LiveQueryAny = LiveQuery<any, QueryInfo>
|
|
42
|
+
export type LiveQueryDefAny = LiveQueryDef<any, any>
|
|
43
|
+
|
|
44
|
+
export interface ILiveQueryRefDef<T> {
|
|
45
|
+
_tag: 'live-ref-def'
|
|
46
|
+
defaultValue: T
|
|
47
|
+
make: (ctx: ReactivityGraphContext) => RcRef<ILiveQueryRef<T>>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ILiveQueryRef<T> {
|
|
51
|
+
_tag: 'live-ref'
|
|
52
|
+
reactivityGraph: ReactivityGraph
|
|
53
|
+
ref: RG.Ref<T, ReactivityGraphContext, RefreshReason>
|
|
54
|
+
set: (value: T) => void
|
|
55
|
+
get: () => T
|
|
56
|
+
destroy: () => void
|
|
57
|
+
}
|
|
29
58
|
|
|
30
59
|
export const TypeId = Symbol.for('LiveQuery')
|
|
31
60
|
export type TypeId = typeof TypeId
|
|
32
61
|
|
|
62
|
+
export interface RcRef<T> {
|
|
63
|
+
rc: number
|
|
64
|
+
value: T
|
|
65
|
+
deref: () => void
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type DepKey = string | number | ReadonlyArray<string | number | undefined | null>
|
|
69
|
+
|
|
70
|
+
export const depsToString = (deps: DepKey): string => {
|
|
71
|
+
if (typeof deps === 'string' || typeof deps === 'number') {
|
|
72
|
+
return deps.toString()
|
|
73
|
+
}
|
|
74
|
+
return deps.filter(isNotNil).join(',')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface LiveQueryDef<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> {
|
|
78
|
+
_tag: 'def'
|
|
79
|
+
// TODO do we need both id and hash?
|
|
80
|
+
/** A unique identifier for the query definition */
|
|
81
|
+
id: number
|
|
82
|
+
/** Creates a new LiveQuery instance bound to a specific store/reactivityGraph */
|
|
83
|
+
make: (ctx: ReactivityGraphContext, otelContext?: otel.Context) => RcRef<LiveQuery<TResult, TQueryInfo>>
|
|
84
|
+
label: string
|
|
85
|
+
hash: string
|
|
86
|
+
queryInfo: TQueryInfo
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A LiveQuery is stateful
|
|
91
|
+
*/
|
|
33
92
|
export interface LiveQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> {
|
|
34
93
|
id: number
|
|
35
94
|
_tag: 'computed' | 'db' | 'graphql'
|
|
36
95
|
[TypeId]: TypeId
|
|
37
96
|
|
|
97
|
+
// reactivityGraph: ReactivityGraph
|
|
98
|
+
|
|
38
99
|
/** This should only be used on a type-level and doesn't hold any value during runtime */
|
|
39
100
|
'__result!': TResult
|
|
40
101
|
|
|
41
102
|
/** A reactive thunk representing the query results */
|
|
42
|
-
results$: Thunk<TResult,
|
|
103
|
+
results$: RG.Thunk<TResult, ReactivityGraphContext, RefreshReason>
|
|
43
104
|
|
|
44
105
|
label: string
|
|
45
106
|
|
|
46
|
-
run: (otelContext?: otel.Context
|
|
47
|
-
|
|
48
|
-
runAndDestroy: (otelContext?: otel.Context, debugRefreshReason?: RefreshReason) => TResult
|
|
107
|
+
run: (args: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason }) => TResult
|
|
49
108
|
|
|
50
|
-
destroy()
|
|
109
|
+
destroy: () => void
|
|
110
|
+
isDestroyed: boolean
|
|
51
111
|
|
|
52
|
-
subscribe(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
): () => void
|
|
112
|
+
// subscribe(
|
|
113
|
+
// onNewValue: (value: TResult) => void,
|
|
114
|
+
// onUnsubsubscribe?: () => void,
|
|
115
|
+
// options?: { label?: string; otelContext?: otel.Context },
|
|
116
|
+
// ): () => void
|
|
57
117
|
|
|
58
118
|
activeSubscriptions: Set<StackInfo>
|
|
59
119
|
|
|
@@ -75,11 +135,11 @@ export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
|
|
|
75
135
|
/** Human-readable label for the query for debugging */
|
|
76
136
|
abstract label: string
|
|
77
137
|
|
|
78
|
-
abstract results$: Thunk<TResult,
|
|
138
|
+
abstract results$: RG.Thunk<TResult, ReactivityGraphContext, RefreshReason>
|
|
79
139
|
|
|
80
140
|
activeSubscriptions: Set<StackInfo> = new Set()
|
|
81
141
|
|
|
82
|
-
|
|
142
|
+
abstract readonly reactivityGraph: ReactivityGraph
|
|
83
143
|
|
|
84
144
|
abstract queryInfo: TQueryInfo
|
|
85
145
|
|
|
@@ -89,33 +149,93 @@ export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
|
|
|
89
149
|
|
|
90
150
|
executionTimes: number[] = []
|
|
91
151
|
|
|
152
|
+
// TODO double check if this is needed
|
|
153
|
+
isDestroyed = false
|
|
92
154
|
abstract destroy: () => void
|
|
93
155
|
|
|
94
|
-
run = (otelContext?: otel.Context
|
|
95
|
-
this.results$.computeResult(otelContext, debugRefreshReason)
|
|
96
|
-
|
|
97
|
-
runAndDestroy = (otelContext?: otel.Context, debugRefreshReason?: RefreshReason): TResult => {
|
|
98
|
-
const result = this.run(otelContext, debugRefreshReason)
|
|
99
|
-
this.destroy()
|
|
100
|
-
return result
|
|
156
|
+
run = (args: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason }): TResult => {
|
|
157
|
+
return this.results$.computeResult(args.otelContext, args.debugRefreshReason)
|
|
101
158
|
}
|
|
102
159
|
|
|
103
|
-
|
|
104
|
-
onNewValue: (value: TResult) => void,
|
|
105
|
-
onUnsubsubscribe?: () => void,
|
|
106
|
-
options?: { label?: string; otelContext?: otel.Context } | undefined,
|
|
107
|
-
): (() => void) =>
|
|
108
|
-
this.reactivityGraph.context?.store.subscribe(this, onNewValue, onUnsubsubscribe, options) ??
|
|
109
|
-
throwContextNotSetError(this.reactivityGraph)
|
|
110
|
-
}
|
|
160
|
+
protected dependencyQueriesRef: DependencyQueriesRef = new Set()
|
|
111
161
|
|
|
112
|
-
|
|
162
|
+
// subscribe = (
|
|
163
|
+
// onNewValue: (value: TResult) => void,
|
|
164
|
+
// onUnsubsubscribe?: () => void,
|
|
165
|
+
// options?: { label?: string; otelContext?: otel.Context } | undefined,
|
|
166
|
+
// ): (() => void) =>
|
|
167
|
+
// this.reactivityGraph.context?.store.subscribe(this, onNewValue, onUnsubsubscribe, options) ??
|
|
168
|
+
// RG.throwContextNotSetError(this.reactivityGraph)
|
|
169
|
+
}
|
|
113
170
|
|
|
114
|
-
export
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
export type GetAtomResult = <T>(
|
|
172
|
+
atom:
|
|
173
|
+
| RG.Atom<T, any, RefreshReason>
|
|
174
|
+
| LiveQueryDef<T, any>
|
|
175
|
+
| LiveQuery<T, any>
|
|
176
|
+
| ILiveQueryRef<T>
|
|
177
|
+
| ILiveQueryRefDef<T>,
|
|
178
|
+
otelContext?: otel.Context | undefined,
|
|
179
|
+
debugRefreshReason?: RefreshReason | undefined,
|
|
180
|
+
) => T
|
|
181
|
+
|
|
182
|
+
export type DependencyQueriesRef = Set<RcRef<LiveQueryAny | ILiveQueryRef<any>>>
|
|
183
|
+
|
|
184
|
+
export const makeGetAtomResult = (
|
|
185
|
+
get: RG.GetAtom,
|
|
186
|
+
ctx: ReactivityGraphContext,
|
|
187
|
+
otelContext: otel.Context,
|
|
188
|
+
dependencyQueriesRef: DependencyQueriesRef,
|
|
189
|
+
) => {
|
|
190
|
+
// NOTE we're using the `otelContext` from `makeGetAtomResult` here, not the `otelContext` from `getAtom`
|
|
191
|
+
const getAtom: GetAtomResult = (atom, _otelContext, debugRefreshReason) => {
|
|
192
|
+
// ReactivityGraph atoms case
|
|
193
|
+
if (atom._tag === 'thunk' || atom._tag === 'ref') return get(atom, otelContext, debugRefreshReason)
|
|
194
|
+
|
|
195
|
+
// LiveQueryDef case
|
|
196
|
+
if (atom._tag === 'def' || atom._tag === 'live-ref-def') {
|
|
197
|
+
const query = atom.make(ctx)
|
|
198
|
+
dependencyQueriesRef.add(query)
|
|
199
|
+
// TODO deref the query on destroy
|
|
200
|
+
return getAtom(query.value, _otelContext, debugRefreshReason)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// LiveQueryRef case
|
|
204
|
+
if (atom._tag === 'live-ref') return get(atom.ref, otelContext, debugRefreshReason)
|
|
205
|
+
|
|
206
|
+
// LiveQuery case
|
|
207
|
+
return get(atom.results$, otelContext, debugRefreshReason)
|
|
118
208
|
}
|
|
119
209
|
|
|
120
210
|
return getAtom
|
|
121
211
|
}
|
|
212
|
+
|
|
213
|
+
export const withRCMap = <T extends LiveQueryAny | ILiveQueryRef<any>>(
|
|
214
|
+
id: string,
|
|
215
|
+
make: (ctx: ReactivityGraphContext, otelContext?: otel.Context) => T,
|
|
216
|
+
): ((ctx: ReactivityGraphContext, otelContext?: otel.Context) => RcRef<T>) => {
|
|
217
|
+
return (ctx, otelContext) => {
|
|
218
|
+
let item = ctx.liveQueryRCMap.get(id)
|
|
219
|
+
if (item) {
|
|
220
|
+
item.rc++
|
|
221
|
+
return item as RcRef<T>
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const query$ = make(ctx, otelContext)
|
|
225
|
+
|
|
226
|
+
item = {
|
|
227
|
+
rc: 1,
|
|
228
|
+
value: query$,
|
|
229
|
+
deref: () => {
|
|
230
|
+
item!.rc--
|
|
231
|
+
if (item!.rc === 0) {
|
|
232
|
+
item!.value.destroy()
|
|
233
|
+
}
|
|
234
|
+
ctx.liveQueryRCMap.delete(id)
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
ctx.liveQueryRCMap.set(id, item)
|
|
238
|
+
|
|
239
|
+
return item as RcRef<T>
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
import type { QueryInfo } from '@livestore/common'
|
|
2
2
|
import * as otel from '@opentelemetry/api'
|
|
3
3
|
|
|
4
|
-
import { globalReactivityGraph } from '../global-state.js'
|
|
5
4
|
import type { Thunk } from '../reactive.js'
|
|
6
5
|
import type { RefreshReason } from '../store/store-types.js'
|
|
6
|
+
import { isValidFunctionString } from '../utils/function-string.js'
|
|
7
7
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
8
|
-
import type {
|
|
9
|
-
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
8
|
+
import type { DepKey, GetAtomResult, LiveQueryDef, ReactivityGraph, ReactivityGraphContext } from './base-class.js'
|
|
9
|
+
import { defCounterRef, depsToString, LiveStoreQueryBase, makeGetAtomResult, withRCMap } from './base-class.js'
|
|
10
10
|
|
|
11
11
|
export const computed = <TResult, TQueryInfo extends QueryInfo = QueryInfo.None>(
|
|
12
12
|
fn: (get: GetAtomResult) => TResult,
|
|
13
13
|
options?: {
|
|
14
|
-
label
|
|
15
|
-
reactivityGraph?: ReactivityGraph
|
|
14
|
+
label?: string
|
|
16
15
|
queryInfo?: TQueryInfo
|
|
16
|
+
deps?: DepKey
|
|
17
17
|
},
|
|
18
|
-
):
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
): LiveQueryDef<TResult, TQueryInfo> => {
|
|
19
|
+
const hash = options?.deps ? depsToString(options.deps) : fn.toString()
|
|
20
|
+
if (isValidFunctionString(hash)._tag === 'invalid') {
|
|
21
|
+
throw new Error(`On Expo/React Native, computed queries must provide a \`deps\` option`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const queryInfo = options?.queryInfo ?? ({ _tag: 'None' } as TQueryInfo)
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
_tag: 'def',
|
|
28
|
+
id: ++defCounterRef.current,
|
|
29
|
+
make: withRCMap(hash, (ctx, _otelContext) => {
|
|
30
|
+
// TODO onDestroy
|
|
31
|
+
return new LiveStoreComputedQuery<TResult, TQueryInfo>({
|
|
32
|
+
fn,
|
|
33
|
+
label: options?.label ?? fn.toString(),
|
|
34
|
+
queryInfo: options?.queryInfo,
|
|
35
|
+
reactivityGraph: ctx.reactivityGraph.deref()!,
|
|
36
|
+
})
|
|
37
|
+
}),
|
|
21
38
|
label: options?.label ?? fn.toString(),
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
39
|
+
// NOTE We're using the `makeQuery` function body string to make sure the key is unique across the app
|
|
40
|
+
// TODO we should figure out whether this could cause some problems and/or if there's a better way to do this
|
|
41
|
+
// NOTE `fn.toString()` doesn't work in Expo as it always produces `[native code]`
|
|
42
|
+
hash,
|
|
43
|
+
queryInfo,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
25
46
|
|
|
26
47
|
export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> extends LiveStoreQueryBase<
|
|
27
48
|
TResult,
|
|
@@ -30,11 +51,11 @@ export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = Quer
|
|
|
30
51
|
_tag: 'computed' = 'computed'
|
|
31
52
|
|
|
32
53
|
/** A reactive thunk representing the query results */
|
|
33
|
-
results$: Thunk<TResult,
|
|
54
|
+
results$: Thunk<TResult, ReactivityGraphContext, RefreshReason>
|
|
34
55
|
|
|
35
56
|
label: string
|
|
36
57
|
|
|
37
|
-
|
|
58
|
+
reactivityGraph: ReactivityGraph
|
|
38
59
|
|
|
39
60
|
queryInfo: TQueryInfo
|
|
40
61
|
|
|
@@ -46,23 +67,22 @@ export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = Quer
|
|
|
46
67
|
}: {
|
|
47
68
|
label: string
|
|
48
69
|
fn: (get: GetAtomResult) => TResult
|
|
49
|
-
reactivityGraph
|
|
70
|
+
reactivityGraph: ReactivityGraph
|
|
50
71
|
queryInfo?: TQueryInfo
|
|
51
72
|
}) {
|
|
52
73
|
super()
|
|
53
74
|
|
|
54
75
|
this.label = label
|
|
55
|
-
|
|
56
|
-
this.reactivityGraph = reactivityGraph ?? globalReactivityGraph
|
|
76
|
+
this.reactivityGraph = reactivityGraph
|
|
57
77
|
this.queryInfo = queryInfo ?? ({ _tag: 'None' } as TQueryInfo)
|
|
58
78
|
|
|
59
79
|
const queryLabel = `${label}:results`
|
|
60
80
|
|
|
61
81
|
this.results$ = this.reactivityGraph.makeThunk(
|
|
62
|
-
(get, setDebugInfo,
|
|
63
|
-
otelTracer.startActiveSpan(`js:${label}`, {}, otelContext ?? rootOtelContext, (span) => {
|
|
82
|
+
(get, setDebugInfo, ctx, otelContext) =>
|
|
83
|
+
ctx.otelTracer.startActiveSpan(`js:${label}`, {}, otelContext ?? ctx.rootOtelContext, (span) => {
|
|
64
84
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
65
|
-
const res = fn(makeGetAtomResult(get, otelContext))
|
|
85
|
+
const res = fn(makeGetAtomResult(get, ctx, otelContext, this.dependencyQueriesRef))
|
|
66
86
|
|
|
67
87
|
span.end()
|
|
68
88
|
|
|
@@ -79,6 +99,12 @@ export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = Quer
|
|
|
79
99
|
}
|
|
80
100
|
|
|
81
101
|
destroy = () => {
|
|
102
|
+
this.isDestroyed = true
|
|
103
|
+
|
|
82
104
|
this.reactivityGraph.destroyNode(this.results$)
|
|
105
|
+
|
|
106
|
+
for (const query of this.dependencyQueriesRef) {
|
|
107
|
+
query.deref()
|
|
108
|
+
}
|
|
83
109
|
}
|
|
84
110
|
}
|