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