@livestore/livestore 0.1.0-dev.9 → 0.2.0-dev.0
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 +3 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/global-state.d.ts +1 -1
- package/dist/global-state.d.ts.map +1 -1
- package/dist/global-state.js +1 -1
- package/dist/global-state.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/live-queries/base-class.d.ts +64 -0
- package/dist/live-queries/base-class.d.ts.map +1 -0
- package/dist/live-queries/base-class.js +31 -0
- package/dist/live-queries/base-class.js.map +1 -0
- package/dist/live-queries/computed.d.ts +26 -0
- package/dist/live-queries/computed.d.ts.map +1 -0
- package/dist/{reactiveQueries/js.js → live-queries/computed.js} +7 -26
- package/dist/live-queries/computed.js.map +1 -0
- package/dist/live-queries/db.d.ts +66 -0
- package/dist/live-queries/db.d.ts.map +1 -0
- package/dist/live-queries/db.js +199 -0
- package/dist/live-queries/db.js.map +1 -0
- package/dist/live-queries/db.test.d.ts +2 -0
- package/dist/live-queries/db.test.d.ts.map +1 -0
- package/dist/live-queries/db.test.js +117 -0
- package/dist/live-queries/db.test.js.map +1 -0
- package/dist/live-queries/graphql.d.ts +49 -0
- package/dist/live-queries/graphql.d.ts.map +1 -0
- package/dist/live-queries/graphql.js +122 -0
- package/dist/live-queries/graphql.js.map +1 -0
- package/dist/live-queries/sql.d.ts +62 -0
- package/dist/live-queries/sql.d.ts.map +1 -0
- package/dist/live-queries/sql.js +175 -0
- package/dist/live-queries/sql.js.map +1 -0
- package/dist/live-queries/sql.test.d.ts +2 -0
- package/dist/live-queries/sql.test.d.ts.map +1 -0
- package/{src/reactiveQueries/sql.test.ts → dist/live-queries/sql.test.js} +68 -91
- package/dist/live-queries/sql.test.js.map +1 -0
- package/dist/reactiveQueries/base-class.d.ts +6 -2
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +2 -0
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/computed.d.ts +4 -13
- package/dist/reactiveQueries/computed.d.ts.map +1 -1
- package/dist/reactiveQueries/computed.js +2 -21
- package/dist/reactiveQueries/computed.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +4 -8
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +1 -15
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +36 -23
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +100 -55
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/reactiveQueries/sql.test.js +12 -11
- package/dist/reactiveQueries/sql.test.js.map +1 -1
- package/dist/row-query-utils.d.ts +17 -0
- package/dist/row-query-utils.d.ts.map +1 -0
- package/dist/row-query-utils.js +30 -0
- package/dist/row-query-utils.js.map +1 -0
- package/dist/row-query.d.ts +10 -27
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +16 -66
- package/dist/row-query.js.map +1 -1
- package/dist/store/create-store.d.ts +1 -1
- package/dist/store/create-store.d.ts.map +1 -1
- package/dist/store/devtools.d.ts +1 -1
- package/dist/store/devtools.d.ts.map +1 -1
- package/dist/store/devtools.js.map +1 -1
- package/dist/store/store-types.d.ts +2 -2
- package/dist/store/store-types.d.ts.map +1 -1
- package/dist/store/store.d.ts +8 -3
- package/dist/store/store.d.ts.map +1 -1
- package/dist/store/store.js +32 -4
- package/dist/store/store.js.map +1 -1
- package/dist/utils/tests/fixture.d.ts +168 -132
- package/dist/utils/tests/fixture.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/global-state.ts +1 -1
- package/src/index.ts +8 -5
- package/src/live-queries/__snapshots__/db.test.ts.snap +301 -0
- package/src/{reactiveQueries → live-queries}/base-class.ts +10 -5
- package/src/{reactiveQueries → live-queries}/computed.ts +5 -29
- package/src/live-queries/db.test.ts +153 -0
- package/src/live-queries/db.ts +350 -0
- package/src/{reactiveQueries → live-queries}/graphql.ts +6 -21
- package/src/row-query-utils.ts +65 -0
- package/src/store/create-store.ts +1 -1
- package/src/store/devtools.ts +1 -1
- package/src/store/store-types.ts +2 -2
- package/src/store/store.ts +44 -7
- package/dist/reactiveQueries/js.d.ts +0 -35
- package/dist/reactiveQueries/js.d.ts.map +0 -1
- package/dist/reactiveQueries/js.js.map +0 -1
- package/dist/store/store-context.d.ts +0 -26
- package/dist/store/store-context.d.ts.map +0 -1
- package/dist/store/store-context.js +0 -6
- package/dist/store/store-context.js.map +0 -1
- package/dist/store-context.d.ts +0 -26
- package/dist/store-context.d.ts.map +0 -1
- package/dist/store-context.js +0 -6
- package/dist/store-context.js.map +0 -1
- package/dist/store-devtools.d.ts +0 -19
- package/dist/store-devtools.d.ts.map +0 -1
- package/dist/store-devtools.js +0 -141
- package/dist/store-devtools.js.map +0 -1
- package/dist/store.d.ts +0 -175
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -509
- package/dist/store.js.map +0 -1
- package/src/reactiveQueries/sql.ts +0 -226
- package/src/row-query.ts +0 -196
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/livestore",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-dev.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"exports": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@graphql-typed-document-node/core": "^3.2.0",
|
|
33
33
|
"@opentelemetry/api": "^1.9.0",
|
|
34
|
-
"@livestore/common": "0.
|
|
35
|
-
"@livestore/
|
|
36
|
-
"@livestore/
|
|
34
|
+
"@livestore/common": "0.2.0-dev.0",
|
|
35
|
+
"@livestore/db-schema": "0.2.0-dev.0",
|
|
36
|
+
"@livestore/utils": "0.2.0-dev.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@opentelemetry/sdk-trace-base": "1.27.0",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"typescript": "5.5.4",
|
|
42
42
|
"vite": "5.4.10",
|
|
43
43
|
"vitest": "^2.1.4",
|
|
44
|
-
"@livestore/web": "0.
|
|
44
|
+
"@livestore/web": "0.2.0-dev.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"graphql": "16.x"
|
package/src/global-state.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import { GlobalValue } from '@livestore/utils/effect'
|
|
15
15
|
|
|
16
|
-
import { makeReactivityGraph } from './
|
|
16
|
+
import { makeReactivityGraph } from './live-queries/base-class.js'
|
|
17
17
|
|
|
18
18
|
export const globalReactivityGraph = GlobalValue.globalValue('livestore-global-reactivityGraph', () =>
|
|
19
19
|
makeReactivityGraph(),
|
package/src/index.ts
CHANGED
|
@@ -25,9 +25,9 @@ export type {
|
|
|
25
25
|
Ref,
|
|
26
26
|
Effect,
|
|
27
27
|
} from './reactive.js'
|
|
28
|
-
export {
|
|
29
|
-
export {
|
|
30
|
-
export { LiveStoreGraphQLQuery, queryGraphQL } from './
|
|
28
|
+
export { LiveStoreComputedQuery, computed } from './live-queries/computed.js'
|
|
29
|
+
export { LiveStoreDbQuery, queryDb } from './live-queries/db.js'
|
|
30
|
+
export { LiveStoreGraphQLQuery, queryGraphQL } from './live-queries/graphql.js'
|
|
31
31
|
export {
|
|
32
32
|
type GetAtomResult,
|
|
33
33
|
type ReactivityGraph,
|
|
@@ -35,11 +35,11 @@ export {
|
|
|
35
35
|
type LiveQuery,
|
|
36
36
|
type GetResult,
|
|
37
37
|
type LiveQueryAny,
|
|
38
|
-
} from './
|
|
38
|
+
} from './live-queries/base-class.js'
|
|
39
39
|
|
|
40
40
|
export { globalReactivityGraph } from './global-state.js'
|
|
41
41
|
|
|
42
|
-
export {
|
|
42
|
+
export { deriveColQuery } from './row-query-utils.js'
|
|
43
43
|
|
|
44
44
|
export * from '@livestore/common/schema'
|
|
45
45
|
export {
|
|
@@ -52,6 +52,9 @@ export {
|
|
|
52
52
|
prepareBindValues,
|
|
53
53
|
type Bindable,
|
|
54
54
|
type PreparedBindValues,
|
|
55
|
+
type QueryBuilderAst,
|
|
56
|
+
type QueryBuilder,
|
|
57
|
+
type RowQuery,
|
|
55
58
|
} from '@livestore/common'
|
|
56
59
|
|
|
57
60
|
export { SqliteAst, SqliteDsl } from '@livestore/db-schema'
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`otel > otel 3`] = `
|
|
4
|
+
{
|
|
5
|
+
"_name": "test",
|
|
6
|
+
"children": [
|
|
7
|
+
{
|
|
8
|
+
"_name": "livestore.in-memory-db:execute",
|
|
9
|
+
"attributes": {
|
|
10
|
+
"sql.query": "
|
|
11
|
+
PRAGMA page_size=32768;
|
|
12
|
+
PRAGMA cache_size=10000;
|
|
13
|
+
PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
|
|
14
|
+
PRAGMA synchronous='OFF';
|
|
15
|
+
PRAGMA temp_store='MEMORY';
|
|
16
|
+
PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
|
|
17
|
+
",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"_name": "LiveStore:mutations",
|
|
22
|
+
"children": [
|
|
23
|
+
{
|
|
24
|
+
"_name": "LiveStore:mutate",
|
|
25
|
+
"attributes": {
|
|
26
|
+
"livestore.mutateLabel": "mutate",
|
|
27
|
+
},
|
|
28
|
+
"children": [
|
|
29
|
+
{
|
|
30
|
+
"_name": "LiveStore:processWrites",
|
|
31
|
+
"attributes": {
|
|
32
|
+
"livestore.mutateLabel": "mutate",
|
|
33
|
+
},
|
|
34
|
+
"children": [
|
|
35
|
+
{
|
|
36
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
37
|
+
"attributes": {
|
|
38
|
+
"livestore.args": "{
|
|
39
|
+
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)"
|
|
40
|
+
}",
|
|
41
|
+
"livestore.mutation": "livestore.RawSql",
|
|
42
|
+
},
|
|
43
|
+
"children": [
|
|
44
|
+
{
|
|
45
|
+
"_name": "livestore.in-memory-db:execute",
|
|
46
|
+
"attributes": {
|
|
47
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"_name": "LiveStore:queries",
|
|
60
|
+
"children": [
|
|
61
|
+
{
|
|
62
|
+
"_name": "db:select * from todos",
|
|
63
|
+
"attributes": {
|
|
64
|
+
"sql.query": "select * from todos",
|
|
65
|
+
"sql.rowsCount": 0,
|
|
66
|
+
},
|
|
67
|
+
"children": [
|
|
68
|
+
{
|
|
69
|
+
"_name": "sql-in-memory-select",
|
|
70
|
+
"attributes": {
|
|
71
|
+
"sql.cached": false,
|
|
72
|
+
"sql.query": "select * from todos",
|
|
73
|
+
"sql.rowsCount": 0,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"_name": "db:select * from todos",
|
|
80
|
+
"attributes": {
|
|
81
|
+
"sql.query": "select * from todos",
|
|
82
|
+
"sql.rowsCount": 1,
|
|
83
|
+
},
|
|
84
|
+
"children": [
|
|
85
|
+
{
|
|
86
|
+
"_name": "sql-in-memory-select",
|
|
87
|
+
"attributes": {
|
|
88
|
+
"sql.cached": false,
|
|
89
|
+
"sql.query": "select * from todos",
|
|
90
|
+
"sql.rowsCount": 1,
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
exports[`otel > with thunks 3`] = `
|
|
102
|
+
{
|
|
103
|
+
"_name": "test",
|
|
104
|
+
"children": [
|
|
105
|
+
{
|
|
106
|
+
"_name": "livestore.in-memory-db:execute",
|
|
107
|
+
"attributes": {
|
|
108
|
+
"sql.query": "
|
|
109
|
+
PRAGMA page_size=32768;
|
|
110
|
+
PRAGMA cache_size=10000;
|
|
111
|
+
PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
|
|
112
|
+
PRAGMA synchronous='OFF';
|
|
113
|
+
PRAGMA temp_store='MEMORY';
|
|
114
|
+
PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
|
|
115
|
+
",
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"_name": "LiveStore:mutations",
|
|
120
|
+
"children": [
|
|
121
|
+
{
|
|
122
|
+
"_name": "LiveStore:mutate",
|
|
123
|
+
"attributes": {
|
|
124
|
+
"livestore.mutateLabel": "mutate",
|
|
125
|
+
},
|
|
126
|
+
"children": [
|
|
127
|
+
{
|
|
128
|
+
"_name": "LiveStore:processWrites",
|
|
129
|
+
"attributes": {
|
|
130
|
+
"livestore.mutateLabel": "mutate",
|
|
131
|
+
},
|
|
132
|
+
"children": [
|
|
133
|
+
{
|
|
134
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
135
|
+
"attributes": {
|
|
136
|
+
"livestore.args": "{
|
|
137
|
+
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)"
|
|
138
|
+
}",
|
|
139
|
+
"livestore.mutation": "livestore.RawSql",
|
|
140
|
+
},
|
|
141
|
+
"children": [
|
|
142
|
+
{
|
|
143
|
+
"_name": "livestore.in-memory-db:execute",
|
|
144
|
+
"attributes": {
|
|
145
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"_name": "LiveStore:queries",
|
|
158
|
+
"children": [
|
|
159
|
+
{
|
|
160
|
+
"_name": "db:select * from todos where completed = 0",
|
|
161
|
+
"attributes": {
|
|
162
|
+
"sql.query": "select * from todos where completed = 0",
|
|
163
|
+
"sql.rowsCount": 0,
|
|
164
|
+
},
|
|
165
|
+
"children": [
|
|
166
|
+
{
|
|
167
|
+
"_name": "js:where-filter",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"_name": "sql-in-memory-select",
|
|
171
|
+
"attributes": {
|
|
172
|
+
"sql.cached": false,
|
|
173
|
+
"sql.query": "select * from todos where completed = 0",
|
|
174
|
+
"sql.rowsCount": 0,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"_name": "db:select * from todos where completed = 0",
|
|
181
|
+
"attributes": {
|
|
182
|
+
"sql.query": "select * from todos where completed = 0",
|
|
183
|
+
"sql.rowsCount": 1,
|
|
184
|
+
},
|
|
185
|
+
"children": [
|
|
186
|
+
{
|
|
187
|
+
"_name": "sql-in-memory-select",
|
|
188
|
+
"attributes": {
|
|
189
|
+
"sql.cached": false,
|
|
190
|
+
"sql.query": "select * from todos where completed = 0",
|
|
191
|
+
"sql.rowsCount": 1,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
}
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
exports[`otel > with thunks with query builder and without labels 3`] = `
|
|
203
|
+
{
|
|
204
|
+
"_name": "test",
|
|
205
|
+
"children": [
|
|
206
|
+
{
|
|
207
|
+
"_name": "livestore.in-memory-db:execute",
|
|
208
|
+
"attributes": {
|
|
209
|
+
"sql.query": "
|
|
210
|
+
PRAGMA page_size=32768;
|
|
211
|
+
PRAGMA cache_size=10000;
|
|
212
|
+
PRAGMA journal_mode='MEMORY'; -- we don't flush to disk before committing a write
|
|
213
|
+
PRAGMA synchronous='OFF';
|
|
214
|
+
PRAGMA temp_store='MEMORY';
|
|
215
|
+
PRAGMA foreign_keys='ON'; -- we want foreign key constraints to be enforced
|
|
216
|
+
",
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"_name": "LiveStore:mutations",
|
|
221
|
+
"children": [
|
|
222
|
+
{
|
|
223
|
+
"_name": "LiveStore:mutate",
|
|
224
|
+
"attributes": {
|
|
225
|
+
"livestore.mutateLabel": "mutate",
|
|
226
|
+
},
|
|
227
|
+
"children": [
|
|
228
|
+
{
|
|
229
|
+
"_name": "LiveStore:processWrites",
|
|
230
|
+
"attributes": {
|
|
231
|
+
"livestore.mutateLabel": "mutate",
|
|
232
|
+
},
|
|
233
|
+
"children": [
|
|
234
|
+
{
|
|
235
|
+
"_name": "LiveStore:mutateWithoutRefresh",
|
|
236
|
+
"attributes": {
|
|
237
|
+
"livestore.args": "{
|
|
238
|
+
"sql": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)"
|
|
239
|
+
}",
|
|
240
|
+
"livestore.mutation": "livestore.RawSql",
|
|
241
|
+
},
|
|
242
|
+
"children": [
|
|
243
|
+
{
|
|
244
|
+
"_name": "livestore.in-memory-db:execute",
|
|
245
|
+
"attributes": {
|
|
246
|
+
"sql.query": "INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)",
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"_name": "LiveStore:queries",
|
|
259
|
+
"children": [
|
|
260
|
+
{
|
|
261
|
+
"_name": "db:SELECT * FROM 'todos' WHERE completed = ? LIMIT ?",
|
|
262
|
+
"attributes": {
|
|
263
|
+
"sql.query": "SELECT * FROM 'todos' WHERE completed = ? LIMIT ?",
|
|
264
|
+
"sql.rowsCount": 0,
|
|
265
|
+
},
|
|
266
|
+
"children": [
|
|
267
|
+
{
|
|
268
|
+
"_name": "js:() => ({ completed: false })",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"_name": "sql-in-memory-select",
|
|
272
|
+
"attributes": {
|
|
273
|
+
"sql.cached": false,
|
|
274
|
+
"sql.query": "SELECT * FROM 'todos' WHERE completed = ? LIMIT ?",
|
|
275
|
+
"sql.rowsCount": 0,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"_name": "db:SELECT * FROM 'todos' WHERE completed = ? LIMIT ?",
|
|
282
|
+
"attributes": {
|
|
283
|
+
"sql.query": "SELECT * FROM 'todos' WHERE completed = ? LIMIT ?",
|
|
284
|
+
"sql.rowsCount": 1,
|
|
285
|
+
},
|
|
286
|
+
"children": [
|
|
287
|
+
{
|
|
288
|
+
"_name": "sql-in-memory-select",
|
|
289
|
+
"attributes": {
|
|
290
|
+
"sql.cached": false,
|
|
291
|
+
"sql.query": "SELECT * FROM 'todos' WHERE completed = ? LIMIT ?",
|
|
292
|
+
"sql.rowsCount": 1,
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
}
|
|
301
|
+
`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { QueryInfo
|
|
1
|
+
import type { QueryInfo } from '@livestore/common'
|
|
2
2
|
import type * as otel from '@opentelemetry/api'
|
|
3
3
|
|
|
4
4
|
import { type Atom, type GetAtom, ReactiveGraph, throwContextNotSetError, type Thunk } from '../reactive.js'
|
|
@@ -27,9 +27,13 @@ let queryIdCounter = 0
|
|
|
27
27
|
|
|
28
28
|
export type LiveQueryAny = LiveQuery<any, QueryInfo>
|
|
29
29
|
|
|
30
|
-
export
|
|
30
|
+
export const TypeId = Symbol.for('LiveQuery')
|
|
31
|
+
export type TypeId = typeof TypeId
|
|
32
|
+
|
|
33
|
+
export interface LiveQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> {
|
|
31
34
|
id: number
|
|
32
|
-
_tag: 'computed' | '
|
|
35
|
+
_tag: 'computed' | 'db' | 'graphql'
|
|
36
|
+
[TypeId]: TypeId
|
|
33
37
|
|
|
34
38
|
/** This should only be used on a type-level and doesn't hold any value during runtime */
|
|
35
39
|
'__result!': TResult
|
|
@@ -64,8 +68,9 @@ export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
|
|
|
64
68
|
implements LiveQuery<TResult, TQueryInfo>
|
|
65
69
|
{
|
|
66
70
|
'__result!'!: TResult
|
|
67
|
-
id = queryIdCounter
|
|
68
|
-
|
|
71
|
+
id = queryIdCounter++;
|
|
72
|
+
[TypeId]: TypeId = TypeId
|
|
73
|
+
abstract _tag: 'computed' | 'db' | 'graphql'
|
|
69
74
|
|
|
70
75
|
/** Human-readable label for the query for debugging */
|
|
71
76
|
abstract label: string
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { QueryInfo
|
|
1
|
+
import type { QueryInfo } from '@livestore/common'
|
|
2
2
|
import * as otel from '@opentelemetry/api'
|
|
3
3
|
|
|
4
4
|
import { globalReactivityGraph } from '../global-state.js'
|
|
@@ -8,7 +8,7 @@ import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
|
8
8
|
import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
|
|
9
9
|
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
10
10
|
|
|
11
|
-
export const computed = <TResult, TQueryInfo extends QueryInfo =
|
|
11
|
+
export const computed = <TResult, TQueryInfo extends QueryInfo = QueryInfo.None>(
|
|
12
12
|
fn: (get: GetAtomResult) => TResult,
|
|
13
13
|
options?: {
|
|
14
14
|
label: string
|
|
@@ -16,14 +16,14 @@ export const computed = <TResult, TQueryInfo extends QueryInfo = QueryInfoNone>(
|
|
|
16
16
|
queryInfo?: TQueryInfo
|
|
17
17
|
},
|
|
18
18
|
): LiveQuery<TResult, TQueryInfo> =>
|
|
19
|
-
new
|
|
19
|
+
new LiveStoreComputedQuery<TResult, TQueryInfo>({
|
|
20
20
|
fn,
|
|
21
21
|
label: options?.label ?? fn.toString(),
|
|
22
22
|
reactivityGraph: options?.reactivityGraph,
|
|
23
23
|
queryInfo: options?.queryInfo,
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
export class
|
|
26
|
+
export class LiveStoreComputedQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo.None> extends LiveStoreQueryBase<
|
|
27
27
|
TResult,
|
|
28
28
|
TQueryInfo
|
|
29
29
|
> {
|
|
@@ -38,31 +38,19 @@ export class LiveStoreJSQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoN
|
|
|
38
38
|
|
|
39
39
|
queryInfo: TQueryInfo
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* Currently only used for "nested destruction" of piped queries
|
|
43
|
-
*
|
|
44
|
-
* i.e. when doing something like `const q = querySQL(...).pipe(...)`
|
|
45
|
-
* we need to also destory the SQL query when the JS query `q` is destroyed
|
|
46
|
-
*/
|
|
47
|
-
private onDestroy: (() => void) | undefined
|
|
48
|
-
|
|
49
41
|
constructor({
|
|
50
42
|
fn,
|
|
51
43
|
label,
|
|
52
|
-
onDestroy,
|
|
53
44
|
reactivityGraph,
|
|
54
45
|
queryInfo,
|
|
55
46
|
}: {
|
|
56
47
|
label: string
|
|
57
48
|
fn: (get: GetAtomResult) => TResult
|
|
58
|
-
/** Currently only used for "nested destruction" of piped queries */
|
|
59
|
-
onDestroy?: () => void
|
|
60
49
|
reactivityGraph?: ReactivityGraph
|
|
61
50
|
queryInfo?: TQueryInfo
|
|
62
51
|
}) {
|
|
63
52
|
super()
|
|
64
53
|
|
|
65
|
-
this.onDestroy = onDestroy
|
|
66
54
|
this.label = label
|
|
67
55
|
|
|
68
56
|
this.reactivityGraph = reactivityGraph ?? globalReactivityGraph
|
|
@@ -86,23 +74,11 @@ export class LiveStoreJSQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoN
|
|
|
86
74
|
|
|
87
75
|
return res
|
|
88
76
|
}),
|
|
89
|
-
{ label: queryLabel, meta: { liveStoreThunkType: '
|
|
77
|
+
{ label: queryLabel, meta: { liveStoreThunkType: 'computedResults' } },
|
|
90
78
|
)
|
|
91
79
|
}
|
|
92
80
|
|
|
93
|
-
// pipe = <U>(fn: (result: TResult, get: GetAtomResult) => U): LiveStoreJSQuery<U> =>
|
|
94
|
-
// new LiveStoreJSQuery({
|
|
95
|
-
// fn: (get) => {
|
|
96
|
-
// const results = get(this.results$)
|
|
97
|
-
// return fn(results, get)
|
|
98
|
-
// },
|
|
99
|
-
// label: `${this.label}:js`,
|
|
100
|
-
// onDestroy: () => this.destroy(),
|
|
101
|
-
// reactivityGraph: this.reactivityGraph,
|
|
102
|
-
// })
|
|
103
|
-
|
|
104
81
|
destroy = () => {
|
|
105
82
|
this.reactivityGraph.destroyNode(this.results$)
|
|
106
|
-
this.onDestroy?.()
|
|
107
83
|
}
|
|
108
84
|
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Effect, Schema } from '@livestore/utils/effect'
|
|
2
|
+
import * as otel from '@opentelemetry/api'
|
|
3
|
+
import { BasicTracerProvider, InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
import { computed, queryDb, rawSqlMutation, sql } from '../index.js'
|
|
7
|
+
import { makeTodoMvc, tables } from '../utils/tests/fixture.js'
|
|
8
|
+
import { getSimplifiedRootSpan } from '../utils/tests/otel.js'
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
TODO write tests for:
|
|
12
|
+
|
|
13
|
+
- sql queries without and with `map` (incl. callback and schemas)
|
|
14
|
+
- optional and explicit `queriedTables` argument
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
describe('otel', () => {
|
|
18
|
+
let cachedProvider: BasicTracerProvider | undefined
|
|
19
|
+
|
|
20
|
+
const makeQuery = Effect.gen(function* () {
|
|
21
|
+
const exporter = new InMemorySpanExporter()
|
|
22
|
+
|
|
23
|
+
const provider = cachedProvider ?? new BasicTracerProvider()
|
|
24
|
+
cachedProvider = provider
|
|
25
|
+
provider.addSpanProcessor(new SimpleSpanProcessor(exporter))
|
|
26
|
+
provider.register()
|
|
27
|
+
|
|
28
|
+
const otelTracer = otel.trace.getTracer('test')
|
|
29
|
+
|
|
30
|
+
const span = otelTracer.startSpan('test')
|
|
31
|
+
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
32
|
+
|
|
33
|
+
const { store } = yield* makeTodoMvc({ otelTracer, otelContext })
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
store,
|
|
37
|
+
otelTracer,
|
|
38
|
+
exporter,
|
|
39
|
+
span,
|
|
40
|
+
provider,
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('otel', async () => {
|
|
45
|
+
const { exporter } = await Effect.gen(function* () {
|
|
46
|
+
const { store, exporter, span } = yield* makeQuery
|
|
47
|
+
|
|
48
|
+
const query$ = queryDb({
|
|
49
|
+
query: `select * from todos`,
|
|
50
|
+
schema: Schema.Array(tables.todos.schema),
|
|
51
|
+
queriedTables: new Set(['todos']),
|
|
52
|
+
})
|
|
53
|
+
expect(query$.run()).toMatchInlineSnapshot('[]')
|
|
54
|
+
|
|
55
|
+
store.mutate(rawSqlMutation({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
|
|
56
|
+
|
|
57
|
+
expect(query$.run()).toMatchInlineSnapshot(`
|
|
58
|
+
[
|
|
59
|
+
{
|
|
60
|
+
"completed": false,
|
|
61
|
+
"id": "t1",
|
|
62
|
+
"text": "buy milk",
|
|
63
|
+
},
|
|
64
|
+
]
|
|
65
|
+
`)
|
|
66
|
+
|
|
67
|
+
query$.destroy()
|
|
68
|
+
span.end()
|
|
69
|
+
|
|
70
|
+
return { exporter }
|
|
71
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise)
|
|
72
|
+
|
|
73
|
+
expect(getSimplifiedRootSpan(exporter)).toMatchSnapshot()
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('with thunks', async () => {
|
|
77
|
+
const { exporter } = await Effect.gen(function* () {
|
|
78
|
+
const { store, exporter, span } = yield* makeQuery
|
|
79
|
+
|
|
80
|
+
const defaultTodo = { id: '', text: '', completed: false }
|
|
81
|
+
|
|
82
|
+
const filter = computed(() => `where completed = 0`, { label: 'where-filter' })
|
|
83
|
+
const query$ = queryDb(
|
|
84
|
+
(get) => ({
|
|
85
|
+
query: `select * from todos ${get(filter)}`,
|
|
86
|
+
schema: Schema.Array(tables.todos.schema).pipe(Schema.headOrElse(() => defaultTodo)),
|
|
87
|
+
}),
|
|
88
|
+
{ label: 'all todos' },
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
expect(query$.run()).toMatchInlineSnapshot(`
|
|
92
|
+
{
|
|
93
|
+
"completed": false,
|
|
94
|
+
"id": "",
|
|
95
|
+
"text": "",
|
|
96
|
+
}
|
|
97
|
+
`)
|
|
98
|
+
|
|
99
|
+
store.mutate(rawSqlMutation({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
|
|
100
|
+
|
|
101
|
+
expect(query$.run()).toMatchInlineSnapshot(`
|
|
102
|
+
{
|
|
103
|
+
"completed": false,
|
|
104
|
+
"id": "t1",
|
|
105
|
+
"text": "buy milk",
|
|
106
|
+
}
|
|
107
|
+
`)
|
|
108
|
+
|
|
109
|
+
query$.destroy()
|
|
110
|
+
span.end()
|
|
111
|
+
|
|
112
|
+
return { exporter }
|
|
113
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise)
|
|
114
|
+
|
|
115
|
+
expect(getSimplifiedRootSpan(exporter)).toMatchSnapshot()
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('with thunks with query builder and without labels', async () => {
|
|
119
|
+
const { exporter } = await Effect.gen(function* () {
|
|
120
|
+
const { store, exporter, span } = yield* makeQuery
|
|
121
|
+
|
|
122
|
+
const defaultTodo = { id: '', text: '', completed: false }
|
|
123
|
+
|
|
124
|
+
const filter = computed(() => ({ completed: false }))
|
|
125
|
+
const query$ = queryDb((get) => tables.todos.query.where(get(filter)).first({ fallback: () => defaultTodo }))
|
|
126
|
+
|
|
127
|
+
expect(query$.run()).toMatchInlineSnapshot(`
|
|
128
|
+
{
|
|
129
|
+
"completed": false,
|
|
130
|
+
"id": "",
|
|
131
|
+
"text": "",
|
|
132
|
+
}
|
|
133
|
+
`)
|
|
134
|
+
|
|
135
|
+
store.mutate(rawSqlMutation({ sql: sql`INSERT INTO todos (id, text, completed) VALUES ('t1', 'buy milk', 0)` }))
|
|
136
|
+
|
|
137
|
+
expect(query$.run()).toMatchInlineSnapshot(`
|
|
138
|
+
{
|
|
139
|
+
"completed": false,
|
|
140
|
+
"id": "t1",
|
|
141
|
+
"text": "buy milk",
|
|
142
|
+
}
|
|
143
|
+
`)
|
|
144
|
+
|
|
145
|
+
query$.destroy()
|
|
146
|
+
span.end()
|
|
147
|
+
|
|
148
|
+
return { exporter }
|
|
149
|
+
}).pipe(Effect.scoped, Effect.tapCauseLogPretty, Effect.runPromise)
|
|
150
|
+
|
|
151
|
+
expect(getSimplifiedRootSpan(exporter)).toMatchSnapshot()
|
|
152
|
+
})
|
|
153
|
+
})
|