@livestore/livestore 0.0.39-dev.3 → 0.0.40
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/README.md +15 -24
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/react/fixture.d.ts +210 -35
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +10 -29
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/cud.d.ts +28 -0
- package/dist/cud.d.ts.map +1 -0
- package/dist/cud.js +50 -0
- package/dist/cud.js.map +1 -0
- package/dist/cud.test.d.ts +2 -0
- package/dist/cud.test.d.ts.map +1 -0
- package/dist/cud.test.js +47 -0
- package/dist/cud.test.js.map +1 -0
- package/dist/inMemoryDatabase.d.ts +1 -1
- package/dist/inMemoryDatabase.d.ts.map +1 -1
- package/dist/inMemoryDatabase.js +1 -4
- package/dist/inMemoryDatabase.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +11 -7
- package/dist/migrations.js.map +1 -1
- package/dist/query-info.d.ts +49 -0
- package/dist/query-info.d.ts.map +1 -0
- package/dist/{update-path.js → query-info.js} +4 -3
- package/dist/query-info.js.map +1 -0
- package/dist/react/LiveStoreContext.d.ts +0 -6
- package/dist/react/LiveStoreContext.d.ts.map +1 -1
- package/dist/react/LiveStoreContext.js.map +1 -1
- package/dist/react/useAtom.d.ts +2 -2
- package/dist/react/useAtom.d.ts.map +1 -1
- package/dist/react/useAtom.js +3 -3
- package/dist/react/useAtom.js.map +1 -1
- package/dist/react/useQuery.d.ts.map +1 -1
- package/dist/react/useQuery.test.d.ts.map +1 -0
- package/dist/{__tests__/react → react}/useQuery.test.js +8 -11
- package/dist/react/useQuery.test.js.map +1 -0
- package/dist/react/useRow.d.ts +2 -2
- package/dist/react/useRow.d.ts.map +1 -1
- package/dist/react/useRow.js +5 -5
- package/dist/react/useRow.js.map +1 -1
- package/dist/react/useRow.test.d.ts.map +1 -0
- package/dist/{__tests__/react → react}/useRow.test.js +14 -38
- package/dist/react/useRow.test.js.map +1 -0
- package/dist/react/useTemporaryQuery.d.ts +2 -2
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/reactive.d.ts +2 -2
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +50 -15
- package/dist/reactive.js.map +1 -1
- package/dist/reactive.test.d.ts.map +1 -0
- package/dist/{__tests__/reactive.test.js → reactive.test.js} +1 -1
- package/dist/reactive.test.js.map +1 -0
- package/dist/reactiveQueries/base-class.d.ts +16 -8
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +2 -1
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +15 -9
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +29 -8
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +8 -8
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js +5 -4
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +11 -11
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +7 -6
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/reactiveQueries/sql.test.d.ts.map +1 -0
- package/dist/{__tests__/reactiveQueries → reactiveQueries}/sql.test.js +44 -34
- package/dist/reactiveQueries/sql.test.js.map +1 -0
- package/dist/row-query.d.ts +5 -5
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +11 -9
- package/dist/row-query.js.map +1 -1
- package/dist/schema/index.d.ts +20 -7
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +18 -3
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/mutations.d.ts +81 -0
- package/dist/schema/mutations.d.ts.map +1 -0
- package/dist/schema/mutations.js +29 -0
- package/dist/schema/mutations.js.map +1 -0
- package/dist/schema/parse-utils.d.ts +3 -6
- package/dist/schema/parse-utils.d.ts.map +1 -1
- package/dist/schema/parse-utils.js +2 -27
- package/dist/schema/parse-utils.js.map +1 -1
- package/dist/schema/system-tables.d.ts +8 -8
- package/dist/schema/table-def.d.ts +6 -6
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +2 -2
- package/dist/schema/table-def.js.map +1 -1
- package/dist/storage/in-memory/index.d.ts +4 -0
- package/dist/storage/in-memory/index.d.ts.map +1 -1
- package/dist/storage/in-memory/index.js +3 -0
- package/dist/storage/in-memory/index.js.map +1 -1
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/tauri/index.d.ts +4 -0
- package/dist/storage/tauri/index.d.ts.map +1 -1
- package/dist/storage/tauri/index.js +6 -0
- package/dist/storage/tauri/index.js.map +1 -1
- package/dist/storage/utils/idb.d.ts +1 -0
- package/dist/storage/utils/idb.d.ts.map +1 -1
- package/dist/storage/utils/idb.js +11 -0
- package/dist/storage/utils/idb.js.map +1 -1
- package/dist/storage/web-worker/common.d.ts +11 -0
- package/dist/storage/web-worker/common.d.ts.map +1 -0
- package/dist/storage/web-worker/common.js +2 -0
- package/dist/storage/web-worker/common.js.map +1 -0
- package/dist/storage/web-worker/index.d.ts +14 -7
- package/dist/storage/web-worker/index.d.ts.map +1 -1
- package/dist/storage/web-worker/index.js +70 -14
- package/dist/storage/web-worker/index.js.map +1 -1
- package/dist/storage/web-worker/make-worker.d.ts +20 -0
- package/dist/storage/web-worker/make-worker.d.ts.map +1 -0
- package/dist/storage/web-worker/make-worker.js +155 -0
- package/dist/storage/web-worker/make-worker.js.map +1 -0
- package/dist/storage/web-worker/vite-dev-polyfill.d.ts +2 -0
- package/dist/storage/web-worker/vite-dev-polyfill.d.ts.map +1 -0
- package/dist/storage/web-worker/vite-dev-polyfill.js +35 -0
- package/dist/storage/web-worker/vite-dev-polyfill.js.map +1 -0
- package/dist/store.d.ts +32 -42
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +82 -131
- package/dist/store.js.map +1 -1
- package/dist/utils/dev.d.ts +3 -0
- package/dist/utils/dev.d.ts.map +1 -0
- package/dist/utils/dev.js +16 -0
- package/dist/utils/dev.js.map +1 -0
- package/dist/utils/util.d.ts +2 -0
- package/dist/utils/util.d.ts.map +1 -1
- package/dist/utils/util.js +2 -0
- package/dist/utils/util.js.map +1 -1
- package/package.json +26 -14
- package/src/__tests__/react/fixture.tsx +12 -30
- package/src/cud.test.ts +52 -0
- package/src/cud.ts +92 -0
- package/src/inMemoryDatabase.ts +2 -7
- package/src/index.ts +14 -8
- package/src/migrations.ts +10 -7
- package/src/{update-path.ts → query-info.ts} +18 -21
- package/src/react/LiveStoreContext.ts +0 -9
- package/src/react/useAtom.ts +6 -6
- package/src/{__tests__/react → react}/useQuery.test.tsx +11 -11
- package/src/react/useQuery.ts +1 -1
- package/src/{__tests__/react → react}/useRow.test.tsx +21 -39
- package/src/react/useRow.ts +10 -10
- package/src/{__tests__/reactive.test.ts → reactive.test.ts} +1 -1
- package/src/reactive.ts +60 -19
- package/src/reactiveQueries/base-class.ts +23 -9
- package/src/reactiveQueries/graphql.ts +49 -13
- package/src/reactiveQueries/js.ts +15 -13
- package/src/{__tests__/reactiveQueries → reactiveQueries}/sql.test.ts +44 -34
- package/src/reactiveQueries/sql.ts +24 -22
- package/src/row-query.ts +24 -22
- package/src/schema/index.ts +47 -11
- package/src/schema/mutations.ts +129 -0
- package/src/schema/parse-utils.ts +3 -45
- package/src/schema/table-def.ts +9 -2
- package/src/storage/in-memory/index.ts +7 -0
- package/src/storage/index.ts +8 -0
- package/src/storage/tauri/index.ts +10 -0
- package/src/storage/utils/idb.ts +14 -0
- package/src/storage/web-worker/common.ts +6 -0
- package/src/storage/web-worker/index.ts +86 -17
- package/src/storage/web-worker/make-worker.ts +214 -0
- package/src/storage/web-worker/vite-dev-polyfill.ts +33 -0
- package/src/store.ts +142 -212
- package/src/utils/dev.ts +23 -0
- package/src/utils/util.ts +4 -0
- package/dist/__tests__/mutations.test.d.ts +0 -2
- package/dist/__tests__/mutations.test.d.ts.map +0 -1
- package/dist/__tests__/mutations.test.js +0 -40
- package/dist/__tests__/mutations.test.js.map +0 -1
- package/dist/__tests__/react/useQuery.test.d.ts.map +0 -1
- package/dist/__tests__/react/useQuery.test.js.map +0 -1
- package/dist/__tests__/react/useRow.test.d.ts.map +0 -1
- package/dist/__tests__/react/useRow.test.js.map +0 -1
- package/dist/__tests__/reactive.test.d.ts.map +0 -1
- package/dist/__tests__/reactive.test.js.map +0 -1
- package/dist/__tests__/reactiveQueries/sql.test.d.ts.map +0 -1
- package/dist/__tests__/reactiveQueries/sql.test.js.map +0 -1
- package/dist/events.d.ts +0 -7
- package/dist/events.d.ts.map +0 -1
- package/dist/events.js +0 -2
- package/dist/events.js.map +0 -1
- package/dist/mutations.d.ts +0 -33
- package/dist/mutations.d.ts.map +0 -1
- package/dist/mutations.js +0 -38
- package/dist/mutations.js.map +0 -1
- package/dist/schema/action.d.ts +0 -30
- package/dist/schema/action.d.ts.map +0 -1
- package/dist/schema/action.js +0 -3
- package/dist/schema/action.js.map +0 -1
- package/dist/storage/web-worker/worker.d.ts +0 -13
- package/dist/storage/web-worker/worker.d.ts.map +0 -1
- package/dist/storage/web-worker/worker.js +0 -110
- package/dist/storage/web-worker/worker.js.map +0 -1
- package/dist/update-path.d.ts +0 -52
- package/dist/update-path.d.ts.map +0 -1
- package/dist/update-path.js.map +0 -1
- package/src/__tests__/mutations.test.ts +0 -43
- package/src/events.ts +0 -8
- package/src/mutations.ts +0 -79
- package/src/schema/action.ts +0 -41
- package/src/storage/web-worker/worker.ts +0 -141
- /package/dist/{__tests__/react → react}/useQuery.test.d.ts +0 -0
- /package/dist/{__tests__/react → react}/useRow.test.d.ts +0 -0
- /package/dist/{__tests__/reactive.test.d.ts → reactive.test.d.ts} +0 -0
- /package/dist/{__tests__/reactiveQueries → reactiveQueries}/sql.test.d.ts +0 -0
package/src/reactive.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
/* eslint-disable prefer-arrow/prefer-arrow-functions */
|
|
25
25
|
|
|
26
26
|
import type { PrettifyFlat } from '@livestore/utils'
|
|
27
|
-
import {
|
|
27
|
+
import { shouldNeverHappen } from '@livestore/utils'
|
|
28
28
|
import type * as otel from '@opentelemetry/api'
|
|
29
29
|
import { isEqual } from 'lodash-es'
|
|
30
30
|
|
|
@@ -94,7 +94,7 @@ export type DebugThunkInfo<T extends string = string> = {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
export type DebugRefreshReasonBase =
|
|
97
|
-
/** Usually in response to some `
|
|
97
|
+
/** Usually in response to some `mutate` calls with `skipRefresh: true` */
|
|
98
98
|
| {
|
|
99
99
|
_tag: 'runDeferredEffects'
|
|
100
100
|
originalRefreshReasons?: ReadonlyArray<DebugRefreshReasonBase>
|
|
@@ -135,7 +135,7 @@ const unknownRefreshReason = () => {
|
|
|
135
135
|
|
|
136
136
|
export type SerializedAtom = Readonly<
|
|
137
137
|
PrettifyFlat<
|
|
138
|
-
Pick<Atom<unknown, unknown, any>, '_tag' | 'id' | 'label' | 'meta'> & {
|
|
138
|
+
Pick<Atom<unknown, unknown, any>, '_tag' | 'id' | 'label' | 'meta' | 'isDirty'> & {
|
|
139
139
|
sub: ReadonlyArray<string>
|
|
140
140
|
super: ReadonlyArray<string>
|
|
141
141
|
}
|
|
@@ -162,17 +162,6 @@ const uniqueNodeId = () => `node-${++nodeIdCounter}`
|
|
|
162
162
|
let refreshInfoIdCounter = 0
|
|
163
163
|
const uniqueRefreshInfoId = () => `refresh-info-${++refreshInfoIdCounter}`
|
|
164
164
|
|
|
165
|
-
const serializeAtom = (atom: Atom<any, unknown, any>): SerializedAtom => ({
|
|
166
|
-
...pick(atom, ['_tag', 'id', 'label', 'meta', 'isDirty']),
|
|
167
|
-
sub: Array.from(atom.sub).map((a) => a.id),
|
|
168
|
-
super: Array.from(atom.super).map((a) => a.id),
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
const serializeEffect = (effect: Effect): SerializedEffect => ({
|
|
172
|
-
...pick(effect, ['_tag', 'id', 'label']),
|
|
173
|
-
sub: Array.from(effect.sub).map((a) => a.id),
|
|
174
|
-
})
|
|
175
|
-
|
|
176
165
|
let globalGraphIdCounter = 0
|
|
177
166
|
const uniqueGraphId = () => `graph-${++globalGraphIdCounter}`
|
|
178
167
|
|
|
@@ -515,11 +504,25 @@ export class ReactiveGraph<
|
|
|
515
504
|
subComp.super.delete(superComp)
|
|
516
505
|
}
|
|
517
506
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
507
|
+
// NOTE This function is performance-optimized (i.e. not using `Array.from`)
|
|
508
|
+
getSnapshot = (): ReactiveGraphSnapshot => {
|
|
509
|
+
const atoms: SerializedAtom[] = []
|
|
510
|
+
for (const atom of this.atoms) {
|
|
511
|
+
atoms.push(serializeAtom(atom))
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const effects: SerializedEffect[] = []
|
|
515
|
+
for (const effect of this.effects) {
|
|
516
|
+
effects.push(serializeEffect(effect))
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const deferredEffects: string[] = []
|
|
520
|
+
for (const [effect] of this.deferredEffects) {
|
|
521
|
+
deferredEffects.push(effect.id)
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return { atoms, effects, deferredEffects }
|
|
525
|
+
}
|
|
523
526
|
|
|
524
527
|
subscribeToRefresh = (cb: () => void) => {
|
|
525
528
|
this.refreshCallbacks.add(cb)
|
|
@@ -561,3 +564,41 @@ const markSuperCompDirtyRec = <T>(atom: Atom<T, unknown, any>, effectsToRefresh:
|
|
|
561
564
|
export const throwContextNotSetError = (graph: ReactiveGraph<any, any, any>): never => {
|
|
562
565
|
throw new Error(`LiveStore Error: \`context\` not set on ReactiveGraph (${graph.id})`)
|
|
563
566
|
}
|
|
567
|
+
|
|
568
|
+
// NOTE This function is performance-optimized (i.e. not using `pick` and `Array.from`)
|
|
569
|
+
const serializeAtom = (atom: Atom<any, unknown, any>): SerializedAtom => {
|
|
570
|
+
const sub: string[] = []
|
|
571
|
+
for (const a of atom.sub) {
|
|
572
|
+
sub.push(a.id)
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const super_: string[] = []
|
|
576
|
+
for (const a of atom.super) {
|
|
577
|
+
super_.push(a.id)
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return {
|
|
581
|
+
_tag: atom._tag,
|
|
582
|
+
id: atom.id,
|
|
583
|
+
label: atom.label,
|
|
584
|
+
meta: atom.meta,
|
|
585
|
+
isDirty: atom.isDirty,
|
|
586
|
+
sub,
|
|
587
|
+
super: super_,
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// NOTE This function is performance-optimized (i.e. not using `pick` and `Array.from`)
|
|
592
|
+
const serializeEffect = (effect: Effect): SerializedEffect => {
|
|
593
|
+
const sub: string[] = []
|
|
594
|
+
for (const a of effect.sub) {
|
|
595
|
+
sub.push(a.id)
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return {
|
|
599
|
+
_tag: effect._tag,
|
|
600
|
+
id: effect.id,
|
|
601
|
+
label: effect.label,
|
|
602
|
+
sub,
|
|
603
|
+
}
|
|
604
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type * as otel from '@opentelemetry/api'
|
|
2
2
|
import ReactDOM from 'react-dom'
|
|
3
3
|
|
|
4
|
+
import type { QueryInfo, QueryInfoNone } from '../query-info.js'
|
|
4
5
|
import type { StackInfo } from '../react/utils/stack-info.js'
|
|
5
6
|
import { type Atom, type GetAtom, ReactiveGraph, throwContextNotSetError, type Thunk } from '../reactive.js'
|
|
6
7
|
import type { QueryDebugInfo, RefreshReason, Store } from '../store.js'
|
|
7
|
-
import type { UpdatePathDesc, UpdatePathDescNone } from '../update-path.js'
|
|
8
8
|
|
|
9
9
|
export type DbGraph = ReactiveGraph<RefreshReason, QueryDebugInfo, DbContext>
|
|
10
10
|
|
|
@@ -26,12 +26,14 @@ export type GetResult<TQuery extends LiveQueryAny> = TQuery extends LiveQuery<in
|
|
|
26
26
|
|
|
27
27
|
let queryIdCounter = 0
|
|
28
28
|
|
|
29
|
-
export type LiveQueryAny = LiveQuery<any,
|
|
29
|
+
export type LiveQueryAny = LiveQuery<any, QueryInfo>
|
|
30
30
|
|
|
31
|
-
export interface LiveQuery<TResult,
|
|
31
|
+
export interface LiveQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoNone> {
|
|
32
32
|
id: number
|
|
33
33
|
_tag: 'js' | 'sql' | 'graphql'
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
/** This should only be used on a type-level and doesn't hold any value during runtime */
|
|
36
|
+
'__result!': TResult
|
|
35
37
|
|
|
36
38
|
/** A reactive thunk representing the query results */
|
|
37
39
|
results$: Thunk<TResult, DbContext, RefreshReason>
|
|
@@ -40,19 +42,29 @@ export interface LiveQuery<TResult, TUpdatePath extends UpdatePathDesc = UpdateP
|
|
|
40
42
|
|
|
41
43
|
run: (otelContext?: otel.Context, debugRefreshReason?: RefreshReason) => TResult
|
|
42
44
|
|
|
45
|
+
runAndDestroy: (otelContext?: otel.Context, debugRefreshReason?: RefreshReason) => TResult
|
|
46
|
+
|
|
43
47
|
destroy(): void
|
|
44
48
|
|
|
49
|
+
subscribe(
|
|
50
|
+
onNewValue: (value: TResult) => void,
|
|
51
|
+
onUnsubsubscribe?: () => void,
|
|
52
|
+
options?: { label?: string; otelContext?: otel.Context },
|
|
53
|
+
): () => void
|
|
54
|
+
|
|
45
55
|
activeSubscriptions: Set<StackInfo>
|
|
46
56
|
|
|
47
|
-
|
|
57
|
+
queryInfo: TQueryInfo
|
|
48
58
|
|
|
49
59
|
runs: number
|
|
60
|
+
|
|
61
|
+
executionTimes: number[]
|
|
50
62
|
}
|
|
51
63
|
|
|
52
|
-
export abstract class LiveStoreQueryBase<TResult,
|
|
53
|
-
implements LiveQuery<TResult,
|
|
64
|
+
export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
|
|
65
|
+
implements LiveQuery<TResult, TQueryInfo>
|
|
54
66
|
{
|
|
55
|
-
'
|
|
67
|
+
'__result!'!: TResult
|
|
56
68
|
id = queryIdCounter++
|
|
57
69
|
abstract _tag: 'js' | 'sql' | 'graphql'
|
|
58
70
|
|
|
@@ -65,12 +77,14 @@ export abstract class LiveStoreQueryBase<TResult, TUpdatePath extends UpdatePath
|
|
|
65
77
|
|
|
66
78
|
protected abstract dbGraph: DbGraph
|
|
67
79
|
|
|
68
|
-
abstract
|
|
80
|
+
abstract queryInfo: TQueryInfo
|
|
69
81
|
|
|
70
82
|
get runs() {
|
|
71
83
|
return this.results$.recomputations
|
|
72
84
|
}
|
|
73
85
|
|
|
86
|
+
executionTimes: number[] = []
|
|
87
|
+
|
|
74
88
|
abstract destroy: () => void
|
|
75
89
|
|
|
76
90
|
run = (otelContext?: otel.Context, debugRefreshReason?: RefreshReason): TResult =>
|
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'
|
|
2
|
-
import {
|
|
2
|
+
import { shouldNeverHappen } from '@livestore/utils'
|
|
3
|
+
import { Schema, TreeFormatter } from '@livestore/utils/effect'
|
|
3
4
|
import * as otel from '@opentelemetry/api'
|
|
4
5
|
import * as graphql from 'graphql'
|
|
5
6
|
|
|
6
7
|
import { globalDbGraph } from '../global-state.js'
|
|
8
|
+
import type { QueryInfoNone } from '../query-info.js'
|
|
7
9
|
import type { Thunk } from '../reactive.js'
|
|
8
10
|
import type { BaseGraphQLContext, RefreshReason, Store } from '../store.js'
|
|
9
|
-
import type { UpdatePathDescNone } from '../update-path.js'
|
|
10
11
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
11
12
|
import type { DbContext, DbGraph, GetAtomResult, LiveQuery } from './base-class.js'
|
|
12
13
|
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
13
14
|
|
|
14
|
-
export
|
|
15
|
+
export type MapResult<To, From> = ((res: From, get: GetAtomResult) => To) | Schema.Schema<never, From, To>
|
|
16
|
+
|
|
17
|
+
export const queryGraphQL = <
|
|
18
|
+
TResult extends Record<string, any>,
|
|
19
|
+
TVariableValues extends Record<string, any>,
|
|
20
|
+
TResultMapped extends Record<string, any> = TResult,
|
|
21
|
+
>(
|
|
15
22
|
document: DocumentNode<TResult, TVariableValues>,
|
|
16
23
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues),
|
|
17
|
-
{ label, dbGraph }: { label?: string; dbGraph?: DbGraph } = {},
|
|
18
|
-
): LiveQuery<
|
|
24
|
+
{ label, dbGraph, map }: { label?: string; dbGraph?: DbGraph; map?: MapResult<TResultMapped, TResult> } = {},
|
|
25
|
+
): LiveQuery<TResultMapped, QueryInfoNone> =>
|
|
26
|
+
new LiveStoreGraphQLQuery({ document, genVariableValues, label, dbGraph, map })
|
|
19
27
|
|
|
20
28
|
export class LiveStoreGraphQLQuery<
|
|
21
29
|
TResult extends Record<string, any>,
|
|
22
30
|
TVariableValues extends Record<string, any>,
|
|
23
31
|
TContext extends BaseGraphQLContext,
|
|
24
|
-
|
|
32
|
+
TResultMapped extends Record<string, any> = TResult,
|
|
33
|
+
> extends LiveStoreQueryBase<TResultMapped, QueryInfoNone> {
|
|
25
34
|
_tag: 'graphql' = 'graphql'
|
|
26
35
|
|
|
27
36
|
/** The abstract GraphQL query */
|
|
28
37
|
document: DocumentNode<TResult, TVariableValues>
|
|
29
38
|
|
|
30
39
|
/** A reactive thunk representing the query results */
|
|
31
|
-
results$: Thunk<
|
|
40
|
+
results$: Thunk<TResultMapped, DbContext, RefreshReason>
|
|
32
41
|
|
|
33
42
|
variableValues$: Thunk<TVariableValues, DbContext, RefreshReason>
|
|
34
43
|
|
|
@@ -36,18 +45,22 @@ export class LiveStoreGraphQLQuery<
|
|
|
36
45
|
|
|
37
46
|
protected dbGraph: DbGraph
|
|
38
47
|
|
|
39
|
-
|
|
48
|
+
queryInfo: QueryInfoNone = { _tag: 'None' }
|
|
49
|
+
|
|
50
|
+
private mapResult
|
|
40
51
|
|
|
41
52
|
constructor({
|
|
42
53
|
document,
|
|
43
54
|
label,
|
|
44
55
|
genVariableValues,
|
|
45
56
|
dbGraph,
|
|
57
|
+
map,
|
|
46
58
|
}: {
|
|
47
59
|
document: DocumentNode<TResult, TVariableValues>
|
|
48
60
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues)
|
|
49
61
|
label?: string
|
|
50
62
|
dbGraph?: DbGraph
|
|
63
|
+
map?: MapResult<TResultMapped, TResult>
|
|
51
64
|
}) {
|
|
52
65
|
super()
|
|
53
66
|
|
|
@@ -58,6 +71,23 @@ export class LiveStoreGraphQLQuery<
|
|
|
58
71
|
|
|
59
72
|
this.dbGraph = dbGraph ?? globalDbGraph
|
|
60
73
|
|
|
74
|
+
this.mapResult =
|
|
75
|
+
map === undefined
|
|
76
|
+
? (res: TResult) => res as any as TResultMapped
|
|
77
|
+
: Schema.isSchema(map)
|
|
78
|
+
? (res: TResult) => {
|
|
79
|
+
const parseResult = Schema.decodeEither(map as Schema.Schema<never, TResult, TResultMapped>)(res)
|
|
80
|
+
if (parseResult._tag === 'Left') {
|
|
81
|
+
console.error(`Error parsing GraphQL query result: ${TreeFormatter.formatError(parseResult.left)}`)
|
|
82
|
+
return shouldNeverHappen(`Error parsing SQL query result: ${parseResult.left}`)
|
|
83
|
+
} else {
|
|
84
|
+
return parseResult.right as TResultMapped
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
: typeof map === 'function'
|
|
88
|
+
? map
|
|
89
|
+
: shouldNeverHappen(`Invalid map function ${map}`)
|
|
90
|
+
|
|
61
91
|
// TODO don't even create a thunk if variables are static
|
|
62
92
|
const variableValues$ = this.dbGraph.makeThunk(
|
|
63
93
|
(get, _setDebugInfo, { rootOtelContext }, otelContext) => {
|
|
@@ -73,7 +103,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
73
103
|
this.variableValues$ = variableValues$
|
|
74
104
|
|
|
75
105
|
const resultsLabel = `${labelWithDefault}:results`
|
|
76
|
-
this.results$ = this.dbGraph.makeThunk<
|
|
106
|
+
this.results$ = this.dbGraph.makeThunk<TResultMapped>(
|
|
77
107
|
(get, setDebugInfo, { store, otelTracer, rootOtelContext }, otelContext) => {
|
|
78
108
|
const variableValues = get(variableValues$)
|
|
79
109
|
const { result, queriedTables, durationMs } = this.queryOnce({
|
|
@@ -82,13 +112,13 @@ export class LiveStoreGraphQLQuery<
|
|
|
82
112
|
otelContext: otelContext ?? rootOtelContext,
|
|
83
113
|
otelTracer,
|
|
84
114
|
store: store as Store<TContext>,
|
|
115
|
+
get: makeGetAtomResult(get, otelContext ?? rootOtelContext),
|
|
85
116
|
})
|
|
86
117
|
|
|
87
118
|
// Add dependencies on any tables that were used
|
|
88
119
|
for (const tableName of queriedTables) {
|
|
89
|
-
const tableRef = store.tableRefs[tableName]
|
|
90
|
-
|
|
91
|
-
get(tableRef!)
|
|
120
|
+
const tableRef = store.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`)
|
|
121
|
+
get(tableRef)
|
|
92
122
|
}
|
|
93
123
|
|
|
94
124
|
setDebugInfo({ _tag: 'graphql', label: resultsLabel, query: graphql.print(document), durationMs })
|
|
@@ -121,12 +151,14 @@ export class LiveStoreGraphQLQuery<
|
|
|
121
151
|
otelTracer,
|
|
122
152
|
variableValues,
|
|
123
153
|
store,
|
|
154
|
+
get,
|
|
124
155
|
}: {
|
|
125
156
|
document: graphql.DocumentNode
|
|
126
157
|
otelContext: otel.Context
|
|
127
158
|
otelTracer: otel.Tracer
|
|
128
159
|
variableValues: TVariableValues
|
|
129
160
|
store: Store<TContext>
|
|
161
|
+
get: GetAtomResult
|
|
130
162
|
}) => {
|
|
131
163
|
const schema =
|
|
132
164
|
store.graphQLSchema ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL schema")
|
|
@@ -161,10 +193,14 @@ export class LiveStoreGraphQLQuery<
|
|
|
161
193
|
|
|
162
194
|
span.end()
|
|
163
195
|
|
|
196
|
+
const result = this.mapResult(res.data as unknown as TResult, get)
|
|
197
|
+
|
|
164
198
|
const durationMs = getDurationMsFromSpan(span)
|
|
165
199
|
|
|
200
|
+
this.executionTimes.push(durationMs)
|
|
201
|
+
|
|
166
202
|
return {
|
|
167
|
-
result
|
|
203
|
+
result,
|
|
168
204
|
queriedTables: Array.from(context.queriedTables.values()),
|
|
169
205
|
durationMs,
|
|
170
206
|
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import * as otel from '@opentelemetry/api'
|
|
2
2
|
|
|
3
3
|
import { globalDbGraph } from '../global-state.js'
|
|
4
|
+
import type { QueryInfo, QueryInfoNone } from '../query-info.js'
|
|
4
5
|
import type { Thunk } from '../reactive.js'
|
|
5
6
|
import type { RefreshReason } from '../store.js'
|
|
6
|
-
import type { UpdatePathDesc, UpdatePathDescNone } from '../update-path.js'
|
|
7
7
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
8
8
|
import type { DbContext, DbGraph, GetAtomResult, LiveQuery } from './base-class.js'
|
|
9
9
|
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
10
10
|
|
|
11
|
-
export const computed = <TResult,
|
|
11
|
+
export const computed = <TResult, TQueryInfo extends QueryInfo = QueryInfoNone>(
|
|
12
12
|
fn: (get: GetAtomResult) => TResult,
|
|
13
13
|
options?: {
|
|
14
14
|
label: string
|
|
15
15
|
dbGraph?: DbGraph
|
|
16
|
-
|
|
16
|
+
queryInfo?: TQueryInfo
|
|
17
17
|
},
|
|
18
|
-
): LiveQuery<TResult,
|
|
19
|
-
new LiveStoreJSQuery<TResult,
|
|
18
|
+
): LiveQuery<TResult, TQueryInfo> =>
|
|
19
|
+
new LiveStoreJSQuery<TResult, TQueryInfo>({
|
|
20
20
|
fn,
|
|
21
21
|
label: options?.label ?? fn.toString(),
|
|
22
22
|
dbGraph: options?.dbGraph,
|
|
23
|
-
|
|
23
|
+
queryInfo: options?.queryInfo,
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
export class LiveStoreJSQuery<
|
|
26
|
+
export class LiveStoreJSQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoNone> extends LiveStoreQueryBase<
|
|
27
27
|
TResult,
|
|
28
|
-
|
|
29
|
-
>
|
|
28
|
+
TQueryInfo
|
|
29
|
+
> {
|
|
30
30
|
_tag: 'js' = 'js'
|
|
31
31
|
|
|
32
32
|
/** A reactive thunk representing the query results */
|
|
@@ -36,7 +36,7 @@ export class LiveStoreJSQuery<
|
|
|
36
36
|
|
|
37
37
|
protected dbGraph: DbGraph
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
queryInfo: TQueryInfo
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* Currently only used for "nested destruction" of piped queries
|
|
@@ -51,14 +51,14 @@ export class LiveStoreJSQuery<
|
|
|
51
51
|
label,
|
|
52
52
|
onDestroy,
|
|
53
53
|
dbGraph,
|
|
54
|
-
|
|
54
|
+
queryInfo,
|
|
55
55
|
}: {
|
|
56
56
|
label: string
|
|
57
57
|
fn: (get: GetAtomResult) => TResult
|
|
58
58
|
/** Currently only used for "nested destruction" of piped queries */
|
|
59
59
|
onDestroy?: () => void
|
|
60
60
|
dbGraph?: DbGraph
|
|
61
|
-
|
|
61
|
+
queryInfo?: TQueryInfo
|
|
62
62
|
}) {
|
|
63
63
|
super()
|
|
64
64
|
|
|
@@ -66,7 +66,7 @@ export class LiveStoreJSQuery<
|
|
|
66
66
|
this.label = label
|
|
67
67
|
|
|
68
68
|
this.dbGraph = dbGraph ?? globalDbGraph
|
|
69
|
-
this.
|
|
69
|
+
this.queryInfo = queryInfo ?? ({ _tag: 'None' } as TQueryInfo)
|
|
70
70
|
|
|
71
71
|
const queryLabel = `${label}:results`
|
|
72
72
|
|
|
@@ -80,6 +80,8 @@ export class LiveStoreJSQuery<
|
|
|
80
80
|
|
|
81
81
|
const durationMs = getDurationMsFromSpan(span)
|
|
82
82
|
|
|
83
|
+
this.executionTimes.push(durationMs)
|
|
84
|
+
|
|
83
85
|
setDebugInfo({ _tag: 'js', label, query: fn.toString(), durationMs })
|
|
84
86
|
|
|
85
87
|
return res
|
|
@@ -3,8 +3,8 @@ import type { ReadableSpan } from '@opentelemetry/sdk-trace-base'
|
|
|
3
3
|
import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
4
4
|
import { describe, expect, it } from 'vitest'
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { makeTodoMvc, todos } from '../__tests__/react/fixture.js'
|
|
7
|
+
import { computed, ParseUtils, querySQL, rawSqlMutation, sql } from '../index.js'
|
|
8
8
|
|
|
9
9
|
/*
|
|
10
10
|
TODO write tests for:
|
|
@@ -40,10 +40,7 @@ describe('otel', () => {
|
|
|
40
40
|
const query = querySQL(`select * from todos`, { queriedTables: new Set(['todos']) })
|
|
41
41
|
expect(query.run()).toMatchInlineSnapshot('[]')
|
|
42
42
|
|
|
43
|
-
store.
|
|
44
|
-
sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);`,
|
|
45
|
-
writeTables: ['todos'],
|
|
46
|
-
})
|
|
43
|
+
store.mutate(rawSqlMutation({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
|
|
47
44
|
|
|
48
45
|
expect(query.run()).toMatchInlineSnapshot(`
|
|
49
46
|
[
|
|
@@ -91,28 +88,36 @@ describe('otel', () => {
|
|
|
91
88
|
},
|
|
92
89
|
},
|
|
93
90
|
{
|
|
94
|
-
"_name": "LiveStore:
|
|
91
|
+
"_name": "LiveStore:mutations",
|
|
95
92
|
"children": [
|
|
96
93
|
{
|
|
97
|
-
"_name": "LiveStore:
|
|
94
|
+
"_name": "LiveStore:mutate",
|
|
95
|
+
"attributes": {
|
|
96
|
+
"livestore.mutateLabel": "mutate",
|
|
97
|
+
},
|
|
98
98
|
"children": [
|
|
99
99
|
{
|
|
100
|
-
"_name": "LiveStore:
|
|
100
|
+
"_name": "LiveStore:processWrites",
|
|
101
101
|
"attributes": {
|
|
102
|
-
"livestore.
|
|
103
|
-
"livestore.args": "{
|
|
104
|
-
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);",
|
|
105
|
-
"writeTables": [
|
|
106
|
-
"todos"
|
|
107
|
-
]
|
|
108
|
-
}",
|
|
102
|
+
"livestore.mutateLabel": "mutate",
|
|
109
103
|
},
|
|
110
104
|
"children": [
|
|
111
105
|
{
|
|
112
|
-
"_name": "
|
|
106
|
+
"_name": "LiveStore:mutatetWithoutRefresh",
|
|
113
107
|
"attributes": {
|
|
114
|
-
"
|
|
108
|
+
"livestore.args": "{
|
|
109
|
+
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)"
|
|
110
|
+
}",
|
|
111
|
+
"livestore.mutation": "livestore.RawSql",
|
|
115
112
|
},
|
|
113
|
+
"children": [
|
|
114
|
+
{
|
|
115
|
+
"_name": "livestore.in-memory-db:execute",
|
|
116
|
+
"attributes": {
|
|
117
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
],
|
|
116
121
|
},
|
|
117
122
|
],
|
|
118
123
|
},
|
|
@@ -183,10 +188,7 @@ describe('otel', () => {
|
|
|
183
188
|
}
|
|
184
189
|
`)
|
|
185
190
|
|
|
186
|
-
store.
|
|
187
|
-
sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);`,
|
|
188
|
-
writeTables: ['todos'],
|
|
189
|
-
})
|
|
191
|
+
store.mutate(rawSqlMutation({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
|
|
190
192
|
|
|
191
193
|
expect(query.run()).toMatchInlineSnapshot(`
|
|
192
194
|
{
|
|
@@ -232,28 +234,36 @@ describe('otel', () => {
|
|
|
232
234
|
},
|
|
233
235
|
},
|
|
234
236
|
{
|
|
235
|
-
"_name": "LiveStore:
|
|
237
|
+
"_name": "LiveStore:mutations",
|
|
236
238
|
"children": [
|
|
237
239
|
{
|
|
238
|
-
"_name": "LiveStore:
|
|
240
|
+
"_name": "LiveStore:mutate",
|
|
241
|
+
"attributes": {
|
|
242
|
+
"livestore.mutateLabel": "mutate",
|
|
243
|
+
},
|
|
239
244
|
"children": [
|
|
240
245
|
{
|
|
241
|
-
"_name": "LiveStore:
|
|
246
|
+
"_name": "LiveStore:processWrites",
|
|
242
247
|
"attributes": {
|
|
243
|
-
"livestore.
|
|
244
|
-
"livestore.args": "{
|
|
245
|
-
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0);",
|
|
246
|
-
"writeTables": [
|
|
247
|
-
"todos"
|
|
248
|
-
]
|
|
249
|
-
}",
|
|
248
|
+
"livestore.mutateLabel": "mutate",
|
|
250
249
|
},
|
|
251
250
|
"children": [
|
|
252
251
|
{
|
|
253
|
-
"_name": "
|
|
252
|
+
"_name": "LiveStore:mutatetWithoutRefresh",
|
|
254
253
|
"attributes": {
|
|
255
|
-
"
|
|
254
|
+
"livestore.args": "{
|
|
255
|
+
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)"
|
|
256
|
+
}",
|
|
257
|
+
"livestore.mutation": "livestore.RawSql",
|
|
256
258
|
},
|
|
259
|
+
"children": [
|
|
260
|
+
{
|
|
261
|
+
"_name": "livestore.in-memory-db:execute",
|
|
262
|
+
"attributes": {
|
|
263
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
],
|
|
257
267
|
},
|
|
258
268
|
],
|
|
259
269
|
},
|