@livestore/livestore 0.3.0-dev.5 → 0.3.0-dev.51

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 (170) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/QueryCache.d.ts.map +1 -1
  3. package/dist/SqliteDbWrapper.d.ts +60 -0
  4. package/dist/SqliteDbWrapper.d.ts.map +1 -0
  5. package/dist/{SynchronousDatabaseWrapper.js → SqliteDbWrapper.js} +69 -34
  6. package/dist/SqliteDbWrapper.js.map +1 -0
  7. package/dist/effect/LiveStore.d.ts +6 -34
  8. package/dist/effect/LiveStore.d.ts.map +1 -1
  9. package/dist/effect/LiveStore.js +10 -12
  10. package/dist/effect/LiveStore.js.map +1 -1
  11. package/dist/effect/mod.d.ts +3 -0
  12. package/dist/effect/mod.d.ts.map +1 -0
  13. package/dist/effect/mod.js +3 -0
  14. package/dist/effect/mod.js.map +1 -0
  15. package/dist/internal/mod.d.ts +3 -0
  16. package/dist/internal/mod.d.ts.map +1 -0
  17. package/dist/internal/mod.js +3 -0
  18. package/dist/internal/mod.js.map +1 -0
  19. package/dist/live-queries/base-class.d.ts +69 -29
  20. package/dist/live-queries/base-class.d.ts.map +1 -1
  21. package/dist/live-queries/base-class.js +60 -14
  22. package/dist/live-queries/base-class.js.map +1 -1
  23. package/dist/live-queries/client-document-get-query.d.ts +12 -0
  24. package/dist/live-queries/client-document-get-query.d.ts.map +1 -0
  25. package/dist/live-queries/client-document-get-query.js +18 -0
  26. package/dist/live-queries/client-document-get-query.js.map +1 -0
  27. package/dist/live-queries/computed.d.ts +13 -15
  28. package/dist/live-queries/computed.d.ts.map +1 -1
  29. package/dist/live-queries/computed.js +37 -15
  30. package/dist/live-queries/computed.js.map +1 -1
  31. package/dist/live-queries/db-query.d.ts +93 -0
  32. package/dist/live-queries/db-query.d.ts.map +1 -0
  33. package/dist/live-queries/{db.js → db-query.js} +113 -40
  34. package/dist/live-queries/db-query.js.map +1 -0
  35. package/dist/live-queries/db-query.test.d.ts +2 -0
  36. package/dist/live-queries/db-query.test.d.ts.map +1 -0
  37. package/dist/live-queries/db-query.test.js +133 -0
  38. package/dist/live-queries/db-query.test.js.map +1 -0
  39. package/dist/live-queries/mod.d.ts +5 -0
  40. package/dist/live-queries/mod.d.ts.map +1 -0
  41. package/dist/live-queries/mod.js +5 -0
  42. package/dist/live-queries/mod.js.map +1 -0
  43. package/dist/live-queries/signal.d.ts +25 -0
  44. package/dist/live-queries/signal.d.ts.map +1 -0
  45. package/dist/live-queries/signal.js +50 -0
  46. package/dist/live-queries/signal.js.map +1 -0
  47. package/dist/live-queries/signal.test.d.ts +2 -0
  48. package/dist/live-queries/signal.test.d.ts.map +1 -0
  49. package/dist/live-queries/signal.test.js +25 -0
  50. package/dist/live-queries/signal.test.js.map +1 -0
  51. package/dist/mod.d.ts +14 -0
  52. package/dist/mod.d.ts.map +1 -0
  53. package/dist/mod.js +13 -0
  54. package/dist/mod.js.map +1 -0
  55. package/dist/reactive.d.ts +23 -17
  56. package/dist/reactive.d.ts.map +1 -1
  57. package/dist/reactive.js +23 -19
  58. package/dist/reactive.js.map +1 -1
  59. package/dist/reactive.test.js +1 -1
  60. package/dist/reactive.test.js.map +1 -1
  61. package/dist/store/create-store.d.ts +70 -12
  62. package/dist/store/create-store.d.ts.map +1 -1
  63. package/dist/store/create-store.js +68 -19
  64. package/dist/store/create-store.js.map +1 -1
  65. package/dist/store/devtools.d.ts +5 -4
  66. package/dist/store/devtools.d.ts.map +1 -1
  67. package/dist/store/devtools.js +92 -40
  68. package/dist/store/devtools.js.map +1 -1
  69. package/dist/store/store-types.d.ts +54 -42
  70. package/dist/store/store-types.d.ts.map +1 -1
  71. package/dist/store/store-types.js +2 -5
  72. package/dist/store/store-types.js.map +1 -1
  73. package/dist/store/store.d.ts +141 -35
  74. package/dist/store/store.d.ts.map +1 -1
  75. package/dist/store/store.js +322 -154
  76. package/dist/store/store.js.map +1 -1
  77. package/dist/utils/data-structures.d.ts.map +1 -1
  78. package/dist/utils/dev.d.ts.map +1 -1
  79. package/dist/utils/dev.js +6 -1
  80. package/dist/utils/dev.js.map +1 -1
  81. package/dist/utils/function-string.d.ts +7 -0
  82. package/dist/utils/function-string.d.ts.map +1 -0
  83. package/dist/utils/function-string.js +9 -0
  84. package/dist/utils/function-string.js.map +1 -0
  85. package/dist/utils/stack-info.d.ts.map +1 -1
  86. package/dist/utils/stack-info.js +6 -1
  87. package/dist/utils/stack-info.js.map +1 -1
  88. package/dist/utils/stack-info.test.js +54 -1
  89. package/dist/utils/stack-info.test.js.map +1 -1
  90. package/dist/utils/tests/fixture.d.ts +59 -216
  91. package/dist/utils/tests/fixture.d.ts.map +1 -1
  92. package/dist/utils/tests/fixture.js +23 -18
  93. package/dist/utils/tests/fixture.js.map +1 -1
  94. package/dist/utils/tests/mod.d.ts +1 -0
  95. package/dist/utils/tests/mod.d.ts.map +1 -1
  96. package/dist/utils/tests/mod.js +1 -0
  97. package/dist/utils/tests/mod.js.map +1 -1
  98. package/dist/utils/tests/otel.d.ts.map +1 -1
  99. package/dist/utils/tests/otel.js +8 -3
  100. package/dist/utils/tests/otel.js.map +1 -1
  101. package/package.json +29 -26
  102. package/src/{SynchronousDatabaseWrapper.ts → SqliteDbWrapper.ts} +92 -42
  103. package/src/effect/LiveStore.ts +27 -64
  104. package/src/effect/{index.ts → mod.ts} +2 -3
  105. package/src/internal/mod.ts +2 -0
  106. package/src/live-queries/__snapshots__/{db.test.ts.snap → db-query.test.ts.snap} +241 -45
  107. package/src/live-queries/base-class.ts +170 -53
  108. package/src/live-queries/client-document-get-query.ts +52 -0
  109. package/src/live-queries/computed.ts +51 -33
  110. package/src/live-queries/db-query.test.ts +192 -0
  111. package/src/live-queries/{db.ts → db-query.ts} +171 -82
  112. package/src/live-queries/mod.ts +4 -0
  113. package/src/live-queries/signal.test.ts +40 -0
  114. package/src/live-queries/signal.ts +81 -0
  115. package/src/mod.ts +51 -0
  116. package/src/reactive.test.ts +1 -1
  117. package/src/reactive.ts +66 -43
  118. package/src/store/create-store.ts +188 -62
  119. package/src/store/devtools.ts +124 -46
  120. package/src/store/store-types.ts +54 -43
  121. package/src/store/store.ts +457 -237
  122. package/src/utils/dev.ts +6 -1
  123. package/src/utils/function-string.ts +12 -0
  124. package/src/utils/stack-info.test.ts +58 -1
  125. package/src/utils/stack-info.ts +6 -1
  126. package/src/utils/tests/fixture.ts +22 -31
  127. package/src/utils/tests/mod.ts +1 -0
  128. package/src/utils/tests/otel.ts +10 -3
  129. package/dist/SynchronousDatabaseWrapper.d.ts +0 -41
  130. package/dist/SynchronousDatabaseWrapper.d.ts.map +0 -1
  131. package/dist/SynchronousDatabaseWrapper.js.map +0 -1
  132. package/dist/effect/index.d.ts +0 -2
  133. package/dist/effect/index.d.ts.map +0 -1
  134. package/dist/effect/index.js +0 -2
  135. package/dist/effect/index.js.map +0 -1
  136. package/dist/global-state.d.ts +0 -14
  137. package/dist/global-state.d.ts.map +0 -1
  138. package/dist/global-state.js +0 -16
  139. package/dist/global-state.js.map +0 -1
  140. package/dist/index.d.ts +0 -20
  141. package/dist/index.d.ts.map +0 -1
  142. package/dist/index.js +0 -16
  143. package/dist/index.js.map +0 -1
  144. package/dist/live-queries/db.d.ts +0 -66
  145. package/dist/live-queries/db.d.ts.map +0 -1
  146. package/dist/live-queries/db.js.map +0 -1
  147. package/dist/live-queries/db.test.d.ts +0 -2
  148. package/dist/live-queries/db.test.d.ts.map +0 -1
  149. package/dist/live-queries/db.test.js +0 -118
  150. package/dist/live-queries/db.test.js.map +0 -1
  151. package/dist/live-queries/graphql.d.ts +0 -49
  152. package/dist/live-queries/graphql.d.ts.map +0 -1
  153. package/dist/live-queries/graphql.js +0 -122
  154. package/dist/live-queries/graphql.js.map +0 -1
  155. package/dist/row-query-utils.d.ts +0 -17
  156. package/dist/row-query-utils.d.ts.map +0 -1
  157. package/dist/row-query-utils.js +0 -30
  158. package/dist/row-query-utils.js.map +0 -1
  159. package/dist/utils/otel.d.ts +0 -4
  160. package/dist/utils/otel.d.ts.map +0 -1
  161. package/dist/utils/otel.js +0 -6
  162. package/dist/utils/otel.js.map +0 -1
  163. package/src/global-state.ts +0 -20
  164. package/src/index.ts +0 -66
  165. package/src/live-queries/db.test.ts +0 -154
  166. package/src/live-queries/graphql.ts +0 -219
  167. package/src/row-query-utils.ts +0 -65
  168. package/src/utils/otel.ts +0 -9
  169. package/tsconfig.json +0 -18
  170. package/vitest.config.js +0 -9
@@ -14,7 +14,6 @@ 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
@@ -22,33 +21,40 @@ exports[`otel > otel 3`] = `
22
21
  },
23
22
  },
24
23
  {
25
- "_name": "LiveStore:createStore",
24
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
25
+ "attributes": {
26
+ "batch": "undefined",
27
+ "batchSize": 1,
28
+ },
29
+ },
30
+ {
31
+ "_name": "client-session-sync-processor:pull",
32
+ "attributes": {
33
+ "code.stacktrace": "<STACKTRACE>",
34
+ "span.label": "⚠︎ Interrupted",
35
+ "status.interrupted": true,
36
+ },
26
37
  },
27
38
  {
28
39
  "_name": "LiveStore:sync",
29
40
  },
30
41
  {
31
- "_name": "LiveStore:mutations",
42
+ "_name": "LiveStore:commits",
32
43
  "children": [
33
44
  {
34
- "_name": "LiveStore:mutate",
45
+ "_name": "LiveStore:commit",
35
46
  "attributes": {
36
- "livestore.mutateLabel": "mutate",
47
+ "livestore.eventTags": [
48
+ "livestore.RawSql",
49
+ ],
50
+ "livestore.eventsCount": 1,
37
51
  },
38
52
  "children": [
39
53
  {
40
- "_name": "LiveStore:mutate:applyMutations",
54
+ "_name": "livestore.in-memory-db:execute",
41
55
  "attributes": {
42
- "livestore.mutateLabel": "mutate",
56
+ "sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
43
57
  },
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
58
  },
53
59
  ],
54
60
  },
@@ -97,7 +103,179 @@ exports[`otel > otel 3`] = `
97
103
  }
98
104
  `;
99
105
 
106
+ exports[`otel > with thunks 1`] = `
107
+ {
108
+ "atoms": [
109
+ {
110
+ "_tag": "ref",
111
+ "id": "node-1",
112
+ "isDestroyed": false,
113
+ "isDirty": false,
114
+ "label": "tableRef:todos",
115
+ "meta": {
116
+ "liveStoreRefType": "table",
117
+ },
118
+ "previousResult": {
119
+ "_tag": "Some",
120
+ "value": "null",
121
+ },
122
+ "refreshes": 0,
123
+ "sub": [],
124
+ "super": [],
125
+ },
126
+ {
127
+ "_tag": "ref",
128
+ "id": "node-2",
129
+ "isDestroyed": false,
130
+ "isDirty": false,
131
+ "label": "tableRef:app",
132
+ "meta": {
133
+ "liveStoreRefType": "table",
134
+ },
135
+ "previousResult": {
136
+ "_tag": "Some",
137
+ "value": "null",
138
+ },
139
+ "refreshes": 0,
140
+ "sub": [],
141
+ "super": [],
142
+ },
143
+ ],
144
+ "deferredEffects": [],
145
+ "effects": [],
146
+ }
147
+ `;
148
+
100
149
  exports[`otel > with thunks 3`] = `
150
+ {
151
+ "atoms": [
152
+ {
153
+ "_tag": "ref",
154
+ "id": "node-1",
155
+ "isDestroyed": false,
156
+ "isDirty": false,
157
+ "label": "tableRef:todos",
158
+ "meta": {
159
+ "liveStoreRefType": "table",
160
+ },
161
+ "previousResult": {
162
+ "_tag": "Some",
163
+ "value": "null",
164
+ },
165
+ "refreshes": 0,
166
+ "sub": [],
167
+ "super": [],
168
+ },
169
+ {
170
+ "_tag": "ref",
171
+ "id": "node-2",
172
+ "isDestroyed": false,
173
+ "isDirty": false,
174
+ "label": "tableRef:app",
175
+ "meta": {
176
+ "liveStoreRefType": "table",
177
+ },
178
+ "previousResult": {
179
+ "_tag": "Some",
180
+ "value": "null",
181
+ },
182
+ "refreshes": 0,
183
+ "sub": [],
184
+ "super": [],
185
+ },
186
+ ],
187
+ "deferredEffects": [],
188
+ "effects": [],
189
+ }
190
+ `;
191
+
192
+ exports[`otel > with thunks 4`] = `
193
+ {
194
+ "atoms": [
195
+ {
196
+ "_tag": "ref",
197
+ "id": "node-1",
198
+ "isDestroyed": false,
199
+ "isDirty": false,
200
+ "label": "tableRef:todos",
201
+ "meta": {
202
+ "liveStoreRefType": "table",
203
+ },
204
+ "previousResult": {
205
+ "_tag": "Some",
206
+ "value": "null",
207
+ },
208
+ "refreshes": 1,
209
+ "sub": [],
210
+ "super": [],
211
+ },
212
+ {
213
+ "_tag": "ref",
214
+ "id": "node-2",
215
+ "isDestroyed": false,
216
+ "isDirty": false,
217
+ "label": "tableRef:app",
218
+ "meta": {
219
+ "liveStoreRefType": "table",
220
+ },
221
+ "previousResult": {
222
+ "_tag": "Some",
223
+ "value": "null",
224
+ },
225
+ "refreshes": 0,
226
+ "sub": [],
227
+ "super": [],
228
+ },
229
+ ],
230
+ "deferredEffects": [],
231
+ "effects": [],
232
+ }
233
+ `;
234
+
235
+ exports[`otel > with thunks 6`] = `
236
+ {
237
+ "atoms": [
238
+ {
239
+ "_tag": "ref",
240
+ "id": "node-1",
241
+ "isDestroyed": false,
242
+ "isDirty": false,
243
+ "label": "tableRef:todos",
244
+ "meta": {
245
+ "liveStoreRefType": "table",
246
+ },
247
+ "previousResult": {
248
+ "_tag": "Some",
249
+ "value": "null",
250
+ },
251
+ "refreshes": 1,
252
+ "sub": [],
253
+ "super": [],
254
+ },
255
+ {
256
+ "_tag": "ref",
257
+ "id": "node-2",
258
+ "isDestroyed": false,
259
+ "isDirty": false,
260
+ "label": "tableRef:app",
261
+ "meta": {
262
+ "liveStoreRefType": "table",
263
+ },
264
+ "previousResult": {
265
+ "_tag": "Some",
266
+ "value": "null",
267
+ },
268
+ "refreshes": 0,
269
+ "sub": [],
270
+ "super": [],
271
+ },
272
+ ],
273
+ "deferredEffects": [],
274
+ "effects": [],
275
+ }
276
+ `;
277
+
278
+ exports[`otel > with thunks 7`] = `
101
279
  {
102
280
  "_name": "createStore",
103
281
  "attributes": {
@@ -111,7 +289,6 @@ exports[`otel > with thunks 3`] = `
111
289
  "sql.query": "
112
290
  PRAGMA page_size=32768;
113
291
  PRAGMA cache_size=10000;
114
- PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
115
292
  PRAGMA synchronous='OFF';
116
293
  PRAGMA temp_store='MEMORY';
117
294
  PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
@@ -119,33 +296,40 @@ exports[`otel > with thunks 3`] = `
119
296
  },
120
297
  },
121
298
  {
122
- "_name": "LiveStore:createStore",
299
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
300
+ "attributes": {
301
+ "batch": "undefined",
302
+ "batchSize": 1,
303
+ },
304
+ },
305
+ {
306
+ "_name": "client-session-sync-processor:pull",
307
+ "attributes": {
308
+ "code.stacktrace": "<STACKTRACE>",
309
+ "span.label": "⚠︎ Interrupted",
310
+ "status.interrupted": true,
311
+ },
123
312
  },
124
313
  {
125
314
  "_name": "LiveStore:sync",
126
315
  },
127
316
  {
128
- "_name": "LiveStore:mutations",
317
+ "_name": "LiveStore:commits",
129
318
  "children": [
130
319
  {
131
- "_name": "LiveStore:mutate",
320
+ "_name": "LiveStore:commit",
132
321
  "attributes": {
133
- "livestore.mutateLabel": "mutate",
322
+ "livestore.eventTags": [
323
+ "livestore.RawSql",
324
+ ],
325
+ "livestore.eventsCount": 1,
134
326
  },
135
327
  "children": [
136
328
  {
137
- "_name": "LiveStore:mutate:applyMutations",
329
+ "_name": "livestore.in-memory-db:execute",
138
330
  "attributes": {
139
- "livestore.mutateLabel": "mutate",
331
+ "sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
140
332
  },
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
333
  },
150
334
  ],
151
335
  },
@@ -181,6 +365,9 @@ exports[`otel > with thunks 3`] = `
181
365
  "sql.rowsCount": 1,
182
366
  },
183
367
  "children": [
368
+ {
369
+ "_name": "js:where-filter",
370
+ },
184
371
  {
185
372
  "_name": "sql-in-memory-select",
186
373
  "attributes": {
@@ -211,7 +398,6 @@ exports[`otel > with thunks with query builder and without labels 3`] = `
211
398
  "sql.query": "
212
399
  PRAGMA page_size=32768;
213
400
  PRAGMA cache_size=10000;
214
- PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
215
401
  PRAGMA synchronous='OFF';
216
402
  PRAGMA temp_store='MEMORY';
217
403
  PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
@@ -219,33 +405,40 @@ exports[`otel > with thunks with query builder and without labels 3`] = `
219
405
  },
220
406
  },
221
407
  {
222
- "_name": "LiveStore:createStore",
408
+ "_name": "@livestore/common:LeaderSyncProcessor:push",
409
+ "attributes": {
410
+ "batch": "undefined",
411
+ "batchSize": 1,
412
+ },
413
+ },
414
+ {
415
+ "_name": "client-session-sync-processor:pull",
416
+ "attributes": {
417
+ "code.stacktrace": "<STACKTRACE>",
418
+ "span.label": "⚠︎ Interrupted",
419
+ "status.interrupted": true,
420
+ },
223
421
  },
224
422
  {
225
423
  "_name": "LiveStore:sync",
226
424
  },
227
425
  {
228
- "_name": "LiveStore:mutations",
426
+ "_name": "LiveStore:commits",
229
427
  "children": [
230
428
  {
231
- "_name": "LiveStore:mutate",
429
+ "_name": "LiveStore:commit",
232
430
  "attributes": {
233
- "livestore.mutateLabel": "mutate",
431
+ "livestore.eventTags": [
432
+ "livestore.RawSql",
433
+ ],
434
+ "livestore.eventsCount": 1,
234
435
  },
235
436
  "children": [
236
437
  {
237
- "_name": "LiveStore:mutate:applyMutations",
438
+ "_name": "livestore.in-memory-db:execute",
238
439
  "attributes": {
239
- "livestore.mutateLabel": "mutate",
440
+ "sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
240
441
  },
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
442
  },
250
443
  ],
251
444
  },
@@ -281,6 +474,9 @@ exports[`otel > with thunks with query builder and without labels 3`] = `
281
474
  "sql.rowsCount": 1,
282
475
  },
283
476
  "children": [
477
+ {
478
+ "_name": "js:() => ({ completed: false })",
479
+ },
284
480
  {
285
481
  "_name": "sql-in-memory-select",
286
482
  "attributes": {
@@ -1,121 +1,238 @@
1
- import type { QueryInfo } from '@livestore/common'
1
+ import { isNotNil } from '@livestore/utils'
2
+ import { Predicate } from '@livestore/utils/effect'
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<LiveQuery.Any | ISignal<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 LiveQueryDef.Any | LiveQuery.Any | SignalDef<any>> =
27
+ TQuery extends LiveQuery<infer TResult>
28
+ ? TResult
29
+ : TQuery extends LiveQueryDef<infer TResult>
30
+ ? TResult
31
+ : TQuery extends SignalDef<infer TResult>
32
+ ? TResult
33
+ : unknown
25
34
 
26
35
  let queryIdCounter = 0
27
36
 
28
- export type LiveQueryAny = LiveQuery<any, QueryInfo>
37
+ export interface SignalDef<T> extends LiveQueryDef<T, 'signal-def'> {
38
+ _tag: 'signal-def'
39
+ defaultValue: T
40
+ hash: string
41
+ label: string
42
+ make: (ctx: ReactivityGraphContext) => RcRef<ISignal<T>>
43
+ }
44
+
45
+ export interface ISignal<T> extends LiveQuery<T> {
46
+ _tag: 'signal'
47
+ reactivityGraph: ReactivityGraph
48
+ ref: RG.Ref<T, ReactivityGraphContext, RefreshReason>
49
+ set: (value: T) => void
50
+ get: () => T
51
+ destroy: () => void
52
+ }
29
53
 
30
54
  export const TypeId = Symbol.for('LiveQuery')
31
55
  export type TypeId = typeof TypeId
32
56
 
33
- export interface LiveQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> {
57
+ export interface RcRef<T> {
58
+ rc: number
59
+ value: T
60
+ deref: () => void
61
+ }
62
+
63
+ export type DepKey = string | number | ReadonlyArray<string | number | undefined | null>
64
+
65
+ export const depsToString = (deps: DepKey): string => {
66
+ if (typeof deps === 'string' || typeof deps === 'number') {
67
+ return deps.toString()
68
+ }
69
+ return deps.filter(isNotNil).join(',')
70
+ }
71
+
72
+ // TODO we should refactor/clean up how LiveQueryDef / SignalDef / LiveQuery / ISignal are defined (particularly on the type-level)
73
+ export interface LiveQueryDef<TResult, TTag extends string = 'def'> {
74
+ _tag: TTag
75
+ /** Creates a new LiveQuery instance bound to a specific store/reactivityGraph */
76
+ make: (ctx: ReactivityGraphContext, otelContext?: otel.Context) => RcRef<LiveQuery<TResult> | ISignal<TResult>>
77
+ label: string
78
+ hash: string
79
+ }
80
+
81
+ export namespace LiveQueryDef {
82
+ export type Any = LiveQueryDef<any, 'def' | 'signal-def'>
83
+ }
84
+
85
+ /**
86
+ * A LiveQuery is stateful
87
+ */
88
+ export interface LiveQuery<TResult> {
34
89
  id: number
35
- _tag: 'computed' | 'db' | 'graphql'
90
+ _tag: 'computed' | 'db' | 'graphql' | 'signal'
36
91
  [TypeId]: TypeId
37
92
 
93
+ // reactivityGraph: ReactivityGraph
94
+
38
95
  /** This should only be used on a type-level and doesn't hold any value during runtime */
39
96
  '__result!': TResult
40
97
 
41
98
  /** A reactive thunk representing the query results */
42
- results$: Thunk<TResult, QueryContext, RefreshReason>
99
+ results$: RG.Atom<TResult, ReactivityGraphContext, RefreshReason>
43
100
 
44
101
  label: string
45
102
 
46
- run: (otelContext?: otel.Context, debugRefreshReason?: RefreshReason) => TResult
103
+ run: (args: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason }) => TResult
47
104
 
48
- runAndDestroy: (otelContext?: otel.Context, debugRefreshReason?: RefreshReason) => TResult
105
+ destroy: () => void
106
+ isDestroyed: boolean
49
107
 
50
- destroy(): void
51
-
52
- subscribe(
53
- onNewValue: (value: TResult) => void,
54
- onUnsubsubscribe?: () => void,
55
- options?: { label?: string; otelContext?: otel.Context },
56
- ): () => void
108
+ // subscribe(
109
+ // onNewValue: (value: TResult) => void,
110
+ // onUnsubsubscribe?: () => void,
111
+ // options?: { label?: string; otelContext?: otel.Context },
112
+ // ): () => void
57
113
 
58
114
  activeSubscriptions: Set<StackInfo>
59
115
 
60
- queryInfo: TQueryInfo
61
-
62
116
  runs: number
63
117
 
64
118
  executionTimes: number[]
119
+ def: LiveQueryDef<TResult> | SignalDef<TResult>
65
120
  }
66
121
 
67
- export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
68
- implements LiveQuery<TResult, TQueryInfo>
69
- {
122
+ export namespace LiveQuery {
123
+ export type Any = LiveQuery<any>
124
+ }
125
+
126
+ export abstract class LiveStoreQueryBase<TResult> implements LiveQuery<TResult> {
70
127
  '__result!'!: TResult
71
128
  id = queryIdCounter++;
72
129
  [TypeId]: TypeId = TypeId
73
- abstract _tag: 'computed' | 'db' | 'graphql'
130
+ abstract _tag: 'computed' | 'db' | 'graphql' | 'signal'
74
131
 
75
132
  /** Human-readable label for the query for debugging */
76
133
  abstract label: string
77
134
 
78
- abstract results$: Thunk<TResult, QueryContext, RefreshReason>
135
+ abstract def: LiveQueryDef<TResult> | SignalDef<TResult>
79
136
 
80
- activeSubscriptions: Set<StackInfo> = new Set()
137
+ abstract results$: RG.Atom<TResult, ReactivityGraphContext, RefreshReason>
81
138
 
82
- protected abstract reactivityGraph: ReactivityGraph
139
+ activeSubscriptions: Set<StackInfo> = new Set()
83
140
 
84
- abstract queryInfo: TQueryInfo
141
+ abstract readonly reactivityGraph: ReactivityGraph
85
142
 
86
143
  get runs() {
87
- return this.results$.recomputations
144
+ if (this.results$._tag === 'thunk') {
145
+ return this.results$.recomputations
146
+ }
147
+ return 0
88
148
  }
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, 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
156
+ run = (args: { otelContext?: otel.Context; debugRefreshReason?: RefreshReason }): TResult => {
157
+ return this.results$.computeResult(args.otelContext, args.debugRefreshReason)
101
158
  }
102
159
 
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
- }
160
+ protected dependencyQueriesRef: DependencyQueriesRef = new Set()
111
161
 
112
- export type GetAtomResult = <T>(atom: Atom<T, any, RefreshReason> | LiveQuery<T, any>) => T
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 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)
171
+ export type GetAtomResult = <T>(
172
+ atom: RG.Atom<T, any, RefreshReason> | LiveQueryDef<T> | LiveQuery<T> | ISignal<T> | SignalDef<T>,
173
+ otelContext?: otel.Context | undefined,
174
+ debugRefreshReason?: RefreshReason | undefined,
175
+ ) => T
176
+
177
+ export type DependencyQueriesRef = Set<RcRef<LiveQuery.Any | ISignal<any>>>
178
+
179
+ export const makeGetAtomResult = (
180
+ get: RG.GetAtom,
181
+ ctx: ReactivityGraphContext,
182
+ otelContext: otel.Context,
183
+ dependencyQueriesRef: DependencyQueriesRef,
184
+ ) => {
185
+ // NOTE we're using the `otelContext` from `makeGetAtomResult` here, not the `otelContext` from `getAtom`
186
+ const getAtom: GetAtomResult = (atom, _otelContext, debugRefreshReason) => {
187
+ // ReactivityGraph atoms case
188
+ if (atom._tag === 'thunk' || atom._tag === 'ref') return get(atom, otelContext, debugRefreshReason)
189
+
190
+ // def case
191
+ if (atom._tag === 'def' || atom._tag === 'signal-def') {
192
+ const query = atom.make(ctx)
193
+ dependencyQueriesRef.add(query)
194
+ // TODO deref the query on destroy
195
+ return getAtom(query.value, _otelContext, debugRefreshReason)
196
+ }
197
+
198
+ // Signal case
199
+ if (atom._tag === 'signal' && Predicate.hasProperty(atom, 'ref')) {
200
+ return get(atom.ref, otelContext, debugRefreshReason)
201
+ }
202
+
203
+ // LiveQuery case
204
+ return get(atom.results$, otelContext, debugRefreshReason)
118
205
  }
119
206
 
120
207
  return getAtom
121
208
  }
209
+
210
+ export const withRCMap = <T extends LiveQuery.Any | ISignal<any>>(
211
+ id: string,
212
+ make: (ctx: ReactivityGraphContext, otelContext?: otel.Context) => T,
213
+ ): ((ctx: ReactivityGraphContext, otelContext?: otel.Context) => RcRef<T>) => {
214
+ return (ctx, otelContext) => {
215
+ let item = ctx.defRcMap.get(id)
216
+ if (item) {
217
+ item.rc++
218
+ return item as RcRef<T>
219
+ }
220
+
221
+ const query$ = make(ctx, otelContext)
222
+
223
+ item = {
224
+ rc: 1,
225
+ value: query$,
226
+ deref: () => {
227
+ item!.rc--
228
+ if (item!.rc === 0) {
229
+ item!.value.destroy()
230
+ ctx.defRcMap.delete(id)
231
+ }
232
+ },
233
+ }
234
+ ctx.defRcMap.set(id, item)
235
+
236
+ return item as RcRef<T>
237
+ }
238
+ }