@livestore/livestore 0.0.39-dev.3 → 0.0.39
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/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/mutations.test.js +1 -1
- package/dist/__tests__/react/fixture.d.ts +18 -18
- package/dist/mutations.d.ts +1 -1
- package/dist/mutations.d.ts.map +1 -1
- package/dist/mutations.js +5 -1
- package/dist/mutations.js.map +1 -1
- package/dist/{update-path.d.ts → query-info.d.ts} +12 -12
- package/dist/query-info.d.ts.map +1 -0
- package/dist/{update-path.js → query-info.js} +2 -2
- 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/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/useTemporaryQuery.d.ts +2 -2
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +14 -8
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +1 -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 +28 -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 +4 -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 +6 -6
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/row-query.d.ts +5 -5
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +4 -4
- package/dist/row-query.js.map +1 -1
- package/dist/schema/parse-utils.d.ts +0 -3
- 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 +5 -5
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js.map +1 -1
- package/package.json +10 -10
- package/src/__tests__/mutations.test.ts +1 -1
- package/src/mutations.ts +9 -2
- package/src/{update-path.ts → query-info.ts} +15 -15
- package/src/react/LiveStoreContext.ts +0 -9
- package/src/react/useAtom.ts +6 -6
- package/src/react/useQuery.ts +1 -1
- package/src/react/useRow.ts +10 -10
- package/src/reactiveQueries/base-class.ts +19 -9
- package/src/reactiveQueries/graphql.ts +47 -13
- package/src/reactiveQueries/js.ts +13 -13
- package/src/reactiveQueries/sql.ts +22 -22
- package/src/row-query.ts +13 -13
- package/src/schema/parse-utils.ts +2 -44
- package/src/schema/table-def.ts +2 -1
- package/dist/update-path.d.ts.map +0 -1
- package/dist/update-path.js.map +0 -1
|
@@ -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,12 @@ 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
|
|
|
166
200
|
return {
|
|
167
|
-
result
|
|
201
|
+
result,
|
|
168
202
|
queriedTables: Array.from(context.queriedTables.values()),
|
|
169
203
|
durationMs,
|
|
170
204
|
}
|
|
@@ -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
|
|
|
@@ -3,9 +3,9 @@ import { Schema, TreeFormatter } from '@livestore/utils/effect'
|
|
|
3
3
|
import * as otel from '@opentelemetry/api'
|
|
4
4
|
|
|
5
5
|
import { globalDbGraph } from '../global-state.js'
|
|
6
|
+
import type { QueryInfo, QueryInfoNone } from '../query-info.js'
|
|
6
7
|
import type { Thunk } from '../reactive.js'
|
|
7
8
|
import type { RefreshReason } from '../store.js'
|
|
8
|
-
import type { UpdatePathDesc, UpdatePathDescNone } from '../update-path.js'
|
|
9
9
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
10
10
|
import type { Bindable } from '../utils/util.js'
|
|
11
11
|
import { prepareBindValues } from '../utils/util.js'
|
|
@@ -14,12 +14,12 @@ import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
|
14
14
|
|
|
15
15
|
export type MapRows<TResult, TRaw = any> =
|
|
16
16
|
| ((rows: ReadonlyArray<TRaw>) => TResult)
|
|
17
|
-
| Schema.Schema<ReadonlyArray<TRaw>, TResult>
|
|
17
|
+
| Schema.Schema<never, ReadonlyArray<TRaw>, TResult>
|
|
18
18
|
|
|
19
|
-
export const querySQL = <
|
|
19
|
+
export const querySQL = <TResult, TRaw = any>(
|
|
20
20
|
query: string | ((get: GetAtomResult) => string),
|
|
21
21
|
options?: {
|
|
22
|
-
map?: MapRows<
|
|
22
|
+
map?: MapRows<TResult, TRaw>
|
|
23
23
|
/**
|
|
24
24
|
* Can be provided explicitly to slightly speed up initial query performance
|
|
25
25
|
*
|
|
@@ -30,29 +30,29 @@ export const querySQL = <Result, TRaw = any>(
|
|
|
30
30
|
label?: string
|
|
31
31
|
dbGraph?: DbGraph
|
|
32
32
|
},
|
|
33
|
-
): LiveQuery<
|
|
34
|
-
new LiveStoreSQLQuery<
|
|
33
|
+
): LiveQuery<TResult, QueryInfoNone> =>
|
|
34
|
+
new LiveStoreSQLQuery<TResult, QueryInfoNone>({
|
|
35
35
|
label: options?.label,
|
|
36
36
|
genQueryString: query,
|
|
37
37
|
queriedTables: options?.queriedTables,
|
|
38
38
|
bindValues: options?.bindValues,
|
|
39
39
|
dbGraph: options?.dbGraph,
|
|
40
40
|
map: options?.map,
|
|
41
|
-
|
|
41
|
+
queryInfo: { _tag: 'None' },
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
/* An object encapsulating a reactive SQL query */
|
|
45
|
-
export class LiveStoreSQLQuery<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
>
|
|
45
|
+
export class LiveStoreSQLQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoNone> extends LiveStoreQueryBase<
|
|
46
|
+
TResult,
|
|
47
|
+
TQueryInfo
|
|
48
|
+
> {
|
|
49
49
|
_tag: 'sql' = 'sql'
|
|
50
50
|
|
|
51
51
|
/** A reactive thunk representing the query text */
|
|
52
52
|
queryString$: Thunk<string, DbContext, RefreshReason>
|
|
53
53
|
|
|
54
54
|
/** A reactive thunk representing the query results */
|
|
55
|
-
results$: Thunk<
|
|
55
|
+
results$: Thunk<TResult, DbContext, RefreshReason>
|
|
56
56
|
|
|
57
57
|
label: string
|
|
58
58
|
|
|
@@ -63,7 +63,7 @@ export class LiveStoreSQLQuery<
|
|
|
63
63
|
|
|
64
64
|
private mapRows
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
queryInfo: TQueryInfo
|
|
67
67
|
|
|
68
68
|
constructor({
|
|
69
69
|
genQueryString,
|
|
@@ -73,16 +73,16 @@ export class LiveStoreSQLQuery<
|
|
|
73
73
|
dbGraph,
|
|
74
74
|
map,
|
|
75
75
|
execBeforeFirstRun,
|
|
76
|
-
|
|
76
|
+
queryInfo,
|
|
77
77
|
}: {
|
|
78
78
|
label?: string
|
|
79
79
|
genQueryString: string | ((get: GetAtomResult) => string)
|
|
80
80
|
queriedTables?: Set<string>
|
|
81
81
|
bindValues?: Bindable
|
|
82
82
|
dbGraph?: DbGraph
|
|
83
|
-
map?: MapRows<
|
|
83
|
+
map?: MapRows<TResult>
|
|
84
84
|
execBeforeFirstRun?: (ctx: DbContext) => void
|
|
85
|
-
|
|
85
|
+
queryInfo?: TQueryInfo
|
|
86
86
|
}) {
|
|
87
87
|
super()
|
|
88
88
|
|
|
@@ -90,18 +90,18 @@ export class LiveStoreSQLQuery<
|
|
|
90
90
|
this.label = `sql(${label})`
|
|
91
91
|
this.dbGraph = dbGraph ?? globalDbGraph
|
|
92
92
|
this.execBeforeFirstRun = execBeforeFirstRun
|
|
93
|
-
this.
|
|
93
|
+
this.queryInfo = queryInfo ?? ({ _tag: 'None' } as TQueryInfo)
|
|
94
94
|
this.mapRows =
|
|
95
95
|
map === undefined
|
|
96
|
-
? (rows: any) => rows as
|
|
96
|
+
? (rows: any) => rows as TResult
|
|
97
97
|
: Schema.isSchema(map)
|
|
98
98
|
? (rows: any) => {
|
|
99
|
-
const parseResult = Schema.
|
|
99
|
+
const parseResult = Schema.decodeEither(map as Schema.Schema<never, ReadonlyArray<any>, TResult>)(rows)
|
|
100
100
|
if (parseResult._tag === 'Left') {
|
|
101
101
|
console.error(`Error parsing SQL query result: ${TreeFormatter.formatError(parseResult.left)}`)
|
|
102
102
|
return shouldNeverHappen(`Error parsing SQL query result: ${parseResult.left}`)
|
|
103
103
|
} else {
|
|
104
|
-
return parseResult.right as
|
|
104
|
+
return parseResult.right as TResult
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
: typeof map === 'function'
|
|
@@ -130,7 +130,7 @@ export class LiveStoreSQLQuery<
|
|
|
130
130
|
|
|
131
131
|
const queriedTablesRef = { current: queriedTables }
|
|
132
132
|
|
|
133
|
-
const results$ = this.dbGraph.makeThunk<
|
|
133
|
+
const results$ = this.dbGraph.makeThunk<TResult>(
|
|
134
134
|
(get, setDebugInfo, { store, otelTracer, rootOtelContext }, otelContext) =>
|
|
135
135
|
otelTracer.startActiveSpan(
|
|
136
136
|
'sql:...', // NOTE span name will be overridden further down
|
|
@@ -197,7 +197,7 @@ export class LiveStoreSQLQuery<
|
|
|
197
197
|
// label: `${this.label}:js`,
|
|
198
198
|
// onDestroy: () => this.destroy(),
|
|
199
199
|
// dbGraph: this.dbGraph,
|
|
200
|
-
//
|
|
200
|
+
// queryInfo: undefined,
|
|
201
201
|
// })
|
|
202
202
|
|
|
203
203
|
/** Returns a reactive query */
|
package/src/row-query.ts
CHANGED
|
@@ -6,8 +6,9 @@ import { SqliteAst, SqliteDsl } from 'effect-db-schema'
|
|
|
6
6
|
import { computed } from './index.js'
|
|
7
7
|
import type { InMemoryDatabase } from './inMemoryDatabase.js'
|
|
8
8
|
import { migrateTable } from './migrations.js'
|
|
9
|
+
import type { QueryInfoCol, QueryInfoNone, QueryInfoRow } from './query-info.js'
|
|
9
10
|
import type { Ref } from './reactive.js'
|
|
10
|
-
import type { DbContext, DbGraph,
|
|
11
|
+
import type { DbContext, DbGraph, LiveQuery, LiveQueryAny } from './reactiveQueries/base-class.js'
|
|
11
12
|
// import type { LiveStoreJSQuery } from './reactiveQueries/js.js'
|
|
12
13
|
import { LiveStoreSQLQuery } from './reactiveQueries/sql.js'
|
|
13
14
|
import { SCHEMA_META_TABLE } from './schema/index.js'
|
|
@@ -18,7 +19,6 @@ import {
|
|
|
18
19
|
type TableOptions,
|
|
19
20
|
} from './schema/table-def.js'
|
|
20
21
|
import type { RefreshReason } from './store.js'
|
|
21
|
-
import type { UpdatePathDesc, UpdatePathDescCol, UpdatePathDescNone, UpdatePathDescRow } from './update-path.js'
|
|
22
22
|
import type { GetValForKey } from './utils/util.js'
|
|
23
23
|
import { prepareBindValues, sql } from './utils/util.js'
|
|
24
24
|
|
|
@@ -36,13 +36,13 @@ export type MakeRowQuery = {
|
|
|
36
36
|
<TTableDef extends TableDef<DefaultSqliteTableDef, boolean, TableOptions & { isSingleton: true }>>(
|
|
37
37
|
table: TTableDef,
|
|
38
38
|
options?: RowQueryOptions,
|
|
39
|
-
): LiveQuery<RowResult<TTableDef>,
|
|
39
|
+
): LiveQuery<RowResult<TTableDef>, QueryInfoRow<TTableDef>>
|
|
40
40
|
<TTableDef extends TableDef<DefaultSqliteTableDef, boolean, TableOptions & { isSingleton: false }>>(
|
|
41
41
|
table: TTableDef,
|
|
42
42
|
// TODO adjust so it works with arbitrary primary keys or unique constraints
|
|
43
43
|
id: string,
|
|
44
44
|
options?: RowQueryOptions & RowQueryOptionsDefaulValues<TTableDef>,
|
|
45
|
-
): LiveQuery<RowResult<TTableDef>,
|
|
45
|
+
): LiveQuery<RowResult<TTableDef>, QueryInfoRow<TTableDef>>
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// TODO also allow other where clauses and multiple rows
|
|
@@ -85,7 +85,7 @@ export const rowQuery: MakeRowQuery = <TTableDef extends TableDef>(
|
|
|
85
85
|
if (results.length === 0) return shouldNeverHappen(`No results for query ${queryStr}`)
|
|
86
86
|
|
|
87
87
|
const componentStateEffectSchema = SqliteDsl.structSchemaForTable(stateSchema)
|
|
88
|
-
const parseResult = Schema.
|
|
88
|
+
const parseResult = Schema.decodeEither(componentStateEffectSchema)(results[0]!)
|
|
89
89
|
|
|
90
90
|
if (parseResult._tag === 'Left') {
|
|
91
91
|
console.error('decode error', TreeFormatter.formatError(parseResult.left), 'results', results)
|
|
@@ -94,7 +94,7 @@ export const rowQuery: MakeRowQuery = <TTableDef extends TableDef>(
|
|
|
94
94
|
|
|
95
95
|
return table.isSingleColumn === true ? parseResult.right.value : parseResult.right
|
|
96
96
|
},
|
|
97
|
-
|
|
97
|
+
queryInfo: { _tag: 'Row', table, id: id ?? 'singleton' },
|
|
98
98
|
})
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -107,20 +107,20 @@ export type RowResultEncoded<TTableDef extends TableDef> = TTableDef['isSingleCo
|
|
|
107
107
|
: SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>
|
|
108
108
|
|
|
109
109
|
export const deriveColQuery: {
|
|
110
|
-
<TQuery extends LiveQuery<any,
|
|
110
|
+
<TQuery extends LiveQuery<any, QueryInfoNone>, TCol extends keyof TQuery['__result!'] & string>(
|
|
111
111
|
query$: TQuery,
|
|
112
112
|
colName: TCol,
|
|
113
|
-
): LiveQuery<TQuery['
|
|
114
|
-
<TQuery extends LiveQuery<any,
|
|
113
|
+
): LiveQuery<TQuery['__result!'][TCol], QueryInfoNone>
|
|
114
|
+
<TQuery extends LiveQuery<any, QueryInfoRow<any>>, TCol extends keyof TQuery['__result!'] & string>(
|
|
115
115
|
query$: TQuery,
|
|
116
116
|
colName: TCol,
|
|
117
|
-
): LiveQuery<TQuery['
|
|
117
|
+
): LiveQuery<TQuery['__result!'][TCol], QueryInfoCol<TQuery['queryInfo']['table'], TCol>>
|
|
118
118
|
} = (query$: LiveQueryAny, colName: string) => {
|
|
119
119
|
return computed((get) => get(query$)[colName], {
|
|
120
120
|
label: `deriveColQuery:${query$.label}:${colName}`,
|
|
121
|
-
|
|
122
|
-
query$.
|
|
123
|
-
? { _tag: 'Col', table: query$.
|
|
121
|
+
queryInfo:
|
|
122
|
+
query$.queryInfo._tag === 'Row'
|
|
123
|
+
? { _tag: 'Col', table: query$.queryInfo.table, column: colName, id: query$.queryInfo.id }
|
|
124
124
|
: undefined,
|
|
125
125
|
}) as any
|
|
126
126
|
}
|
|
@@ -5,52 +5,10 @@ import { SqliteDsl as __SqliteDsl } from 'effect-db-schema'
|
|
|
5
5
|
|
|
6
6
|
import { type FromColumns, type FromTable, getDefaultValuesDecoded, type TableDef } from './table-def.js'
|
|
7
7
|
|
|
8
|
-
export const headUnsafe = <From, To>(schema: Schema.Schema<From, To>) =>
|
|
9
|
-
Schema.transform(
|
|
10
|
-
Schema.array(schema),
|
|
11
|
-
Schema.to(schema),
|
|
12
|
-
(rows) => rows[0]!,
|
|
13
|
-
(row) => [row],
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
// export const head = <From, To>(schema: Schema.Schema<From, To>) =>
|
|
17
|
-
// Schema.transform(
|
|
18
|
-
// Schema.array(schema),
|
|
19
|
-
// Schema.optionFromSelf(Schema.to(schema)),
|
|
20
|
-
// (rows) => Option.fromNullable(rows[0]),
|
|
21
|
-
// (row) => (row._tag === 'None' ? [] : [row.value]),
|
|
22
|
-
// )
|
|
23
|
-
|
|
24
|
-
export const headOr = <From, To>(schema: Schema.Schema<From, To>, fallback: To) =>
|
|
25
|
-
Schema.transform(
|
|
26
|
-
Schema.array(schema),
|
|
27
|
-
Schema.to(schema),
|
|
28
|
-
(rows) => rows[0] ?? fallback,
|
|
29
|
-
(row) => [row],
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
// export const pluck = <From extends {}, To, K extends keyof From & keyof To & string>(
|
|
33
|
-
// schema: Schema.Schema<From, To>,
|
|
34
|
-
// prop: K,
|
|
35
|
-
// ): Schema.Schema<From, To[K]> => {
|
|
36
|
-
// const toSchema = Schema.make(SchemaAST.getPropertySignatures(schema.ast).find((s) => s.name === prop)!.type) as any
|
|
37
|
-
// return Schema.transform(
|
|
38
|
-
// schema,
|
|
39
|
-
// toSchema,
|
|
40
|
-
// (row) => (row as any)[prop],
|
|
41
|
-
// (val) => ({ [prop]: val }) as any,
|
|
42
|
-
// )
|
|
43
|
-
// }
|
|
44
|
-
|
|
45
|
-
// export const schemaFor = <TTableDef extends TableDef>(
|
|
46
|
-
// table: TTableDef,
|
|
47
|
-
// ): Schema.Schema<FromTable.RowEncoded<TTableDef>, FromTable.RowDecoded<TTableDef>> =>
|
|
48
|
-
// SqliteDsl.structSchemaForTable(table.sqliteDef) as any
|
|
49
|
-
|
|
50
8
|
export const many = <TTableDef extends TableDef>(
|
|
51
9
|
table: TTableDef,
|
|
52
10
|
): ((rawRows: ReadonlyArray<any>) => ReadonlyArray<FromTable.RowDecoded<TTableDef>>) => {
|
|
53
|
-
return Schema.
|
|
11
|
+
return Schema.decodeSync(Schema.array(table.schema)) as TODO
|
|
54
12
|
}
|
|
55
13
|
|
|
56
14
|
export const first =
|
|
@@ -59,7 +17,7 @@ export const first =
|
|
|
59
17
|
fallback?: FromColumns.InsertRowDecoded<TTableDef['sqliteDef']['columns']>,
|
|
60
18
|
) =>
|
|
61
19
|
(rawRows: ReadonlyArray<any>) => {
|
|
62
|
-
const rows = Schema.
|
|
20
|
+
const rows = Schema.decodeSync(Schema.array(table.schema))(rawRows)
|
|
63
21
|
|
|
64
22
|
if (rows.length === 0) {
|
|
65
23
|
const schemaDefaultValues = getDefaultValuesDecoded(table)
|
package/src/schema/table-def.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type DefaultSqliteTableDefConstrained = SqliteDsl.TableDefinition<string,
|
|
|
18
18
|
// TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDef,
|
|
19
19
|
// TIsSingleColumn extends boolean = boolean,
|
|
20
20
|
// TOptions extends TableOptions = TableOptions,
|
|
21
|
-
// > = TableDefBase<TSqliteDef, TIsSingleColumn, TOptions> & { schema: Schema.Schema<any, any> }
|
|
21
|
+
// > = TableDefBase<TSqliteDef, TIsSingleColumn, TOptions> & { schema: Schema.Schema<never, any, any> }
|
|
22
22
|
|
|
23
23
|
// /**
|
|
24
24
|
// * NOTE in the past we used to have a single `TableDef` but there are some TS issues when indroducing
|
|
@@ -44,6 +44,7 @@ export type TableDef<
|
|
|
44
44
|
// NOTE we're not using `SqliteDsl.StructSchemaForColumns<TSqliteDef['columns']>`
|
|
45
45
|
// as we don't want the alias type for users to show up
|
|
46
46
|
TSchema = Schema.Schema<
|
|
47
|
+
never,
|
|
47
48
|
SqliteDsl.AnyIfConstained<
|
|
48
49
|
TSqliteDef['columns'],
|
|
49
50
|
{ readonly [K in keyof TSqliteDef['columns']]: Schema.Schema.From<TSqliteDef['columns'][K]['schema']> }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"update-path.d.ts","sourceRoot":"","sources":["../src/update-path.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAEhE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,QAAQ,GAAG,QAAQ,IAC5D,kBAAkB,GAClB,iBAAiB,CAAC,SAAS,CAAC,GAC5B,0BAA0B,CAAC,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,GAC/D,iBAAiB,CAAC,SAAS,EAAE,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;AAEzE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,SAAS,SAAS,QAAQ,IAAI;IAC1D,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,SAAS,SAAS,QAAQ,EAAE,QAAQ,SAAS,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,IAAI;IACpH,IAAI,EAAE,KAAK,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,QAAQ,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,0BAA0B,CAAC,SAAS,SAAS,QAAQ,EAAE,QAAQ,SAAS,aAAa,CAAC,SAAS,CAAC,IAAI;IAC9G,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,QAAQ,CAAA;IAChB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,KAAK,aAAa,CAAC,SAAS,SAAS,QAAQ,IAAI,MAAM;KACpD,OAAO,IAAI,MAAM,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,SAAS,MAAM,GAC1H,OAAO,GACP,KAAK,GAAG,EAAE;CACf,CAAA;AAID,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,cAAc,IAAI,KAAK,SAAS;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GACxF,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAChD,KAAK,SAAS;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAC3B,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GACnF,KAAK,SAAS;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,GACd,KAAK,CAAA;AAEb,eAAO,MAAM,uBAAuB,mGAGjC,UAmCF,CAAA;AAED,KAAK,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAAA"}
|
package/dist/update-path.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"update-path.js","sourceRoot":"","sources":["../src/update-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AA4DhD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,UAAiB,EACjB,KAAgC,EACpB,EAAE;IACd,IAAI,UAAU,CAAC,IAAI,KAAK,cAAc,IAAI,UAAU,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACrE,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAA;IACjD,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,CAAA;IAExB,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE;QACxC,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAEtC,MAAM,mBAAmB,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC,CAAA;YAErF,yCAAyC;YACzC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,KAAK,CAAC,CAAA;YAChE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,CAAA;QACpC,CAAC;aAAM,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAA;YACpC,MAAM,YAAY,GAChB,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,iBAAiB,CAAC,UAAU,UAAU,YAAY,CAAC,CAAA;YACnG,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,EAAE,CAAA;YAC3E,OAAO,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,iBAAiB,EAAE,CAAA;QAC5B,CAAC;IACH,CAAC,CAAC,EAAE,CAAA;IAEJ,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,UAAU,OAAO,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEjG,MAAM,WAAW,GAAG,eAAe,EAAE,GAAG,CAAA;IACxC,MAAM,GAAG,GAAG,UAAU,cAAc,CAAC,IAAI,QAAQ,YAAY,IAAI,WAAW,EAAE,CAAA;IAC9E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAS,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAEtE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CAAA;AAClF,CAAC,CAAA"}
|