@livestore/livestore 0.0.13 → 0.0.14
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 +18 -21
- package/dist/.tsbuildinfo +1 -1
- package/dist/QueryCache.d.ts +1 -1
- package/dist/QueryCache.d.ts.map +1 -1
- package/dist/QueryCache.js.map +1 -1
- package/dist/__tests__/react/fixture.d.ts +5 -4
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +13 -14
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/__tests__/react/useComponentState.test.d.ts +2 -0
- package/dist/__tests__/react/useComponentState.test.d.ts.map +1 -0
- package/dist/__tests__/react/useComponentState.test.js +68 -0
- package/dist/__tests__/react/useComponentState.test.js.map +1 -0
- package/dist/__tests__/react/useLQuery.test.d.ts +2 -0
- package/dist/__tests__/react/useLQuery.test.d.ts.map +1 -0
- package/dist/__tests__/react/useLQuery.test.js +38 -0
- package/dist/__tests__/react/useLQuery.test.js.map +1 -0
- package/dist/__tests__/react/useLiveStoreComponent.test.js +4 -9
- package/dist/__tests__/react/useLiveStoreComponent.test.js.map +1 -1
- package/dist/__tests__/react/useQuery.test.d.ts +2 -0
- package/dist/__tests__/react/useQuery.test.d.ts.map +1 -0
- package/dist/__tests__/react/useQuery.test.js +33 -0
- package/dist/__tests__/react/useQuery.test.js.map +1 -0
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.d.ts +2 -0
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.d.ts.map +1 -0
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.js +38 -0
- package/dist/__tests__/react/utils/extractStackInfoFromStackTrace.test.js.map +1 -0
- package/dist/__tests__/reactive.test.js +168 -95
- package/dist/__tests__/reactive.test.js.map +1 -1
- package/dist/__tests__/reactiveQueries/sql.test.d.ts +2 -0
- package/dist/__tests__/reactiveQueries/sql.test.d.ts.map +1 -0
- package/dist/__tests__/reactiveQueries/sql.test.js +337 -0
- package/dist/__tests__/reactiveQueries/sql.test.js.map +1 -0
- package/dist/effect/LiveStore.d.ts +3 -9
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +11 -7
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/inMemoryDatabase.d.ts +17 -21
- package/dist/inMemoryDatabase.d.ts.map +1 -1
- package/dist/inMemoryDatabase.js +2 -9
- package/dist/inMemoryDatabase.js.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts +7 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +18 -13
- package/dist/migrations.js.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +1 -3
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js +13 -10
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +3 -3
- package/dist/react/index.js.map +1 -1
- package/dist/react/useComponentState.d.ts +50 -0
- package/dist/react/useComponentState.d.ts.map +1 -0
- package/dist/react/useComponentState.js +248 -0
- package/dist/react/useComponentState.js.map +1 -0
- package/dist/react/useGlobalQuery.d.ts +2 -2
- package/dist/react/useGlobalQuery.d.ts.map +1 -1
- package/dist/react/useGlobalQuery.js +5 -2
- package/dist/react/useGlobalQuery.js.map +1 -1
- package/dist/react/useGraphQL.d.ts +5 -3
- package/dist/react/useGraphQL.d.ts.map +1 -1
- package/dist/react/useGraphQL.js +27 -7
- package/dist/react/useGraphQL.js.map +1 -1
- package/dist/react/useLiveStoreComponent.d.ts +14 -14
- package/dist/react/useLiveStoreComponent.d.ts.map +1 -1
- package/dist/react/useLiveStoreComponent.js +151 -91
- package/dist/react/useLiveStoreComponent.js.map +1 -1
- package/dist/react/useQuery.d.ts +3 -0
- package/dist/react/useQuery.d.ts.map +1 -0
- package/dist/react/useQuery.js +42 -0
- package/dist/react/useQuery.js.map +1 -0
- package/dist/react/useTemporaryQuery.d.ts +8 -0
- package/dist/react/useTemporaryQuery.d.ts.map +1 -0
- package/dist/react/useTemporaryQuery.js +17 -0
- package/dist/react/useTemporaryQuery.js.map +1 -0
- package/dist/react/utils/extractNamesFromStackTrace.d.ts +3 -0
- package/dist/react/utils/extractNamesFromStackTrace.d.ts.map +1 -0
- package/dist/react/utils/extractNamesFromStackTrace.js +40 -0
- package/dist/react/utils/extractNamesFromStackTrace.js.map +1 -0
- package/dist/react/utils/extractStackInfoFromStackTrace.d.ts +7 -0
- package/dist/react/utils/extractStackInfoFromStackTrace.d.ts.map +1 -0
- package/dist/react/utils/extractStackInfoFromStackTrace.js +40 -0
- package/dist/react/utils/extractStackInfoFromStackTrace.js.map +1 -0
- package/dist/reactive.d.ts +42 -48
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +293 -186
- package/dist/reactive.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +28 -20
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +25 -17
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graph.d.ts +10 -0
- package/dist/reactiveQueries/graph.d.ts.map +1 -0
- package/dist/reactiveQueries/graph.js +6 -0
- package/dist/reactiveQueries/graph.js.map +1 -0
- package/dist/reactiveQueries/graphql.d.ts +35 -18
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +91 -10
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +17 -13
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js +31 -8
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +22 -18
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +81 -16
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/schema.d.ts +0 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +3 -6
- package/dist/schema.js.map +1 -1
- package/dist/storage/in-memory/index.d.ts +2 -2
- package/dist/storage/in-memory/index.d.ts.map +1 -1
- package/dist/storage/in-memory/index.js.map +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/tauri/index.d.ts +2 -2
- package/dist/storage/tauri/index.d.ts.map +1 -1
- package/dist/storage/tauri/index.js.map +1 -1
- package/dist/storage/web-worker/index.d.ts +4 -4
- package/dist/storage/web-worker/index.d.ts.map +1 -1
- package/dist/storage/web-worker/index.js +3 -5
- package/dist/storage/web-worker/index.js.map +1 -1
- package/dist/storage/web-worker/worker.js +2 -2
- package/dist/storage/web-worker/worker.js.map +1 -1
- package/dist/store.d.ts +19 -52
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +323 -266
- package/dist/store.js.map +1 -1
- package/dist/util.d.ts +3 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +2 -0
- package/dist/util.js.map +1 -1
- package/package.json +2 -1
- package/src/QueryCache.ts +1 -1
- package/src/__tests__/react/fixture.tsx +21 -16
- package/src/__tests__/react/{useLiveStoreComponent.test.tsx → useComponentState.test.tsx} +9 -20
- package/src/__tests__/react/useQuery.test.tsx +48 -0
- package/src/__tests__/react/utils/extractStackInfoFromStackTrace.test.ts +40 -0
- package/src/__tests__/reactive.test.ts +194 -142
- package/src/__tests__/reactiveQueries/sql.test.ts +372 -0
- package/src/effect/LiveStore.ts +14 -18
- package/src/inMemoryDatabase.ts +22 -30
- package/src/index.ts +8 -6
- package/src/migrations.ts +39 -21
- package/src/react/LiveStoreProvider.tsx +13 -16
- package/src/react/index.ts +4 -8
- package/src/react/{useLiveStoreComponent.ts → useComponentState.ts} +98 -230
- package/src/react/useQuery.ts +58 -0
- package/src/react/useTemporaryQuery.ts +21 -0
- package/src/react/utils/extractStackInfoFromStackTrace.ts +47 -0
- package/src/reactive.ts +386 -267
- package/src/reactiveQueries/base-class.ts +61 -39
- package/src/reactiveQueries/graph.ts +15 -0
- package/src/reactiveQueries/graphql.ts +147 -31
- package/src/reactiveQueries/js.ts +54 -21
- package/src/reactiveQueries/sql.ts +128 -37
- package/src/schema.ts +2 -5
- package/src/storage/in-memory/index.ts +2 -2
- package/src/storage/index.ts +2 -2
- package/src/storage/tauri/index.ts +2 -2
- package/src/storage/web-worker/index.ts +6 -8
- package/src/storage/web-worker/worker.ts +2 -2
- package/src/store.ts +394 -418
- package/src/util.ts +8 -2
- package/dist/backends/base.d.ts +0 -13
- package/dist/backends/base.d.ts.map +0 -1
- package/dist/backends/base.js +0 -53
- package/dist/backends/base.js.map +0 -1
- package/dist/backends/in-memory/index.d.ts +0 -22
- package/dist/backends/in-memory/index.d.ts.map +0 -1
- package/dist/backends/in-memory/index.js +0 -45
- package/dist/backends/in-memory/index.js.map +0 -1
- package/dist/backends/index.d.ts +0 -41
- package/dist/backends/index.d.ts.map +0 -1
- package/dist/backends/index.js +0 -16
- package/dist/backends/index.js.map +0 -1
- package/dist/backends/tauri/index.d.ts +0 -21
- package/dist/backends/tauri/index.d.ts.map +0 -1
- package/dist/backends/tauri/index.js +0 -48
- package/dist/backends/tauri/index.js.map +0 -1
- package/dist/backends/utils/idb.d.ts +0 -10
- package/dist/backends/utils/idb.d.ts.map +0 -1
- package/dist/backends/utils/idb.js +0 -58
- package/dist/backends/utils/idb.js.map +0 -1
- package/dist/backends/web-worker/index.d.ts +0 -26
- package/dist/backends/web-worker/index.d.ts.map +0 -1
- package/dist/backends/web-worker/index.js +0 -63
- package/dist/backends/web-worker/index.js.map +0 -1
- package/dist/backends/web-worker/worker.d.ts +0 -17
- package/dist/backends/web-worker/worker.d.ts.map +0 -1
- package/dist/backends/web-worker/worker.js +0 -139
- package/dist/backends/web-worker/worker.js.map +0 -1
- package/dist/storage/base.d.ts +0 -10
- package/dist/storage/base.d.ts.map +0 -1
- package/dist/storage/base.js +0 -14
- package/dist/storage/base.js.map +0 -1
- package/src/react/useGlobalQuery.ts +0 -37
- package/src/react/useGraphQL.ts +0 -112
package/dist/store.js
CHANGED
|
@@ -1,247 +1,294 @@
|
|
|
1
1
|
import { assertNever, makeNoopSpan, makeNoopTracer, shouldNeverHappen } from '@livestore/utils';
|
|
2
2
|
import { identity } from '@livestore/utils/effect';
|
|
3
3
|
import * as otel from '@opentelemetry/api';
|
|
4
|
-
import * as graphql from 'graphql';
|
|
5
|
-
import { uniqueId } from 'lodash-es';
|
|
6
|
-
import * as ReactDOM from 'react-dom';
|
|
7
|
-
import initSqlite3Wasm from 'sqlite-esm';
|
|
8
4
|
import { v4 as uuid } from 'uuid';
|
|
9
5
|
import { tableNameForComponentKey } from './componentKey.js';
|
|
10
6
|
import { InMemoryDatabase } from './inMemoryDatabase.js';
|
|
11
7
|
import { migrateDb } from './migrations.js';
|
|
12
8
|
import { getDurationMsFromSpan } from './otel.js';
|
|
13
|
-
import {
|
|
14
|
-
import { LiveStoreGraphQLQuery } from './reactiveQueries/graphql.js';
|
|
15
|
-
import { LiveStoreJSQuery } from './reactiveQueries/js.js';
|
|
16
|
-
import { LiveStoreSQLQuery } from './reactiveQueries/sql.js';
|
|
9
|
+
import { dbGraph } from './reactiveQueries/graph.js';
|
|
17
10
|
import { componentStateTables } from './schema.js';
|
|
18
|
-
import { isPromise, sql } from './util.js';
|
|
19
|
-
export const
|
|
20
|
-
const globalComponentKey = { _tag: 'singleton', componentName: '__global', id: 'singleton' };
|
|
11
|
+
import { isPromise, prepareBindValues, sql } from './util.js';
|
|
12
|
+
export const globalComponentKey = { _tag: 'singleton', componentName: '__global', id: 'singleton' };
|
|
21
13
|
export class Store {
|
|
22
|
-
constructor({ db, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext, }) {
|
|
14
|
+
constructor({ db, dbProxy, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext, }) {
|
|
23
15
|
/**
|
|
24
16
|
* Creates a reactive LiveStore SQL query
|
|
25
17
|
*
|
|
26
18
|
* NOTE The query is actually running (even if no one has subscribed to it yet) and will be kept up to date.
|
|
27
19
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
20
|
+
// querySQL = <TResult>(
|
|
21
|
+
// genQueryString: string | ((get: GetAtomResult) => string),
|
|
22
|
+
// {
|
|
23
|
+
// queriedTables,
|
|
24
|
+
// bindValues,
|
|
25
|
+
// componentKey,
|
|
26
|
+
// label,
|
|
27
|
+
// otelContext = otel.context.active(),
|
|
28
|
+
// }: {
|
|
29
|
+
// /**
|
|
30
|
+
// * List of tables that are queried in this query;
|
|
31
|
+
// * used to determine reactive dependencies.
|
|
32
|
+
// *
|
|
33
|
+
// * NOTE In the future we want to auto-generate this via parsing the query
|
|
34
|
+
// */
|
|
35
|
+
// queriedTables: string[]
|
|
36
|
+
// bindValues?: Bindable | undefined
|
|
37
|
+
// componentKey?: ComponentKey | undefined
|
|
38
|
+
// label?: string | undefined
|
|
39
|
+
// otelContext?: otel.Context
|
|
40
|
+
// },
|
|
41
|
+
// ): LiveStoreSQLQuery<TResult> =>
|
|
42
|
+
// this.otel.tracer.startActiveSpan(
|
|
43
|
+
// 'querySQL', // NOTE span name will be overridden further down
|
|
44
|
+
// { attributes: { label } },
|
|
45
|
+
// otelContext,
|
|
46
|
+
// (span) => {
|
|
47
|
+
// const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
48
|
+
// const queryString$ = this.graph.makeThunk(
|
|
49
|
+
// (get, addDebugInfo) => {
|
|
50
|
+
// if (typeof genQueryString === 'function') {
|
|
51
|
+
// const queryString = genQueryString(makeGetAtomResult(get))
|
|
52
|
+
// addDebugInfo({ _tag: 'js', label: `${label}:queryString`, query: queryString })
|
|
53
|
+
// return queryString
|
|
54
|
+
// } else {
|
|
55
|
+
// return genQueryString
|
|
56
|
+
// }
|
|
57
|
+
// },
|
|
58
|
+
// { label: `${label}:queryString`, meta: { liveStoreThunkType: 'sqlQueryString' } },
|
|
59
|
+
// otelContext,
|
|
60
|
+
// )
|
|
61
|
+
// label = label ?? queryString$.result
|
|
62
|
+
// span.updateName(`querySQL:${label}`)
|
|
63
|
+
// const queryLabel = `${label}:results` + (this.temporaryQueries ? ':temp' : '')
|
|
64
|
+
// const results$ = this.graph.makeThunk<ReadonlyArray<TResult>>(
|
|
65
|
+
// (get, addDebugInfo) =>
|
|
66
|
+
// this.otel.tracer.startActiveSpan(
|
|
67
|
+
// 'sql:', // NOTE span name will be overridden further down
|
|
68
|
+
// {},
|
|
69
|
+
// otelContext,
|
|
70
|
+
// (span) => {
|
|
71
|
+
// try {
|
|
72
|
+
// const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
73
|
+
// // Establish a reactive dependency on the tables used in the query
|
|
74
|
+
// for (const tableName of queriedTables) {
|
|
75
|
+
// const tableRef =
|
|
76
|
+
// this.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`)
|
|
77
|
+
// get(tableRef)
|
|
78
|
+
// }
|
|
79
|
+
// const sqlString = get(queryString$)
|
|
80
|
+
// span.setAttribute('sql.query', sqlString)
|
|
81
|
+
// span.updateName(`sql:${sqlString.slice(0, 50)}`)
|
|
82
|
+
// const results = this.inMemoryDB.select<TResult>(sqlString, {
|
|
83
|
+
// queriedTables,
|
|
84
|
+
// bindValues: bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
|
|
85
|
+
// otelContext,
|
|
86
|
+
// })
|
|
87
|
+
// span.setAttribute('sql.rowsCount', results.length)
|
|
88
|
+
// addDebugInfo({ _tag: 'sql', label: label ?? '', query: sqlString })
|
|
89
|
+
// return results
|
|
90
|
+
// } finally {
|
|
91
|
+
// span.end()
|
|
92
|
+
// }
|
|
93
|
+
// },
|
|
94
|
+
// ),
|
|
95
|
+
// { label: queryLabel },
|
|
96
|
+
// otelContext,
|
|
97
|
+
// )
|
|
98
|
+
// const query = new LiveStoreSQLQuery<TResult>({
|
|
99
|
+
// label,
|
|
100
|
+
// queryString$,
|
|
101
|
+
// results$,
|
|
102
|
+
// componentKey: componentKey ?? globalComponentKey,
|
|
103
|
+
// store: this,
|
|
104
|
+
// otelContext,
|
|
105
|
+
// })
|
|
106
|
+
// this.activeQueries.add(query)
|
|
107
|
+
// // TODO get rid of temporary query workaround
|
|
108
|
+
// if (this.temporaryQueries !== undefined) {
|
|
109
|
+
// this.temporaryQueries.add(query)
|
|
110
|
+
// }
|
|
111
|
+
// // NOTE we are not ending the span here but in the query `destroy` method
|
|
112
|
+
// return query
|
|
113
|
+
// },
|
|
114
|
+
// )
|
|
115
|
+
// queryJS = <TResult>(
|
|
116
|
+
// genResults: (get: GetAtomResult) => TResult,
|
|
117
|
+
// {
|
|
118
|
+
// componentKey = globalComponentKey,
|
|
119
|
+
// label = `js${uniqueId()}`,
|
|
120
|
+
// otelContext = otel.context.active(),
|
|
121
|
+
// }: { componentKey?: ComponentKey; label?: string; otelContext?: otel.Context },
|
|
122
|
+
// ): LiveStoreJSQuery<TResult> =>
|
|
123
|
+
// this.otel.tracer.startActiveSpan(`queryJS:${label}`, { attributes: { label } }, otelContext, (span) => {
|
|
124
|
+
// const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
125
|
+
// const queryLabel = `${label}:results` + (this.temporaryQueries ? ':temp' : '')
|
|
126
|
+
// const results$ = this.graph.makeThunk(
|
|
127
|
+
// (get, addDebugInfo) => {
|
|
128
|
+
// addDebugInfo({ _tag: 'js', label, query: genResults.toString() })
|
|
129
|
+
// return genResults(makeGetAtomResult(get))
|
|
130
|
+
// },
|
|
131
|
+
// { label: queryLabel, meta: { liveStoreThunkType: 'jsResults' } },
|
|
132
|
+
// otelContext,
|
|
133
|
+
// )
|
|
134
|
+
// // const query = new LiveStoreJSQuery<TResult>({
|
|
135
|
+
// // label,
|
|
136
|
+
// // results$,
|
|
137
|
+
// // componentKey,
|
|
138
|
+
// // store: this,
|
|
139
|
+
// // otelContext,
|
|
140
|
+
// // })
|
|
141
|
+
// this.activeQueries.add(query)
|
|
142
|
+
// // TODO get rid of temporary query workaround
|
|
143
|
+
// if (this.temporaryQueries !== undefined) {
|
|
144
|
+
// this.temporaryQueries.add(query)
|
|
145
|
+
// }
|
|
146
|
+
// // NOTE we are not ending the span here but in the query `destroy` method
|
|
147
|
+
// return query
|
|
148
|
+
// })
|
|
149
|
+
// queryGraphQL = <TResult extends Record<string, any>, TVariableValues extends Record<string, any>>(
|
|
150
|
+
// document: DocumentNode<TResult, TVariableValues>,
|
|
151
|
+
// genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues),
|
|
152
|
+
// {
|
|
153
|
+
// componentKey,
|
|
154
|
+
// label,
|
|
155
|
+
// otelContext = otel.context.active(),
|
|
156
|
+
// }: {
|
|
157
|
+
// componentKey: ComponentKey
|
|
158
|
+
// label?: string
|
|
159
|
+
// otelContext?: otel.Context
|
|
160
|
+
// },
|
|
161
|
+
// ): LiveStoreGraphQLQuery<TResult, TVariableValues, TGraphQLContext> =>
|
|
162
|
+
// this.otel.tracer.startActiveSpan(
|
|
163
|
+
// `queryGraphQL:`, // NOTE span name will be overridden further down
|
|
164
|
+
// {},
|
|
165
|
+
// otelContext,
|
|
166
|
+
// (span) => {
|
|
167
|
+
// const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
168
|
+
// if (this.graphQLContext === undefined) {
|
|
169
|
+
// return shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context")
|
|
170
|
+
// }
|
|
171
|
+
// const labelWithDefault = label ?? graphql.getOperationAST(document)?.name?.value ?? 'graphql'
|
|
172
|
+
// span.updateName(`queryGraphQL:${labelWithDefault}`)
|
|
173
|
+
// const variableValues$ = this.graph.makeThunk(
|
|
174
|
+
// (get) => {
|
|
175
|
+
// if (typeof genVariableValues === 'function') {
|
|
176
|
+
// return genVariableValues(makeGetAtomResult(get))
|
|
177
|
+
// } else {
|
|
178
|
+
// return genVariableValues
|
|
179
|
+
// }
|
|
180
|
+
// },
|
|
181
|
+
// { label: `${labelWithDefault}:variableValues`, meta: { liveStoreThunkType: 'graphqlVariableValues' } },
|
|
182
|
+
// // otelContext,
|
|
183
|
+
// )
|
|
184
|
+
// const resultsLabel = `${labelWithDefault}:results` + (this.temporaryQueries ? ':temp' : '')
|
|
185
|
+
// const results$ = this.graph.makeThunk<TResult>(
|
|
186
|
+
// (get, addDebugInfo) => {
|
|
187
|
+
// const variableValues = get(variableValues$)
|
|
188
|
+
// const { result, queriedTables } = this.queryGraphQLOnce(document, variableValues, otelContext)
|
|
189
|
+
// // Add dependencies on any tables that were used
|
|
190
|
+
// for (const tableName of queriedTables) {
|
|
191
|
+
// const tableRef = this.tableRefs[tableName]
|
|
192
|
+
// assertNever(tableRef !== undefined, `No table ref found for ${tableName}`)
|
|
193
|
+
// get(tableRef!)
|
|
194
|
+
// }
|
|
195
|
+
// addDebugInfo({ _tag: 'graphql', label: resultsLabel, query: graphql.print(document) })
|
|
196
|
+
// return result
|
|
197
|
+
// },
|
|
198
|
+
// { label: resultsLabel, meta: { liveStoreThunkType: 'graphqlResults' } },
|
|
199
|
+
// // otelContext,
|
|
200
|
+
// )
|
|
201
|
+
// const query = new LiveStoreGraphQLQuery({
|
|
202
|
+
// document,
|
|
203
|
+
// context: this.graphQLContext,
|
|
204
|
+
// results$,
|
|
205
|
+
// componentKey,
|
|
206
|
+
// label: labelWithDefault,
|
|
207
|
+
// store: this,
|
|
208
|
+
// otelContext,
|
|
209
|
+
// })
|
|
210
|
+
// this.activeQueries.add(query)
|
|
211
|
+
// // TODO get rid of temporary query workaround
|
|
212
|
+
// if (this.temporaryQueries !== undefined) {
|
|
213
|
+
// this.temporaryQueries.add(query)
|
|
214
|
+
// }
|
|
215
|
+
// // NOTE we are not ending the span here but in the query `destroy` method
|
|
216
|
+
// return query
|
|
217
|
+
// },
|
|
218
|
+
// )
|
|
219
|
+
// queryGraphQLOnce = <TResult extends Record<string, any>, TVariableValues extends Record<string, any>>(
|
|
220
|
+
// document: DocumentNode<TResult, TVariableValues>,
|
|
221
|
+
// variableValues: TVariableValues,
|
|
222
|
+
// otelContext: otel.Context = this.otel.queriesSpanContext,
|
|
223
|
+
// ): { result: TResult; queriedTables: string[] } => {
|
|
224
|
+
// const schema =
|
|
225
|
+
// this.graphQLSchema ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL schema")
|
|
226
|
+
// const context =
|
|
227
|
+
// this.graphQLContext ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context")
|
|
228
|
+
// const tracer = this.otel.tracer
|
|
229
|
+
// const operationName = graphql.getOperationAST(document)?.name?.value
|
|
230
|
+
// return tracer.startActiveSpan(`executeGraphQLQuery: ${operationName}`, {}, otelContext, (span) => {
|
|
231
|
+
// try {
|
|
232
|
+
// span.setAttribute('graphql.variables', JSON.stringify(variableValues))
|
|
233
|
+
// span.setAttribute('graphql.query', graphql.print(document))
|
|
234
|
+
// context.queriedTables.clear()
|
|
235
|
+
// context.otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
236
|
+
// const res = graphql.executeSync({
|
|
237
|
+
// document,
|
|
238
|
+
// contextValue: context,
|
|
239
|
+
// schema: schema,
|
|
240
|
+
// variableValues,
|
|
241
|
+
// })
|
|
242
|
+
// // TODO track number of nested SQL queries via Otel + debug info
|
|
243
|
+
// if (res.errors) {
|
|
244
|
+
// span.setStatus({ code: otel.SpanStatusCode.ERROR, message: 'GraphQL error' })
|
|
245
|
+
// span.setAttribute('graphql.error', res.errors.join('\n'))
|
|
246
|
+
// span.setAttribute('graphql.error-detail', JSON.stringify(res.errors))
|
|
247
|
+
// console.error(`graphql error (${operationName})`, res.errors)
|
|
248
|
+
// }
|
|
249
|
+
// return { result: res.data as unknown as TResult, queriedTables: Array.from(context.queriedTables.values()) }
|
|
250
|
+
// } finally {
|
|
251
|
+
// span.end()
|
|
252
|
+
// }
|
|
253
|
+
// })
|
|
254
|
+
// }
|
|
168
255
|
/**
|
|
169
256
|
* Subscribe to the results of a query
|
|
170
257
|
* Returns a function to cancel the subscription.
|
|
171
258
|
*/
|
|
172
|
-
this.subscribe = (query, onNewValue, onSubsubscribe, options) => this.otel.tracer.startActiveSpan(`LiveStore.subscribe`, { attributes: { label: options?.label } },
|
|
259
|
+
this.subscribe = (query, onNewValue, onSubsubscribe, options) => this.otel.tracer.startActiveSpan(`LiveStore.subscribe`, { attributes: { label: options?.label } }, options?.otelContext ?? this.otel.queriesSpanContext, (span) => {
|
|
173
260
|
const otelContext = otel.trace.setSpan(otel.context.active(), span);
|
|
174
|
-
const effect = this.graph.makeEffect((get) => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const subscriptionKey = uuid()
|
|
261
|
+
const effect = this.graph.makeEffect((get) => onNewValue(get(query.results$)), {
|
|
262
|
+
label: `subscribe:${options?.label}`,
|
|
263
|
+
});
|
|
264
|
+
effect.doEffect(otelContext);
|
|
265
|
+
// const subscriptionKey = uuid()
|
|
179
266
|
const unsubscribe = () => {
|
|
180
267
|
try {
|
|
181
268
|
this.graph.destroy(effect);
|
|
182
|
-
|
|
269
|
+
this.activeQueries.delete(query);
|
|
270
|
+
// query.activeSubscriptions.delete(subscriptionKey)
|
|
183
271
|
onSubsubscribe?.();
|
|
184
272
|
}
|
|
185
273
|
finally {
|
|
186
274
|
span.end();
|
|
187
275
|
}
|
|
188
276
|
};
|
|
189
|
-
|
|
277
|
+
this.activeQueries.add(query);
|
|
278
|
+
// query.activeSubscriptions.set(subscriptionKey, unsubscribe)
|
|
190
279
|
return unsubscribe;
|
|
191
280
|
});
|
|
192
|
-
/**
|
|
193
|
-
* Any queries created in the callback will be destroyed when the callback is complete.
|
|
194
|
-
* Useful for temporarily creating reactive queries, which is an idempotent operation
|
|
195
|
-
* that can be safely called inside a React useMemo hook.
|
|
196
|
-
*/
|
|
197
|
-
this.inTempQueryContext = (callback) => {
|
|
198
|
-
this.temporaryQueries = new Set();
|
|
199
|
-
// TODO: consider errors / try/finally here?
|
|
200
|
-
const result = callback();
|
|
201
|
-
for (const query of this.temporaryQueries) {
|
|
202
|
-
this.destroyQuery(query);
|
|
203
|
-
}
|
|
204
|
-
this.temporaryQueries = undefined;
|
|
205
|
-
return result;
|
|
206
|
-
};
|
|
207
281
|
/**
|
|
208
282
|
* Destroys the entire store, including all queries and subscriptions.
|
|
209
283
|
*
|
|
210
284
|
* Currently only used when shutting down the app for debugging purposes (e.g. to close Otel spans).
|
|
211
285
|
*/
|
|
212
286
|
this.destroy = () => {
|
|
213
|
-
for (const query of this.activeQueries) {
|
|
214
|
-
this.destroyQuery(query);
|
|
215
|
-
}
|
|
216
287
|
Object.values(this.tableRefs).forEach((tableRef) => this.graph.destroy(tableRef));
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const queriesSpan = otel.trace.getSpan(this.otel.queriesSpanContext);
|
|
220
|
-
queriesSpan.end();
|
|
288
|
+
otel.trace.getSpan(this.otel.applyEventsSpanContext).end();
|
|
289
|
+
otel.trace.getSpan(this.otel.queriesSpanContext).end();
|
|
221
290
|
// TODO destroy active subscriptions
|
|
222
291
|
};
|
|
223
|
-
this.destroyQuery = (query) => {
|
|
224
|
-
if (query._tag === 'sql') {
|
|
225
|
-
// results are downstream of query string, so will automatically be destroyed together
|
|
226
|
-
this.graph.destroy(query.queryString$);
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
this.graph.destroy(query.results$);
|
|
230
|
-
}
|
|
231
|
-
this.activeQueries.delete(query);
|
|
232
|
-
query.destroy();
|
|
233
|
-
};
|
|
234
|
-
/**
|
|
235
|
-
* Clean up queries and downstream subscriptions associated with a component.
|
|
236
|
-
* This is critical to avoid memory leaks.
|
|
237
|
-
*/
|
|
238
|
-
this.unmountComponent = (componentKey) => {
|
|
239
|
-
for (const query of this.activeQueries) {
|
|
240
|
-
if (query.componentKey === componentKey) {
|
|
241
|
-
this.destroyQuery(query);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
292
|
/* Apply a single write event to the store, and refresh all queries in response */
|
|
246
293
|
this.applyEvent = (eventType, args = {}, options) => {
|
|
247
294
|
const skipRefresh = options?.skipRefresh ?? false;
|
|
@@ -258,16 +305,23 @@ export class Store {
|
|
|
258
305
|
assertNever(tableRef !== undefined, `No table ref found for ${tableName}`);
|
|
259
306
|
tablesToUpdate.push([tableRef, null]);
|
|
260
307
|
}
|
|
308
|
+
const debugRefreshReason = {
|
|
309
|
+
_tag: 'applyEvent',
|
|
310
|
+
event: { type: eventType, args },
|
|
311
|
+
writeTables: [...writeTables],
|
|
312
|
+
};
|
|
261
313
|
// Update all table refs together in a batch, to only trigger one reactive update
|
|
262
|
-
this.graph.setRefs(tablesToUpdate, {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
},
|
|
270
|
-
|
|
314
|
+
this.graph.setRefs(tablesToUpdate, { debugRefreshReason, otelContext });
|
|
315
|
+
if (skipRefresh === false) {
|
|
316
|
+
// TODO update the graph
|
|
317
|
+
// this.graph.refresh(
|
|
318
|
+
// {
|
|
319
|
+
// otelHint: 'applyEvents',
|
|
320
|
+
// debugRefreshReason,
|
|
321
|
+
// },
|
|
322
|
+
// otelContext,
|
|
323
|
+
// )
|
|
324
|
+
}
|
|
271
325
|
}
|
|
272
326
|
catch (e) {
|
|
273
327
|
span.setStatus({ code: otel.SpanStatusCode.ERROR, message: e.toString() });
|
|
@@ -329,16 +383,17 @@ export class Store {
|
|
|
329
383
|
assertNever(tableRef !== undefined, `No table ref found for ${tableName}`);
|
|
330
384
|
tablesToUpdate.push([tableRef, null]);
|
|
331
385
|
}
|
|
386
|
+
const debugRefreshReason = {
|
|
387
|
+
_tag: 'applyEvents',
|
|
388
|
+
events: [...events].map((e) => ({ type: e.eventType, args: e.args })),
|
|
389
|
+
writeTables: [...writeTables],
|
|
390
|
+
};
|
|
332
391
|
// Update all table refs together in a batch, to only trigger one reactive update
|
|
333
|
-
this.graph.setRefs(tablesToUpdate, {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
debugRefreshReason:
|
|
337
|
-
|
|
338
|
-
events: [...events].map((e) => ({ type: e.eventType, args: e.args })),
|
|
339
|
-
writeTables: [...writeTables],
|
|
340
|
-
},
|
|
341
|
-
}, otelContext);
|
|
392
|
+
this.graph.setRefs(tablesToUpdate, { debugRefreshReason, otelContext });
|
|
393
|
+
if (skipRefresh === false) {
|
|
394
|
+
// TODO update the graph
|
|
395
|
+
// this.graph.refresh({ debugRefreshReason, otelHint: 'applyEvents' }, otelContext)
|
|
396
|
+
}
|
|
342
397
|
}
|
|
343
398
|
catch (e) {
|
|
344
399
|
span.setStatus({ code: otel.SpanStatusCode.ERROR, message: e.toString() });
|
|
@@ -356,8 +411,9 @@ export class Store {
|
|
|
356
411
|
this.manualRefresh = (options) => {
|
|
357
412
|
const { label } = options ?? {};
|
|
358
413
|
this.otel.tracer.startActiveSpan('LiveStore:manualRefresh', { attributes: { 'livestore.manualRefreshLabel': label } }, this.otel.applyEventsSpanContext, (span) => {
|
|
359
|
-
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
360
|
-
|
|
414
|
+
// const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
415
|
+
// TODO update the graph
|
|
416
|
+
// this.graph.refresh({ otelHint: 'manualRefresh', debugRefreshReason: { _tag: 'manualRefresh' } }, otelContext)
|
|
361
417
|
span.end();
|
|
362
418
|
});
|
|
363
419
|
};
|
|
@@ -404,13 +460,13 @@ export class Store {
|
|
|
404
460
|
// Synchronously apply the event to the in-memory database
|
|
405
461
|
// const { durationMs } = this.inMemoryDB.applyEvent(eventWithId, actionDefinition, otelContext)
|
|
406
462
|
const { statement, bindValues } = eventToSql(eventWithId, actionDefinition);
|
|
407
|
-
const { durationMs } = this.inMemoryDB.execute(statement.sql, bindValues, statement.writeTables, {
|
|
463
|
+
const { durationMs } = this.inMemoryDB.execute(statement.sql, prepareBindValues(bindValues, statement.sql), statement.writeTables, {
|
|
408
464
|
otelContext,
|
|
409
465
|
});
|
|
410
466
|
// Asynchronously apply the event to a persistent storage (we're not awaiting this promise here)
|
|
411
467
|
if (this.storage !== undefined) {
|
|
412
468
|
// this.storage.applyEvent(eventWithId, actionDefinition, span)
|
|
413
|
-
this.storage.execute(statement.sql, bindValues, span);
|
|
469
|
+
this.storage.execute(statement.sql, prepareBindValues(bindValues, statement.sql), span);
|
|
414
470
|
}
|
|
415
471
|
// Uncomment to print a list of queries currently registered on the store
|
|
416
472
|
// console.log(JSON.parse(JSON.stringify([...this.queries].map((q) => `${labelForKey(q.componentKey)}/${q.label}`))))
|
|
@@ -427,20 +483,21 @@ export class Store {
|
|
|
427
483
|
* This should only be used for framework-internal purposes;
|
|
428
484
|
* all app writes should go through applyEvent.
|
|
429
485
|
*/
|
|
430
|
-
this.execute =
|
|
431
|
-
this.inMemoryDB.execute(query, params, writeTables);
|
|
486
|
+
this.execute = (query, params = {}, writeTables) => {
|
|
487
|
+
this.inMemoryDB.execute(query, prepareBindValues(params, query), writeTables);
|
|
432
488
|
if (this.storage !== undefined) {
|
|
433
489
|
const parentSpan = otel.trace.getSpan(otel.context.active());
|
|
434
|
-
this.storage.execute(query, params, parentSpan);
|
|
490
|
+
this.storage.execute(query, prepareBindValues(params, query), parentSpan);
|
|
435
491
|
}
|
|
436
492
|
};
|
|
437
493
|
this.inMemoryDB = db;
|
|
438
|
-
this.
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
494
|
+
this._proxyDb = dbProxy;
|
|
495
|
+
// this.graph = new ReactiveGraph({
|
|
496
|
+
// // TODO move this into React module
|
|
497
|
+
// // Do all our updates inside a single React setState batch to avoid multiple UI re-renders
|
|
498
|
+
// effectsWrapper: (run) => ReactDOM.unstable_batchedUpdates(() => run()),
|
|
499
|
+
// otelTracer,
|
|
500
|
+
// })
|
|
444
501
|
this.schema = schema;
|
|
445
502
|
// TODO generalize the `tableRefs` concept to allow finer-grained refs
|
|
446
503
|
this.tableRefs = {};
|
|
@@ -450,6 +507,8 @@ export class Store {
|
|
|
450
507
|
const otelApplyEventsSpanContext = otel.trace.setSpan(otel.context.active(), applyEventsSpan);
|
|
451
508
|
const queriesSpan = otelTracer.startSpan('LiveStore:queries', {}, otelRootSpanContext);
|
|
452
509
|
const otelQueriesSpanContext = otel.trace.setSpan(otel.context.active(), queriesSpan);
|
|
510
|
+
this.graph = dbGraph;
|
|
511
|
+
this.graph.context = { store: this, otelTracer, rootOtelContext: otelQueriesSpanContext };
|
|
453
512
|
this.otel = {
|
|
454
513
|
tracer: otelTracer,
|
|
455
514
|
applyEventsSpanContext: otelApplyEventsSpanContext,
|
|
@@ -485,40 +544,29 @@ Store.createStore = (storeOptions, parentSpan) => {
|
|
|
485
544
|
});
|
|
486
545
|
};
|
|
487
546
|
/** Create a new LiveStore Store */
|
|
488
|
-
export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTracer = makeNoopTracer(), otelRootSpanContext = otel.context.active(), boot, }) => {
|
|
547
|
+
export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTracer = makeNoopTracer(), otelRootSpanContext = otel.context.active(), boot, sqlite3, }) => {
|
|
489
548
|
return otelTracer.startActiveSpan('createStore', {}, otelRootSpanContext, async (span) => {
|
|
490
549
|
try {
|
|
491
550
|
const otelContext = otel.trace.setSpan(otel.context.active(), span);
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
const persistedData = await otelTracer.startActiveSpan('storage:getPersistedData', {}, otelContext, async (span) => {
|
|
504
|
-
try {
|
|
505
|
-
return await storage.getPersistedData(span);
|
|
506
|
-
}
|
|
507
|
-
finally {
|
|
508
|
-
span.end();
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
return { storage, persistedData };
|
|
512
|
-
};
|
|
513
|
-
const loadSqlite3 = () => initSqlite3Wasm({
|
|
514
|
-
// Required to load the wasm binary asynchronously. Of course, you can host it wherever you want
|
|
515
|
-
// You can omit locateFile completely when running in node
|
|
516
|
-
// locateFile: () => `/sql-wasm.wasm`,
|
|
517
|
-
print: (message) => console.log(`[livestore sqlite] ${message}`),
|
|
518
|
-
printErr: (message) => console.error(`[livestore sqlite] ${message}`),
|
|
551
|
+
const storage = await otelTracer.startActiveSpan('storage:load', {}, otelContext, async (span) => {
|
|
552
|
+
try {
|
|
553
|
+
const init = await loadStorage();
|
|
554
|
+
const parentSpan = otel.trace.getSpan(otel.context.active()) ?? makeNoopSpan();
|
|
555
|
+
return init({ otelTracer, parentSpan });
|
|
556
|
+
}
|
|
557
|
+
finally {
|
|
558
|
+
span.end();
|
|
559
|
+
}
|
|
519
560
|
});
|
|
520
|
-
const
|
|
521
|
-
|
|
561
|
+
const persistedData = await otelTracer.startActiveSpan('storage:getPersistedData', {}, otelContext, async (span) => {
|
|
562
|
+
try {
|
|
563
|
+
return await storage.getPersistedData(span);
|
|
564
|
+
}
|
|
565
|
+
finally {
|
|
566
|
+
span.end();
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
const db = InMemoryDatabase.load({ data: persistedData, otelTracer, otelRootSpanContext, sqlite3 });
|
|
522
570
|
// Proxy to `db` that also mirrors `execute` calls to `storage`
|
|
523
571
|
const dbProxy = new Proxy(db, {
|
|
524
572
|
get: (db, prop, receiver) => {
|
|
@@ -529,6 +577,15 @@ export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTra
|
|
|
529
577
|
};
|
|
530
578
|
return execute;
|
|
531
579
|
}
|
|
580
|
+
else if (prop === 'select') {
|
|
581
|
+
// NOTE we're even proxying `select` calls here as some apps (e.g. Overtone) currently rely on this
|
|
582
|
+
// TODO remove this once we've migrated all apps to use `execute` instead of `select`
|
|
583
|
+
const select = (query, options = {}) => {
|
|
584
|
+
storage.execute(query, options.bindValues);
|
|
585
|
+
return db.select(query, options);
|
|
586
|
+
};
|
|
587
|
+
return select;
|
|
588
|
+
}
|
|
532
589
|
else {
|
|
533
590
|
return Reflect.get(db, prop, receiver);
|
|
534
591
|
}
|
|
@@ -553,7 +610,7 @@ export const createStore = async ({ schema, loadStorage, graphQLOptions, otelTra
|
|
|
553
610
|
// TODO: we can't apply the schema at this point, we've already loaded persisted data!
|
|
554
611
|
// Think about what to do about this case.
|
|
555
612
|
// await applySchema(db, schema)
|
|
556
|
-
return Store.createStore({ db, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext }, span);
|
|
613
|
+
return Store.createStore({ db, dbProxy, schema, storage, graphQLOptions, otelTracer, otelRootSpanContext }, span);
|
|
557
614
|
}
|
|
558
615
|
finally {
|
|
559
616
|
span.end();
|