@livestore/livestore 0.0.41-dev.2 → 0.0.42-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/dist/.tsbuildinfo +1 -1
- package/dist/{inMemoryDatabase.d.ts → MainDatabaseWrapper.d.ts} +11 -18
- package/dist/MainDatabaseWrapper.d.ts.map +1 -0
- package/dist/{inMemoryDatabase.js → MainDatabaseWrapper.js} +26 -72
- package/dist/MainDatabaseWrapper.js.map +1 -0
- package/dist/__tests__/react/fixture.d.ts +41 -40
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +2 -8
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/cud.d.ts +9 -9
- package/dist/cud.d.ts.map +1 -1
- package/dist/cud.js +7 -8
- package/dist/cud.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +10 -10
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +2 -11
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/global-state.d.ts +2 -2
- package/dist/global-state.d.ts.map +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 +4 -3
- package/dist/index.js.map +1 -1
- package/dist/migrations.d.ts +5 -5
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +37 -21
- package/dist/migrations.js.map +1 -1
- package/dist/query-info.d.ts +8 -9
- package/dist/query-info.d.ts.map +1 -1
- package/dist/query-info.js +1 -1
- package/dist/query-info.js.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +7 -7
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js +11 -19
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/useRow.d.ts +6 -6
- package/dist/react/useRow.d.ts.map +1 -1
- package/dist/react/useRow.js +2 -2
- package/dist/react/useRow.js.map +1 -1
- package/dist/reactiveQueries/sql.js +2 -2
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/reactiveQueries/sql.test.js +12 -31
- package/dist/reactiveQueries/sql.test.js.map +1 -1
- package/dist/row-query.d.ts +6 -6
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +9 -12
- package/dist/row-query.js.map +1 -1
- package/dist/store.d.ts +18 -18
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +80 -86
- package/dist/store.js.map +1 -1
- package/dist/utils/bounded-collections.d.ts +1 -1
- package/dist/utils/bounded-collections.d.ts.map +1 -1
- package/dist/utils/bounded-collections.js +2 -1
- package/dist/utils/bounded-collections.js.map +1 -1
- package/dist/utils/util.d.ts +0 -16
- package/dist/utils/util.d.ts.map +1 -1
- package/dist/utils/util.js +0 -38
- package/dist/utils/util.js.map +1 -1
- package/package.json +8 -44
- package/src/{inMemoryDatabase.ts → MainDatabaseWrapper.ts} +40 -94
- package/src/__tests__/react/fixture.tsx +3 -9
- package/src/cud.ts +17 -16
- package/src/effect/LiveStore.ts +12 -24
- package/src/global-state.ts +3 -2
- package/src/index.ts +7 -23
- package/src/migrations.ts +51 -34
- package/src/query-info.ts +10 -9
- package/src/react/LiveStoreProvider.tsx +19 -27
- package/src/react/useRow.ts +24 -12
- package/src/reactiveQueries/sql.test.ts +12 -31
- package/src/reactiveQueries/sql.ts +2 -2
- package/src/row-query.ts +32 -29
- package/src/store.ts +98 -103
- package/src/utils/bounded-collections.ts +3 -2
- package/src/utils/util.ts +0 -44
- package/tsconfig.json +1 -1
- package/vitest.config.js +4 -0
- package/dist/inMemoryDatabase.d.ts.map +0 -1
- package/dist/inMemoryDatabase.js.map +0 -1
- package/dist/schema/index.d.ts +0 -42
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js +0 -42
- package/dist/schema/index.js.map +0 -1
- package/dist/schema/mutations.d.ts +0 -81
- package/dist/schema/mutations.d.ts.map +0 -1
- package/dist/schema/mutations.js +0 -29
- package/dist/schema/mutations.js.map +0 -1
- package/dist/schema/parse-utils.d.ts +0 -6
- package/dist/schema/parse-utils.d.ts.map +0 -1
- package/dist/schema/parse-utils.js +0 -22
- package/dist/schema/parse-utils.js.map +0 -1
- package/dist/schema/system-tables.d.ts +0 -76
- package/dist/schema/system-tables.d.ts.map +0 -1
- package/dist/schema/system-tables.js +0 -11
- package/dist/schema/system-tables.js.map +0 -1
- package/dist/schema/table-def.d.ts +0 -100
- package/dist/schema/table-def.d.ts.map +0 -1
- package/dist/schema/table-def.js +0 -70
- package/dist/schema/table-def.js.map +0 -1
- package/dist/storage/in-memory/index.d.ts +0 -19
- package/dist/storage/in-memory/index.d.ts.map +0 -1
- package/dist/storage/in-memory/index.js +0 -16
- package/dist/storage/in-memory/index.js.map +0 -1
- package/dist/storage/index.d.ts +0 -18
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -9
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/tauri/index.d.ts +0 -23
- package/dist/storage/tauri/index.d.ts.map +0 -1
- package/dist/storage/tauri/index.js +0 -46
- package/dist/storage/tauri/index.js.map +0 -1
- package/dist/storage/utils/idb.d.ts +0 -11
- package/dist/storage/utils/idb.d.ts.map +0 -1
- package/dist/storage/utils/idb.js +0 -71
- package/dist/storage/utils/idb.js.map +0 -1
- package/dist/storage/web-worker/common.d.ts +0 -11
- package/dist/storage/web-worker/common.d.ts.map +0 -1
- package/dist/storage/web-worker/common.js +0 -2
- package/dist/storage/web-worker/common.js.map +0 -1
- package/dist/storage/web-worker/index.d.ts +0 -34
- package/dist/storage/web-worker/index.d.ts.map +0 -1
- package/dist/storage/web-worker/index.js +0 -134
- package/dist/storage/web-worker/index.js.map +0 -1
- package/dist/storage/web-worker/make-worker.d.ts +0 -20
- package/dist/storage/web-worker/make-worker.d.ts.map +0 -1
- package/dist/storage/web-worker/make-worker.js +0 -155
- package/dist/storage/web-worker/make-worker.js.map +0 -1
- package/dist/storage/web-worker/vite-dev-polyfill.d.ts +0 -2
- package/dist/storage/web-worker/vite-dev-polyfill.d.ts.map +0 -1
- package/dist/storage/web-worker/vite-dev-polyfill.js +0 -35
- package/dist/storage/web-worker/vite-dev-polyfill.js.map +0 -1
- package/src/schema/index.ts +0 -100
- package/src/schema/mutations.ts +0 -128
- package/src/schema/parse-utils.ts +0 -42
- package/src/schema/system-tables.ts +0 -21
- package/src/schema/table-def.ts +0 -270
- package/src/storage/in-memory/index.ts +0 -28
- package/src/storage/index.ts +0 -36
- package/src/storage/tauri/index.ts +0 -66
- package/src/storage/utils/idb.ts +0 -85
- package/src/storage/web-worker/common.ts +0 -6
- package/src/storage/web-worker/index.ts +0 -185
- package/src/storage/web-worker/make-worker.ts +0 -214
- package/src/storage/web-worker/vite-dev-polyfill.ts +0 -33
package/src/query-info.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
+
import { type DbSchema, rawSqlMutation, type RawSqlMutationEvent } from '@livestore/common/schema'
|
|
1
2
|
import { notYetImplemented, shouldNeverHappen } from '@livestore/utils'
|
|
2
3
|
import { Schema } from '@livestore/utils/effect'
|
|
3
4
|
|
|
4
|
-
import { rawSqlMutation, type RawSqlMutationEvent } from './schema/mutations.js'
|
|
5
|
-
import type { FromTable, TableDef } from './schema/table-def.js'
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* Semantic information about a query with supported cases being:
|
|
9
7
|
* - a whole row
|
|
10
8
|
* - a single column value
|
|
11
9
|
* - a sub value in a JSON column
|
|
12
10
|
*/
|
|
13
|
-
export type QueryInfo<TTableDef extends TableDef = TableDef> =
|
|
11
|
+
export type QueryInfo<TTableDef extends DbSchema.TableDef = DbSchema.TableDef> =
|
|
14
12
|
| QueryInfoNone
|
|
15
13
|
| QueryInfoRow<TTableDef>
|
|
16
14
|
| QueryInfoColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
|
|
@@ -20,20 +18,23 @@ export type QueryInfoNone = {
|
|
|
20
18
|
_tag: 'None'
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
export type QueryInfoRow<TTableDef extends TableDef> = {
|
|
21
|
+
export type QueryInfoRow<TTableDef extends DbSchema.TableDef> = {
|
|
24
22
|
_tag: 'Row'
|
|
25
23
|
table: TTableDef
|
|
26
24
|
id: string
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
export type QueryInfoCol<
|
|
27
|
+
export type QueryInfoCol<
|
|
28
|
+
TTableDef extends DbSchema.TableDef,
|
|
29
|
+
TColName extends keyof TTableDef['sqliteDef']['columns'],
|
|
30
|
+
> = {
|
|
30
31
|
_tag: 'Col'
|
|
31
32
|
table: TTableDef
|
|
32
33
|
id: string
|
|
33
34
|
column: TColName
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
export type QueryInfoColJsonValue<TTableDef extends TableDef, TColName extends GetJsonColumn<TTableDef>> = {
|
|
37
|
+
export type QueryInfoColJsonValue<TTableDef extends DbSchema.TableDef, TColName extends GetJsonColumn<TTableDef>> = {
|
|
37
38
|
_tag: 'ColJsonValue'
|
|
38
39
|
table: TTableDef
|
|
39
40
|
id: string
|
|
@@ -44,14 +45,14 @@ export type QueryInfoColJsonValue<TTableDef extends TableDef, TColName extends G
|
|
|
44
45
|
jsonPath: string
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
type GetJsonColumn<TTableDef extends TableDef> = keyof {
|
|
48
|
+
type GetJsonColumn<TTableDef extends DbSchema.TableDef> = keyof {
|
|
48
49
|
[ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
|
|
49
50
|
? ColName
|
|
50
51
|
: never]: {}
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
export type UpdateValueForPath<TPath extends QueryInfo> = TPath extends { _tag: 'Row' }
|
|
54
|
-
? Partial<FromTable.RowDecodedAll<TPath['table']>>
|
|
55
|
+
? Partial<DbSchema.FromTable.RowDecodedAll<TPath['table']>>
|
|
55
56
|
: TPath extends { _tag: 'Col' }
|
|
56
57
|
? Schema.Schema.To<TPath['table']['sqliteDef']['columns'][TPath['column']]['schema']>
|
|
57
58
|
: TPath extends { _tag: 'ColJsonValue' }
|
|
@@ -1,70 +1,65 @@
|
|
|
1
|
+
import type { DatabaseFactory } from '@livestore/common'
|
|
2
|
+
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
1
3
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
4
|
import type * as otel from '@opentelemetry/api'
|
|
3
5
|
import type { ReactElement, ReactNode } from 'react'
|
|
4
6
|
import React from 'react'
|
|
5
|
-
import initSqlite3Wasm from 'sqlite-esm'
|
|
6
7
|
|
|
7
8
|
// TODO refactor so the `react` module doesn't depend on `effect` module
|
|
8
9
|
import type { LiveStoreContext as StoreContext_, LiveStoreCreateStoreOptions } from '../effect/LiveStore.js'
|
|
9
|
-
import type {
|
|
10
|
-
import type { LiveStoreSchema } from '../schema/index.js'
|
|
11
|
-
import type { StorageInit } from '../storage/index.js'
|
|
12
|
-
import type { BaseGraphQLContext, GraphQLOptions, Store } from '../store.js'
|
|
10
|
+
import type { BaseGraphQLContext, BootDb, GraphQLOptions, Store } from '../store.js'
|
|
13
11
|
import { createStore } from '../store.js'
|
|
14
12
|
import { LiveStoreContext } from './LiveStoreContext.js'
|
|
15
13
|
|
|
16
|
-
// NOTE we're starting to initialize the sqlite wasm binary here (already before calling `createStore`),
|
|
17
|
-
// so that it's ready when we need it
|
|
18
|
-
const sqlite3Promise = initSqlite3Wasm({
|
|
19
|
-
print: (message) => console.log(`[livestore sqlite] ${message}`),
|
|
20
|
-
printErr: (message) => console.error(`[livestore sqlite] ${message}`),
|
|
21
|
-
})
|
|
22
|
-
|
|
23
14
|
interface LiveStoreProviderProps<GraphQLContext> {
|
|
24
15
|
schema: LiveStoreSchema
|
|
25
|
-
|
|
26
|
-
boot?: (db: InMemoryDatabase, parentSpan: otel.Span) => unknown | Promise<unknown>
|
|
16
|
+
boot?: (db: BootDb, parentSpan: otel.Span) => unknown | Promise<unknown>
|
|
27
17
|
graphQLOptions?: GraphQLOptions<GraphQLContext>
|
|
28
18
|
otelTracer?: otel.Tracer
|
|
29
19
|
otelRootSpanContext?: otel.Context
|
|
30
20
|
fallback: ReactElement
|
|
21
|
+
makeDb: DatabaseFactory
|
|
22
|
+
batchUpdates?: (run: () => void) => void
|
|
31
23
|
}
|
|
32
24
|
|
|
33
25
|
export const LiveStoreProvider = <GraphQLContext extends BaseGraphQLContext>({
|
|
34
26
|
fallback,
|
|
35
|
-
loadStorage,
|
|
36
27
|
graphQLOptions,
|
|
37
28
|
otelTracer,
|
|
38
29
|
otelRootSpanContext,
|
|
39
30
|
children,
|
|
40
31
|
schema,
|
|
41
32
|
boot,
|
|
33
|
+
makeDb,
|
|
34
|
+
batchUpdates,
|
|
42
35
|
}: LiveStoreProviderProps<GraphQLContext> & { children?: ReactNode }): JSX.Element => {
|
|
43
|
-
const
|
|
36
|
+
const storeCtx = useCreateStore({
|
|
44
37
|
schema,
|
|
45
|
-
loadStorage,
|
|
46
38
|
graphQLOptions,
|
|
47
39
|
otelTracer,
|
|
48
40
|
otelRootSpanContext,
|
|
49
41
|
boot,
|
|
42
|
+
makeDb,
|
|
43
|
+
batchUpdates,
|
|
50
44
|
})
|
|
51
45
|
|
|
52
|
-
if (
|
|
46
|
+
if (storeCtx === undefined) {
|
|
53
47
|
return fallback
|
|
54
48
|
}
|
|
55
49
|
|
|
56
|
-
window.__debugLiveStore =
|
|
50
|
+
window.__debugLiveStore = storeCtx.store
|
|
57
51
|
|
|
58
|
-
return <LiveStoreContext.Provider value={
|
|
52
|
+
return <LiveStoreContext.Provider value={storeCtx}>{children}</LiveStoreContext.Provider>
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
62
56
|
schema,
|
|
63
|
-
loadStorage,
|
|
64
57
|
graphQLOptions,
|
|
65
58
|
otelTracer,
|
|
66
59
|
otelRootSpanContext,
|
|
67
60
|
boot,
|
|
61
|
+
makeDb,
|
|
62
|
+
batchUpdates,
|
|
68
63
|
}: LiveStoreCreateStoreOptions<GraphQLContext>) => {
|
|
69
64
|
const [ctxValue, setCtxValue] = React.useState<StoreContext_ | undefined>()
|
|
70
65
|
|
|
@@ -76,15 +71,14 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
76
71
|
|
|
77
72
|
void (async () => {
|
|
78
73
|
try {
|
|
79
|
-
const sqlite3 = await sqlite3Promise
|
|
80
74
|
store = await createStore({
|
|
81
75
|
schema,
|
|
82
|
-
loadStorage,
|
|
83
76
|
graphQLOptions,
|
|
84
77
|
otelTracer,
|
|
85
78
|
otelRootSpanContext,
|
|
86
79
|
boot,
|
|
87
|
-
|
|
80
|
+
makeDb,
|
|
81
|
+
batchUpdates,
|
|
88
82
|
})
|
|
89
83
|
setCtxValue({ store })
|
|
90
84
|
} catch (e) {
|
|
@@ -95,9 +89,7 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
95
89
|
return () => {
|
|
96
90
|
store?.destroy()
|
|
97
91
|
}
|
|
98
|
-
|
|
99
|
-
// TODO: do we need to return any cleanup function here?
|
|
100
|
-
}, [schema, loadStorage, graphQLOptions, otelTracer, otelRootSpanContext, boot])
|
|
92
|
+
}, [schema, graphQLOptions, otelTracer, otelRootSpanContext, boot, makeDb, batchUpdates])
|
|
101
93
|
|
|
102
94
|
return ctxValue
|
|
103
95
|
}
|
package/src/react/useRow.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DbSchema } from '@livestore/common/schema'
|
|
1
2
|
import * as otel from '@opentelemetry/api'
|
|
2
3
|
import type { SqliteDsl } from 'effect-db-schema'
|
|
3
4
|
import { mapValues } from 'lodash-es'
|
|
@@ -8,18 +9,17 @@ import type { QueryInfo } from '../query-info.js'
|
|
|
8
9
|
import { mutationForQueryInfo } from '../query-info.js'
|
|
9
10
|
import type { RowResult } from '../row-query.js'
|
|
10
11
|
import { rowQuery } from '../row-query.js'
|
|
11
|
-
import { type DefaultSqliteTableDef, type TableDef, tableIsSingleton, type TableOptions } from '../schema/table-def.js'
|
|
12
12
|
import { useStore } from './LiveStoreContext.js'
|
|
13
13
|
import { useQueryRef } from './useQuery.js'
|
|
14
14
|
import { useCleanup } from './utils/useCleanup.js'
|
|
15
15
|
|
|
16
|
-
export type UseRowResult<TTableDef extends TableDef> = [
|
|
16
|
+
export type UseRowResult<TTableDef extends DbSchema.TableDef> = [
|
|
17
17
|
row: RowResult<TTableDef>,
|
|
18
18
|
setRow: StateSetters<TTableDef>,
|
|
19
19
|
query$: LiveQuery<RowResult<TTableDef>, QueryInfo>,
|
|
20
20
|
]
|
|
21
21
|
|
|
22
|
-
export type UseRowOptionsDefaulValues<TTableDef extends TableDef> = {
|
|
22
|
+
export type UseRowOptionsDefaulValues<TTableDef extends DbSchema.TableDef> = {
|
|
23
23
|
defaultValues?: Partial<RowResult<TTableDef>>
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -37,17 +37,29 @@ export type UseRowOptionsBase = {
|
|
|
37
37
|
* If the table is a singleton table, `useRow` can be called without an `id` argument. Otherwise, the `id` argument is required.
|
|
38
38
|
*/
|
|
39
39
|
export const useRow: {
|
|
40
|
-
<
|
|
40
|
+
<
|
|
41
|
+
TTableDef extends DbSchema.TableDef<
|
|
42
|
+
DbSchema.DefaultSqliteTableDef,
|
|
43
|
+
boolean,
|
|
44
|
+
DbSchema.TableOptions & { isSingleton: true }
|
|
45
|
+
>,
|
|
46
|
+
>(
|
|
41
47
|
table: TTableDef,
|
|
42
48
|
options?: UseRowOptionsBase,
|
|
43
49
|
): UseRowResult<TTableDef>
|
|
44
|
-
<
|
|
50
|
+
<
|
|
51
|
+
TTableDef extends DbSchema.TableDef<
|
|
52
|
+
DbSchema.DefaultSqliteTableDef,
|
|
53
|
+
boolean,
|
|
54
|
+
DbSchema.TableOptions & { isSingleton: false }
|
|
55
|
+
>,
|
|
56
|
+
>(
|
|
45
57
|
table: TTableDef,
|
|
46
58
|
// TODO adjust so it works with arbitrary primary keys or unique constraints
|
|
47
59
|
id: string,
|
|
48
60
|
options?: UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>,
|
|
49
61
|
): UseRowResult<TTableDef>
|
|
50
|
-
} = <TTableDef extends TableDef>(
|
|
62
|
+
} = <TTableDef extends DbSchema.TableDef>(
|
|
51
63
|
table: TTableDef,
|
|
52
64
|
idOrOptions?: string | UseRowOptionsBase,
|
|
53
65
|
options_?: UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>,
|
|
@@ -83,7 +95,7 @@ export const useRow: {
|
|
|
83
95
|
|
|
84
96
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
85
97
|
|
|
86
|
-
const query$ = tableIsSingleton(table)
|
|
98
|
+
const query$ = DbSchema.tableIsSingleton(table)
|
|
87
99
|
? (rowQuery(table, { otelContext, dbGraph }) as LiveQuery<RowResult<TTableDef>, QueryInfo>)
|
|
88
100
|
: (rowQuery(table as TTableDef & { options: { isSingleton: false } }, id!, {
|
|
89
101
|
otelContext,
|
|
@@ -160,7 +172,7 @@ export const useRow: {
|
|
|
160
172
|
export type Dispatch<A> = (action: A) => void
|
|
161
173
|
export type SetStateAction<S> = S | ((previousValue: S) => S)
|
|
162
174
|
|
|
163
|
-
export type StateSetters<TTableDef extends TableDef> = TTableDef['isSingleColumn'] extends true
|
|
175
|
+
export type StateSetters<TTableDef extends DbSchema.TableDef> = TTableDef['isSingleColumn'] extends true
|
|
164
176
|
? Dispatch<SetStateAction<RowResult<TTableDef>>>
|
|
165
177
|
: {
|
|
166
178
|
[K in keyof RowResult<TTableDef>]: Dispatch<SetStateAction<RowResult<TTableDef>[K]>>
|
|
@@ -171,7 +183,7 @@ export type StateSetters<TTableDef extends TableDef> = TTableDef['isSingleColumn
|
|
|
171
183
|
/** Reference counted cache for `query$` and otel context */
|
|
172
184
|
class RCCache {
|
|
173
185
|
private readonly cache = new Map<
|
|
174
|
-
TableDef,
|
|
186
|
+
DbSchema.TableDef,
|
|
175
187
|
Map<
|
|
176
188
|
string,
|
|
177
189
|
{
|
|
@@ -182,16 +194,16 @@ class RCCache {
|
|
|
182
194
|
}
|
|
183
195
|
>
|
|
184
196
|
>()
|
|
185
|
-
private reverseCache = new Map<LiveQuery<any, any>, [TableDef, string]>()
|
|
197
|
+
private reverseCache = new Map<LiveQuery<any, any>, [DbSchema.TableDef, string]>()
|
|
186
198
|
|
|
187
|
-
get = (table: TableDef, id: string) => {
|
|
199
|
+
get = (table: DbSchema.TableDef, id: string) => {
|
|
188
200
|
const queries = this.cache.get(table)
|
|
189
201
|
if (queries === undefined) return undefined
|
|
190
202
|
return queries.get(id)
|
|
191
203
|
}
|
|
192
204
|
|
|
193
205
|
set = (
|
|
194
|
-
table: TableDef,
|
|
206
|
+
table: DbSchema.TableDef,
|
|
195
207
|
id: string,
|
|
196
208
|
query$: LiveQuery<any, any>,
|
|
197
209
|
reactId: string,
|
|
@@ -31,11 +31,19 @@ describe('otel', () => {
|
|
|
31
31
|
|
|
32
32
|
const { store } = await makeTodoMvc({ otelTracer: tracer, otelContext })
|
|
33
33
|
|
|
34
|
-
return {
|
|
34
|
+
return {
|
|
35
|
+
[Symbol.dispose]: () => store.destroy(),
|
|
36
|
+
store,
|
|
37
|
+
tracer,
|
|
38
|
+
exporter,
|
|
39
|
+
span,
|
|
40
|
+
provider,
|
|
41
|
+
}
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
it('otel', async () => {
|
|
38
|
-
|
|
45
|
+
using inputs = await makeQuery()
|
|
46
|
+
const { store, exporter, span } = inputs
|
|
39
47
|
|
|
40
48
|
const query = querySQL(`select * from todos`, { queriedTables: new Set(['todos']) })
|
|
41
49
|
expect(query.run()).toMatchInlineSnapshot('[]')
|
|
@@ -73,20 +81,6 @@ describe('otel', () => {
|
|
|
73
81
|
",
|
|
74
82
|
},
|
|
75
83
|
},
|
|
76
|
-
{
|
|
77
|
-
"_name": "sql-in-memory-select",
|
|
78
|
-
"attributes": {
|
|
79
|
-
"sql.cached": false,
|
|
80
|
-
"sql.query": "SELECT * FROM __livestore_schema",
|
|
81
|
-
"sql.rowsCount": 0,
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"_name": "livestore.in-memory-db:execute",
|
|
86
|
-
"attributes": {
|
|
87
|
-
"sql.query": "INSERT OR IGNORE INTO app (id, newTodoText, filter) VALUES ('static', '', 'all');",
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
84
|
{
|
|
91
85
|
"_name": "LiveStore:mutations",
|
|
92
86
|
"children": [
|
|
@@ -170,7 +164,8 @@ describe('otel', () => {
|
|
|
170
164
|
})
|
|
171
165
|
|
|
172
166
|
it('with thunks', async () => {
|
|
173
|
-
|
|
167
|
+
using inputs = await makeQuery()
|
|
168
|
+
const { store, exporter, span } = inputs
|
|
174
169
|
|
|
175
170
|
const defaultTodo = { id: '', text: '', completed: false }
|
|
176
171
|
|
|
@@ -219,20 +214,6 @@ describe('otel', () => {
|
|
|
219
214
|
",
|
|
220
215
|
},
|
|
221
216
|
},
|
|
222
|
-
{
|
|
223
|
-
"_name": "sql-in-memory-select",
|
|
224
|
-
"attributes": {
|
|
225
|
-
"sql.cached": false,
|
|
226
|
-
"sql.query": "SELECT * FROM __livestore_schema",
|
|
227
|
-
"sql.rowsCount": 0,
|
|
228
|
-
},
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
"_name": "livestore.in-memory-db:execute",
|
|
232
|
-
"attributes": {
|
|
233
|
-
"sql.query": "INSERT OR IGNORE INTO app (id, newTodoText, filter) VALUES ('static', '', 'all');",
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
217
|
{
|
|
237
218
|
"_name": "LiveStore:mutations",
|
|
238
219
|
"children": [
|
|
@@ -147,7 +147,7 @@ export class LiveStoreSQLQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo
|
|
|
147
147
|
const sqlString = get(queryString$, otelContext)
|
|
148
148
|
|
|
149
149
|
if (queriedTablesRef.current === undefined) {
|
|
150
|
-
queriedTablesRef.current = store.
|
|
150
|
+
queriedTablesRef.current = store.mainDbWrapper.getTablesUsed(sqlString)
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
// Establish a reactive dependency on the tables used in the query
|
|
@@ -159,7 +159,7 @@ export class LiveStoreSQLQuery<TResult, TQueryInfo extends QueryInfo = QueryInfo
|
|
|
159
159
|
span.setAttribute('sql.query', sqlString)
|
|
160
160
|
span.updateName(`sql:${sqlString.slice(0, 50)}`)
|
|
161
161
|
|
|
162
|
-
const rawResults = store.
|
|
162
|
+
const rawResults = store.mainDbWrapper.select<any>(sqlString, {
|
|
163
163
|
queriedTables,
|
|
164
164
|
bindValues: bindValues ? prepareBindValues(bindValues, sqlString) : undefined,
|
|
165
165
|
otelContext,
|
package/src/row-query.ts
CHANGED
|
@@ -1,26 +1,19 @@
|
|
|
1
|
+
import { sql } from '@livestore/common'
|
|
2
|
+
import { DbSchema, SCHEMA_META_TABLE } from '@livestore/common/schema'
|
|
1
3
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
4
|
import { Schema, TreeFormatter } from '@livestore/utils/effect'
|
|
3
5
|
import type * as otel from '@opentelemetry/api'
|
|
4
6
|
import { SqliteAst, SqliteDsl } from 'effect-db-schema'
|
|
5
7
|
|
|
6
|
-
import { computed } from './index.js'
|
|
7
|
-
import type { InMemoryDatabase } from './inMemoryDatabase.js'
|
|
8
8
|
import { migrateTable } from './migrations.js'
|
|
9
9
|
import type { QueryInfoCol, QueryInfoNone, QueryInfoRow } from './query-info.js'
|
|
10
10
|
import type { Ref } from './reactive.js'
|
|
11
11
|
import type { DbContext, DbGraph, LiveQuery, LiveQueryAny } from './reactiveQueries/base-class.js'
|
|
12
|
+
import { computed } from './reactiveQueries/js.js'
|
|
12
13
|
// import type { LiveStoreJSQuery } from './reactiveQueries/js.js'
|
|
13
14
|
import { LiveStoreSQLQuery } from './reactiveQueries/sql.js'
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
type DefaultSqliteTableDef,
|
|
17
|
-
getDefaultValuesEncoded,
|
|
18
|
-
type TableDef,
|
|
19
|
-
type TableOptions,
|
|
20
|
-
} from './schema/table-def.js'
|
|
21
|
-
import type { RefreshReason } from './store.js'
|
|
15
|
+
import type { RefreshReason, Store } from './store.js'
|
|
22
16
|
import type { GetValForKey } from './utils/util.js'
|
|
23
|
-
import { prepareBindValues, sql } from './utils/util.js'
|
|
24
17
|
|
|
25
18
|
export type RowQueryOptions = {
|
|
26
19
|
otelContext?: otel.Context
|
|
@@ -28,16 +21,28 @@ export type RowQueryOptions = {
|
|
|
28
21
|
dbGraph?: DbGraph
|
|
29
22
|
}
|
|
30
23
|
|
|
31
|
-
export type RowQueryOptionsDefaulValues<TTableDef extends TableDef> = {
|
|
24
|
+
export type RowQueryOptionsDefaulValues<TTableDef extends DbSchema.TableDef> = {
|
|
32
25
|
defaultValues: Partial<RowResult<TTableDef>>
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
export type MakeRowQuery = {
|
|
36
|
-
<
|
|
29
|
+
<
|
|
30
|
+
TTableDef extends DbSchema.TableDef<
|
|
31
|
+
DbSchema.DefaultSqliteTableDef,
|
|
32
|
+
boolean,
|
|
33
|
+
DbSchema.TableOptions & { isSingleton: true }
|
|
34
|
+
>,
|
|
35
|
+
>(
|
|
37
36
|
table: TTableDef,
|
|
38
37
|
options?: RowQueryOptions,
|
|
39
38
|
): LiveQuery<RowResult<TTableDef>, QueryInfoRow<TTableDef>>
|
|
40
|
-
<
|
|
39
|
+
<
|
|
40
|
+
TTableDef extends DbSchema.TableDef<
|
|
41
|
+
DbSchema.DefaultSqliteTableDef,
|
|
42
|
+
boolean,
|
|
43
|
+
DbSchema.TableOptions & { isSingleton: false }
|
|
44
|
+
>,
|
|
45
|
+
>(
|
|
41
46
|
table: TTableDef,
|
|
42
47
|
// TODO adjust so it works with arbitrary primary keys or unique constraints
|
|
43
48
|
id: string,
|
|
@@ -46,7 +51,7 @@ export type MakeRowQuery = {
|
|
|
46
51
|
}
|
|
47
52
|
|
|
48
53
|
// TODO also allow other where clauses and multiple rows
|
|
49
|
-
export const rowQuery: MakeRowQuery = <TTableDef extends TableDef>(
|
|
54
|
+
export const rowQuery: MakeRowQuery = <TTableDef extends DbSchema.TableDef>(
|
|
50
55
|
table: TTableDef,
|
|
51
56
|
idOrOptions?: string | RowQueryOptions,
|
|
52
57
|
options_?: RowQueryOptions & RowQueryOptionsDefaulValues<TTableDef>,
|
|
@@ -98,11 +103,11 @@ export const rowQuery: MakeRowQuery = <TTableDef extends TableDef>(
|
|
|
98
103
|
})
|
|
99
104
|
}
|
|
100
105
|
|
|
101
|
-
export type RowResult<TTableDef extends TableDef> = TTableDef['isSingleColumn'] extends true
|
|
106
|
+
export type RowResult<TTableDef extends DbSchema.TableDef> = TTableDef['isSingleColumn'] extends true
|
|
102
107
|
? GetValForKey<SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>, 'value'>
|
|
103
108
|
: SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>
|
|
104
109
|
|
|
105
|
-
export type RowResultEncoded<TTableDef extends TableDef> = TTableDef['isSingleColumn'] extends true
|
|
110
|
+
export type RowResultEncoded<TTableDef extends DbSchema.TableDef> = TTableDef['isSingleColumn'] extends true
|
|
106
111
|
? GetValForKey<SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>, 'value'>
|
|
107
112
|
: SqliteDsl.FromColumns.RowEncoded<TTableDef['sqliteDef']['columns']>
|
|
108
113
|
|
|
@@ -126,19 +131,19 @@ export const deriveColQuery: {
|
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
const insertRowWithDefaultValuesOrIgnore = ({
|
|
129
|
-
|
|
134
|
+
store,
|
|
130
135
|
id,
|
|
131
136
|
table,
|
|
132
137
|
otelContext,
|
|
133
138
|
defaultValues: explicitDefaultValues,
|
|
134
139
|
}: {
|
|
135
|
-
|
|
140
|
+
store: Store
|
|
136
141
|
id: string
|
|
137
|
-
table: TableDef
|
|
142
|
+
table: DbSchema.TableDef
|
|
138
143
|
otelContext: otel.Context
|
|
139
|
-
defaultValues: Partial<RowResult<TableDef>> | undefined
|
|
144
|
+
defaultValues: Partial<RowResult<DbSchema.TableDef>> | undefined
|
|
140
145
|
}) => {
|
|
141
|
-
const defaultValues = getDefaultValuesEncoded(table, explicitDefaultValues)
|
|
146
|
+
const defaultValues = DbSchema.getDefaultValuesEncoded(table, explicitDefaultValues)
|
|
142
147
|
|
|
143
148
|
const defaultColumnNames = [...Object.keys(defaultValues), 'id']
|
|
144
149
|
const columnValues = defaultColumnNames.map((name) => `$${name}`).join(', ')
|
|
@@ -148,9 +153,7 @@ const insertRowWithDefaultValuesOrIgnore = ({
|
|
|
148
153
|
', ',
|
|
149
154
|
)}) select ${columnValues} where not exists(select 1 from ${tableName} where id = '${id}')`
|
|
150
155
|
|
|
151
|
-
|
|
152
|
-
otelContext,
|
|
153
|
-
})
|
|
156
|
+
store.execute(insertQuery, { ...defaultValues, id }, new Set([tableName]), otelContext)
|
|
154
157
|
}
|
|
155
158
|
|
|
156
159
|
const makeExecBeforeFirstRun =
|
|
@@ -167,7 +170,7 @@ const makeExecBeforeFirstRun =
|
|
|
167
170
|
skipInsertDefaultRow?: boolean
|
|
168
171
|
otelContext?: otel.Context
|
|
169
172
|
componentTableName: string
|
|
170
|
-
table: TableDef
|
|
173
|
+
table: DbSchema.TableDef
|
|
171
174
|
}) =>
|
|
172
175
|
({ store }: DbContext) => {
|
|
173
176
|
const otelContext = otelContext_ ?? store.otel.queriesSpanContext
|
|
@@ -175,12 +178,12 @@ const makeExecBeforeFirstRun =
|
|
|
175
178
|
// TODO find a better solution for this
|
|
176
179
|
if (store.tableRefs[componentTableName] === undefined) {
|
|
177
180
|
const schemaHash = SqliteAst.hash(table.sqliteDef.ast)
|
|
178
|
-
const res = store.
|
|
181
|
+
const res = store.mainDbWrapper.select<{ schemaHash: number }>(
|
|
179
182
|
sql`SELECT schemaHash FROM ${SCHEMA_META_TABLE} WHERE tableName = '${componentTableName}'`,
|
|
180
183
|
)
|
|
181
184
|
if (res.length === 0 || res[0]!.schemaHash !== schemaHash) {
|
|
182
185
|
migrateTable({
|
|
183
|
-
db: store.
|
|
186
|
+
db: store.db,
|
|
184
187
|
tableAst: table.sqliteDef.ast,
|
|
185
188
|
otelContext,
|
|
186
189
|
schemaHash,
|
|
@@ -200,7 +203,7 @@ const makeExecBeforeFirstRun =
|
|
|
200
203
|
if (skipInsertDefaultRow !== true) {
|
|
201
204
|
// TODO find a way to only do this if necessary
|
|
202
205
|
insertRowWithDefaultValuesOrIgnore({
|
|
203
|
-
|
|
206
|
+
store,
|
|
204
207
|
id: id ?? 'singleton',
|
|
205
208
|
table,
|
|
206
209
|
otelContext,
|