@livestore/livestore 0.0.21 → 0.0.22
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 +14 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +0 -2
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/__tests__/react/useQuery.test.js +1 -1
- package/dist/__tests__/react/useQuery.test.js.map +1 -1
- package/dist/__tests__/react/utils/stack-info.test.d.ts +2 -0
- package/dist/__tests__/react/utils/stack-info.test.d.ts.map +1 -0
- package/dist/__tests__/react/utils/stack-info.test.js +43 -0
- package/dist/__tests__/react/utils/stack-info.test.js.map +1 -0
- package/dist/__tests__/reactive.test.js +13 -1
- package/dist/__tests__/reactive.test.js.map +1 -1
- package/dist/__tests__/reactiveQueries/sql.test.js +3 -3
- package/dist/__tests__/reactiveQueries/sql.test.js.map +1 -1
- package/dist/inMemoryDatabase.d.ts +2 -1
- package/dist/inMemoryDatabase.d.ts.map +1 -1
- package/dist/inMemoryDatabase.js +3 -2
- package/dist/inMemoryDatabase.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/useComponentState.d.ts.map +1 -1
- package/dist/react/useComponentState.js +19 -27
- package/dist/react/useComponentState.js.map +1 -1
- package/dist/react/useQuery.d.ts.map +1 -1
- package/dist/react/useQuery.js +46 -26
- package/dist/react/useQuery.js.map +1 -1
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/react/useTemporaryQuery.js +2 -0
- package/dist/react/useTemporaryQuery.js.map +1 -1
- package/dist/react/utils/stack-info.d.ts +11 -0
- package/dist/react/utils/stack-info.d.ts.map +1 -0
- package/dist/react/utils/stack-info.js +49 -0
- package/dist/react/utils/stack-info.js.map +1 -0
- package/dist/reactive.d.ts +33 -43
- package/dist/reactive.d.ts.map +1 -1
- package/dist/reactive.js +66 -255
- package/dist/reactive.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +15 -13
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +5 -8
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +4 -3
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +29 -34
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +2 -1
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js +8 -9
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +11 -5
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +31 -34
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/store.d.ts +26 -12
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +41 -255
- package/dist/store.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/react/fixture.tsx +0 -3
- package/src/__tests__/react/useQuery.test.tsx +1 -1
- package/src/__tests__/react/utils/{extractStackInfoFromStackTrace.test.ts → stack-info.test.ts} +25 -20
- package/src/__tests__/reactive.test.ts +20 -1
- package/src/__tests__/reactiveQueries/sql.test.ts +3 -3
- package/src/inMemoryDatabase.ts +9 -6
- package/src/react/index.ts +1 -0
- package/src/react/useComponentState.ts +25 -30
- package/src/react/useQuery.ts +66 -34
- package/src/react/useTemporaryQuery.ts +2 -0
- package/src/react/utils/{extractStackInfoFromStackTrace.ts → stack-info.ts} +21 -5
- package/src/reactive.ts +148 -339
- package/src/reactiveQueries/base-class.ts +23 -22
- package/src/reactiveQueries/graphql.ts +34 -36
- package/src/reactiveQueries/js.ts +14 -10
- package/src/reactiveQueries/sql.ts +55 -48
- package/src/store.ts +70 -305
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type * as otel from '@opentelemetry/api'
|
|
2
2
|
|
|
3
|
-
import type { StackInfo } from '../react/utils/
|
|
4
|
-
import type { Atom, GetAtom, Thunk } from '../reactive.js'
|
|
5
|
-
import {
|
|
3
|
+
import type { StackInfo } from '../react/utils/stack-info.js'
|
|
4
|
+
import type { Atom, GetAtom, RefreshReasonWithGenericReasons, Thunk } from '../reactive.js'
|
|
5
|
+
import type { RefreshReason } from '../store.js'
|
|
6
|
+
import { type DbContext, dbGraph } from './graph.js'
|
|
6
7
|
import type { LiveStoreJSQuery } from './js.js'
|
|
7
8
|
|
|
8
9
|
export type UnsubscribeQuery = () => void
|
|
@@ -13,19 +14,15 @@ export interface ILiveStoreQuery<TResult> {
|
|
|
13
14
|
id: number
|
|
14
15
|
|
|
15
16
|
/** A reactive thunk representing the query results */
|
|
16
|
-
results$: Thunk<TResult, DbContext>
|
|
17
|
+
results$: Thunk<TResult, DbContext, RefreshReason>
|
|
17
18
|
|
|
18
19
|
label: string
|
|
19
20
|
|
|
20
|
-
run: (otelContext?: otel.Context) => TResult
|
|
21
|
+
run: (otelContext?: otel.Context, debugRefreshReason?: RefreshReasonWithGenericReasons<RefreshReason>) => TResult
|
|
21
22
|
|
|
22
23
|
destroy(): void
|
|
23
24
|
|
|
24
|
-
activeSubscriptions: Set<
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type SubscriberInfo = {
|
|
28
|
-
stack: StackInfo[]
|
|
25
|
+
activeSubscriptions: Set<StackInfo>
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
export abstract class LiveStoreQueryBase<TResult> implements ILiveStoreQuery<TResult> {
|
|
@@ -34,9 +31,9 @@ export abstract class LiveStoreQueryBase<TResult> implements ILiveStoreQuery<TRe
|
|
|
34
31
|
/** Human-readable label for the query for debugging */
|
|
35
32
|
abstract label: string
|
|
36
33
|
|
|
37
|
-
abstract results$: Thunk<TResult, DbContext>
|
|
34
|
+
abstract results$: Thunk<TResult, DbContext, RefreshReason>
|
|
38
35
|
|
|
39
|
-
activeSubscriptions: Set<
|
|
36
|
+
activeSubscriptions: Set<StackInfo> = new Set()
|
|
40
37
|
|
|
41
38
|
get runs() {
|
|
42
39
|
return this.results$.recomputations
|
|
@@ -44,22 +41,26 @@ export abstract class LiveStoreQueryBase<TResult> implements ILiveStoreQuery<TRe
|
|
|
44
41
|
|
|
45
42
|
abstract destroy: () => void
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// onSubsubscribe?: () => void,
|
|
50
|
-
// options?: { label?: string } | undefined,
|
|
51
|
-
// ): (() => void) => this.store.subscribe(this as any, onNewValue as any, onSubsubscribe, options)
|
|
44
|
+
run = (otelContext?: otel.Context, debugRefreshReason?: RefreshReasonWithGenericReasons<RefreshReason>): TResult =>
|
|
45
|
+
this.results$.computeResult(otelContext, debugRefreshReason)
|
|
52
46
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
runAndDestroy = (
|
|
48
|
+
otelContext?: otel.Context,
|
|
49
|
+
debugRefreshReason?: RefreshReasonWithGenericReasons<RefreshReason>,
|
|
50
|
+
): TResult => {
|
|
51
|
+
const result = this.run(otelContext, debugRefreshReason)
|
|
57
52
|
this.destroy()
|
|
58
53
|
return result
|
|
59
54
|
}
|
|
55
|
+
|
|
56
|
+
subscribe = (
|
|
57
|
+
onNewValue: (value: TResult) => void,
|
|
58
|
+
onUnsubsubscribe?: () => void,
|
|
59
|
+
options?: { label?: string; otelContext?: otel.Context } | undefined,
|
|
60
|
+
): (() => void) => dbGraph.context!.store.subscribe(this, onNewValue, onUnsubsubscribe, options)
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
export type GetAtomResult = <T>(atom: Atom<T, any> | LiveStoreJSQuery<T>) => T
|
|
63
|
+
export type GetAtomResult = <T>(atom: Atom<T, any, RefreshReason> | LiveStoreJSQuery<T>) => T
|
|
63
64
|
|
|
64
65
|
export const makeGetAtomResult = (get: GetAtom, otelContext: otel.Context) => {
|
|
65
66
|
const getAtom: GetAtomResult = (atom) => {
|
|
@@ -3,8 +3,9 @@ import { assertNever, shouldNeverHappen } from '@livestore/utils'
|
|
|
3
3
|
import * as otel from '@opentelemetry/api'
|
|
4
4
|
import * as graphql from 'graphql'
|
|
5
5
|
|
|
6
|
+
import { getDurationMsFromSpan } from '../otel.js'
|
|
6
7
|
import type { Thunk } from '../reactive.js'
|
|
7
|
-
import {
|
|
8
|
+
import type { BaseGraphQLContext, RefreshReason, Store } from '../store.js'
|
|
8
9
|
import { type GetAtomResult, LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
9
10
|
import { type DbContext, dbGraph } from './graph.js'
|
|
10
11
|
import { LiveStoreJSQuery } from './js.js'
|
|
@@ -26,16 +27,16 @@ export class LiveStoreGraphQLQuery<
|
|
|
26
27
|
document: DocumentNode<TResult, TVariableValues>
|
|
27
28
|
|
|
28
29
|
/** A reactive thunk representing the query results */
|
|
29
|
-
results$: Thunk<TResult, DbContext>
|
|
30
|
+
results$: Thunk<TResult, DbContext, RefreshReason>
|
|
30
31
|
|
|
31
|
-
variableValues$: Thunk<TVariableValues, DbContext>
|
|
32
|
+
variableValues$: Thunk<TVariableValues, DbContext, RefreshReason>
|
|
32
33
|
|
|
33
34
|
label: string
|
|
34
35
|
|
|
35
36
|
constructor({
|
|
36
37
|
document,
|
|
37
38
|
label,
|
|
38
|
-
genVariableValues,
|
|
39
|
+
genVariableValues,
|
|
39
40
|
}: {
|
|
40
41
|
document: DocumentNode<TResult, TVariableValues>
|
|
41
42
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues)
|
|
@@ -48,13 +49,9 @@ export class LiveStoreGraphQLQuery<
|
|
|
48
49
|
this.label = labelWithDefault
|
|
49
50
|
this.document = document
|
|
50
51
|
|
|
51
|
-
// if (context === undefined) {
|
|
52
|
-
// return shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL context")
|
|
53
|
-
// }
|
|
54
|
-
|
|
55
52
|
// TODO don't even create a thunk if variables are static
|
|
56
53
|
const variableValues$ = dbGraph.makeThunk(
|
|
57
|
-
(get,
|
|
54
|
+
(get, _setDebugInfo, { rootOtelContext }, otelContext) => {
|
|
58
55
|
if (typeof genVariableValues === 'function') {
|
|
59
56
|
return genVariableValues(makeGetAtomResult(get, otelContext ?? rootOtelContext))
|
|
60
57
|
} else {
|
|
@@ -66,12 +63,11 @@ export class LiveStoreGraphQLQuery<
|
|
|
66
63
|
|
|
67
64
|
this.variableValues$ = variableValues$
|
|
68
65
|
|
|
69
|
-
// const resultsLabel = `${labelWithDefault}:results` + (this.temporaryQueries ? ':temp' : '')
|
|
70
66
|
const resultsLabel = `${labelWithDefault}:results`
|
|
71
67
|
this.results$ = dbGraph.makeThunk<TResult>(
|
|
72
|
-
(get,
|
|
68
|
+
(get, setDebugInfo, { store, otelTracer, rootOtelContext }, otelContext) => {
|
|
73
69
|
const variableValues = get(variableValues$)
|
|
74
|
-
const { result, queriedTables } = this.queryOnce({
|
|
70
|
+
const { result, queriedTables, durationMs } = this.queryOnce({
|
|
75
71
|
document,
|
|
76
72
|
variableValues,
|
|
77
73
|
otelContext: otelContext ?? rootOtelContext,
|
|
@@ -86,7 +82,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
86
82
|
get(tableRef!)
|
|
87
83
|
}
|
|
88
84
|
|
|
89
|
-
|
|
85
|
+
setDebugInfo({ _tag: 'graphql', label: resultsLabel, query: graphql.print(document), durationMs })
|
|
90
86
|
|
|
91
87
|
return result
|
|
92
88
|
},
|
|
@@ -122,8 +118,6 @@ export class LiveStoreGraphQLQuery<
|
|
|
122
118
|
variableValues: TVariableValues
|
|
123
119
|
store: Store<TContext>
|
|
124
120
|
}) => {
|
|
125
|
-
// const schema = this.schema
|
|
126
|
-
// const context = this.context
|
|
127
121
|
const schema =
|
|
128
122
|
store.graphQLSchema ?? shouldNeverHappen("Can't run a GraphQL query on a store without GraphQL schema")
|
|
129
123
|
const context =
|
|
@@ -132,33 +126,37 @@ export class LiveStoreGraphQLQuery<
|
|
|
132
126
|
const operationName = graphql.getOperationAST(document)?.name?.value
|
|
133
127
|
|
|
134
128
|
return otelTracer.startActiveSpan(`executeGraphQLQuery: ${operationName}`, {}, otelContext, (span) => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
span.setAttribute('graphql.query', graphql.print(document))
|
|
129
|
+
span.setAttribute('graphql.variables', JSON.stringify(variableValues))
|
|
130
|
+
span.setAttribute('graphql.query', graphql.print(document))
|
|
138
131
|
|
|
139
|
-
|
|
132
|
+
context.queriedTables.clear()
|
|
140
133
|
|
|
141
|
-
|
|
134
|
+
context.otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
142
135
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
const res = graphql.executeSync({
|
|
137
|
+
document,
|
|
138
|
+
contextValue: context,
|
|
139
|
+
schema: schema,
|
|
140
|
+
variableValues,
|
|
141
|
+
})
|
|
149
142
|
|
|
150
|
-
|
|
143
|
+
// TODO track number of nested SQL queries via Otel + debug info
|
|
151
144
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
145
|
+
if (res.errors) {
|
|
146
|
+
span.setStatus({ code: otel.SpanStatusCode.ERROR, message: 'GraphQL error' })
|
|
147
|
+
span.setAttribute('graphql.error', res.errors.join('\n'))
|
|
148
|
+
span.setAttribute('graphql.error-detail', JSON.stringify(res.errors))
|
|
149
|
+
console.error(`graphql error (${operationName})`, res.errors)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
span.end()
|
|
153
|
+
|
|
154
|
+
const durationMs = getDurationMsFromSpan(span)
|
|
158
155
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
156
|
+
return {
|
|
157
|
+
result: res.data as unknown as TResult,
|
|
158
|
+
queriedTables: Array.from(context.queriedTables.values()),
|
|
159
|
+
durationMs,
|
|
162
160
|
}
|
|
163
161
|
})
|
|
164
162
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as otel from '@opentelemetry/api'
|
|
2
2
|
|
|
3
|
+
import { getDurationMsFromSpan } from '../otel.js'
|
|
3
4
|
import type { Thunk } from '../reactive.js'
|
|
5
|
+
import type { RefreshReason } from '../store.js'
|
|
4
6
|
import { type GetAtomResult, LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
5
7
|
import type { DbContext } from './graph.js'
|
|
6
8
|
import { dbGraph } from './graph.js'
|
|
@@ -12,7 +14,7 @@ export class LiveStoreJSQuery<TResult> extends LiveStoreQueryBase<TResult> {
|
|
|
12
14
|
_tag: 'js' = 'js'
|
|
13
15
|
|
|
14
16
|
/** A reactive thunk representing the query results */
|
|
15
|
-
results$: Thunk<TResult, DbContext>
|
|
17
|
+
results$: Thunk<TResult, DbContext, RefreshReason>
|
|
16
18
|
|
|
17
19
|
label: string
|
|
18
20
|
|
|
@@ -37,16 +39,18 @@ export class LiveStoreJSQuery<TResult> extends LiveStoreQueryBase<TResult> {
|
|
|
37
39
|
const queryLabel = `${label}:results`
|
|
38
40
|
|
|
39
41
|
this.results$ = dbGraph.makeThunk(
|
|
40
|
-
(get,
|
|
42
|
+
(get, setDebugInfo, { otelTracer, rootOtelContext }, otelContext) =>
|
|
41
43
|
otelTracer.startActiveSpan(`js:${label}`, {}, otelContext ?? rootOtelContext, (span) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
44
|
+
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
45
|
+
const res = fn(makeGetAtomResult(get, otelContext))
|
|
46
|
+
|
|
47
|
+
span.end()
|
|
48
|
+
|
|
49
|
+
const durationMs = getDurationMsFromSpan(span)
|
|
50
|
+
|
|
51
|
+
setDebugInfo({ _tag: 'js', label, query: fn.toString(), durationMs })
|
|
52
|
+
|
|
53
|
+
return res
|
|
50
54
|
}),
|
|
51
55
|
{ label: queryLabel, meta: { liveStoreThunkType: 'jsResults' } },
|
|
52
56
|
)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
2
|
import * as otel from '@opentelemetry/api'
|
|
3
3
|
|
|
4
|
+
import { getDurationMsFromSpan } from '../otel.js'
|
|
4
5
|
import type { Thunk } from '../reactive.js'
|
|
6
|
+
import type { RefreshReason } from '../store.js'
|
|
5
7
|
import type { Bindable } from '../util.js'
|
|
6
8
|
import { prepareBindValues } from '../util.js'
|
|
7
9
|
import { type GetAtomResult, LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
@@ -11,17 +13,22 @@ import { LiveStoreJSQuery } from './js.js'
|
|
|
11
13
|
|
|
12
14
|
export const querySQL = <Row>(
|
|
13
15
|
query: string | ((get: GetAtomResult) => string),
|
|
14
|
-
options
|
|
15
|
-
|
|
16
|
+
options?: {
|
|
17
|
+
/**
|
|
18
|
+
* Can be provided explicitly to slightly speed up initial query performance
|
|
19
|
+
*
|
|
20
|
+
* NOTE In the future we want to do this automatically at build time
|
|
21
|
+
*/
|
|
22
|
+
queriedTables?: ReadonlyArray<string>
|
|
16
23
|
bindValues?: Bindable
|
|
17
24
|
label?: string
|
|
18
25
|
},
|
|
19
26
|
) =>
|
|
20
27
|
new LiveStoreSQLQuery<Row>({
|
|
21
|
-
label: options
|
|
28
|
+
label: options?.label,
|
|
22
29
|
genQueryString: query,
|
|
23
|
-
queriedTables: options
|
|
24
|
-
bindValues: options
|
|
30
|
+
queriedTables: options?.queriedTables,
|
|
31
|
+
bindValues: options?.bindValues,
|
|
25
32
|
})
|
|
26
33
|
|
|
27
34
|
/* An object encapsulating a reactive SQL query */
|
|
@@ -29,10 +36,10 @@ export class LiveStoreSQLQuery<Row> extends LiveStoreQueryBase<ReadonlyArray<Row
|
|
|
29
36
|
_tag: 'sql' = 'sql'
|
|
30
37
|
|
|
31
38
|
/** A reactive thunk representing the query text */
|
|
32
|
-
queryString$: Thunk<string, DbContext>
|
|
39
|
+
queryString$: Thunk<string, DbContext, RefreshReason>
|
|
33
40
|
|
|
34
41
|
/** A reactive thunk representing the query results */
|
|
35
|
-
results$: Thunk<ReadonlyArray<Row>, DbContext>
|
|
42
|
+
results$: Thunk<ReadonlyArray<Row>, DbContext, RefreshReason>
|
|
36
43
|
|
|
37
44
|
label: string
|
|
38
45
|
|
|
@@ -44,19 +51,22 @@ export class LiveStoreSQLQuery<Row> extends LiveStoreQueryBase<ReadonlyArray<Row
|
|
|
44
51
|
}: {
|
|
45
52
|
label?: string
|
|
46
53
|
genQueryString: string | ((get: GetAtomResult) => string)
|
|
47
|
-
queriedTables
|
|
54
|
+
queriedTables?: ReadonlyArray<string>
|
|
48
55
|
bindValues?: Bindable
|
|
49
56
|
}) {
|
|
50
57
|
super()
|
|
51
58
|
|
|
52
59
|
const label = label_ ?? genQueryString.toString()
|
|
60
|
+
this.label = `sql(${label})`
|
|
53
61
|
|
|
54
62
|
// TODO don't even create a thunk if query string is static
|
|
55
63
|
const queryString$ = dbGraph.makeThunk(
|
|
56
|
-
(get,
|
|
64
|
+
(get, setDebugInfo, { rootOtelContext }, otelContext) => {
|
|
57
65
|
if (typeof genQueryString === 'function') {
|
|
66
|
+
const startMs = performance.now()
|
|
58
67
|
const queryString = genQueryString(makeGetAtomResult(get, otelContext ?? rootOtelContext))
|
|
59
|
-
|
|
68
|
+
const durationMs = performance.now() - startMs
|
|
69
|
+
setDebugInfo({ _tag: 'js', label: `${label}:queryString`, query: queryString, durationMs })
|
|
60
70
|
return queryString
|
|
61
71
|
} else {
|
|
62
72
|
return genQueryString
|
|
@@ -67,57 +77,54 @@ export class LiveStoreSQLQuery<Row> extends LiveStoreQueryBase<ReadonlyArray<Row
|
|
|
67
77
|
|
|
68
78
|
this.queryString$ = queryString$
|
|
69
79
|
|
|
70
|
-
// TODO come up with different way to handle labels
|
|
71
|
-
// label = label ?? `sql(${queryString$.computeResult()})`
|
|
72
|
-
|
|
73
|
-
this.label = `sql(${label})`
|
|
74
|
-
// span.updateName(`querySQL:${label}`)
|
|
75
|
-
|
|
76
80
|
const queryLabel = `${label}:results`
|
|
77
|
-
|
|
81
|
+
|
|
82
|
+
const queriedTablesRef = { current: queriedTables }
|
|
78
83
|
|
|
79
84
|
const results$ = dbGraph.makeThunk<ReadonlyArray<Row>>(
|
|
80
|
-
(get,
|
|
85
|
+
(get, setDebugInfo, { store, otelTracer, rootOtelContext }, otelContext) =>
|
|
81
86
|
otelTracer.startActiveSpan(
|
|
82
|
-
'sql
|
|
87
|
+
'sql:...', // NOTE span name will be overridden further down
|
|
83
88
|
{},
|
|
84
89
|
otelContext ?? rootOtelContext,
|
|
85
90
|
(span) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const results = store.inMemoryDB.select<Row>(sqlString, {
|
|
100
|
-
queriedTables,
|
|
101
|
-
bindValues: bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
|
|
102
|
-
otelContext,
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
span.setAttribute('sql.rowsCount', results.length)
|
|
106
|
-
addDebugInfo({ _tag: 'sql', label: label ?? '', query: sqlString })
|
|
107
|
-
|
|
108
|
-
return results
|
|
109
|
-
} finally {
|
|
110
|
-
span.end()
|
|
91
|
+
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
92
|
+
|
|
93
|
+
const sqlString = get(queryString$, otelContext)
|
|
94
|
+
|
|
95
|
+
if (queriedTablesRef.current === undefined) {
|
|
96
|
+
queriedTablesRef.current = store.inMemoryDB.getTablesUsed(sqlString)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Establish a reactive dependency on the tables used in the query
|
|
100
|
+
for (const tableName of queriedTablesRef.current) {
|
|
101
|
+
const tableRef = store.tableRefs[tableName] ?? shouldNeverHappen(`No table ref found for ${tableName}`)
|
|
102
|
+
get(tableRef, otelContext)
|
|
111
103
|
}
|
|
104
|
+
|
|
105
|
+
span.setAttribute('sql.query', sqlString)
|
|
106
|
+
span.updateName(`sql:${sqlString.slice(0, 50)}`)
|
|
107
|
+
|
|
108
|
+
const results = store.inMemoryDB.select<Row>(sqlString, {
|
|
109
|
+
queriedTables,
|
|
110
|
+
bindValues: bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
|
|
111
|
+
otelContext,
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
span.setAttribute('sql.rowsCount', results.length)
|
|
115
|
+
|
|
116
|
+
span.end()
|
|
117
|
+
|
|
118
|
+
const durationMs = getDurationMsFromSpan(span)
|
|
119
|
+
|
|
120
|
+
setDebugInfo({ _tag: 'sql', label, query: sqlString, durationMs })
|
|
121
|
+
|
|
122
|
+
return results
|
|
112
123
|
},
|
|
113
124
|
),
|
|
114
125
|
{ label: queryLabel },
|
|
115
126
|
)
|
|
116
127
|
|
|
117
|
-
// this.queryString$ = queryString$
|
|
118
|
-
// this.results$ = results$
|
|
119
|
-
// this.payload = payload
|
|
120
|
-
|
|
121
128
|
this.results$ = results$
|
|
122
129
|
}
|
|
123
130
|
|