@livestore/livestore 0.0.54-dev.2 → 0.0.54-dev.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/dist/.tsbuildinfo +1 -1
- package/dist/MainDatabaseWrapper.d.ts +6 -5
- package/dist/MainDatabaseWrapper.d.ts.map +1 -1
- package/dist/MainDatabaseWrapper.js +3 -3
- package/dist/MainDatabaseWrapper.js.map +1 -1
- package/dist/QueryCache.d.ts +1 -1
- package/dist/QueryCache.d.ts.map +1 -1
- package/dist/QueryCache.js.map +1 -1
- package/dist/__tests__/react/fixture.d.ts +4 -4
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +10 -8
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/effect/LiveStore.d.ts +2 -3
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +4 -2
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/global-state.d.ts +1 -1
- package/dist/global-state.d.ts.map +1 -1
- package/dist/global-state.js +2 -2
- package/dist/global-state.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +3 -4
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js +8 -13
- package/dist/react/LiveStoreProvider.js.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 +3 -3
- package/dist/react/useRow.js.map +1 -1
- package/dist/react/useRow.test.js +21 -21
- package/dist/react/useRow.test.js.map +1 -1
- package/dist/react/useTemporaryQuery.js +1 -1
- package/dist/react/useTemporaryQuery.js.map +1 -1
- package/dist/reactive.js +1 -1
- package/dist/reactive.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +6 -6
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js +3 -3
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +8 -8
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +10 -10
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +6 -6
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js +8 -8
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +9 -10
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +12 -12
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/row-query.d.ts +2 -2
- 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/store.d.ts +23 -20
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +140 -144
- package/dist/store.js.map +1 -1
- package/package.json +5 -12
- package/src/MainDatabaseWrapper.ts +14 -8
- package/src/QueryCache.ts +1 -2
- package/src/__tests__/react/fixture.tsx +11 -9
- package/src/effect/LiveStore.ts +6 -5
- package/src/global-state.ts +2 -2
- package/src/index.ts +17 -4
- package/src/react/LiveStoreProvider.tsx +10 -18
- package/src/react/useRow.test.tsx +21 -21
- package/src/react/useRow.ts +5 -5
- package/src/react/useTemporaryQuery.ts +2 -2
- package/src/reactive.ts +3 -1
- package/src/reactiveQueries/base-class.ts +9 -9
- package/src/reactiveQueries/graphql.ts +19 -15
- package/src/reactiveQueries/js.ts +12 -12
- package/src/reactiveQueries/sql.ts +19 -21
- package/src/row-query.ts +8 -8
- package/src/store.ts +214 -179
- package/dist/utils/bounded-collections.d.ts +0 -34
- package/dist/utils/bounded-collections.d.ts.map +0 -1
- package/dist/utils/bounded-collections.js +0 -91
- package/dist/utils/bounded-collections.js.map +0 -1
- package/dist/utils/util.d.ts +0 -14
- package/dist/utils/util.d.ts.map +0 -1
- package/dist/utils/util.js +0 -19
- package/dist/utils/util.js.map +0 -1
- package/src/utils/util.ts +0 -31
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/* eslint-disable prefer-arrow/prefer-arrow-functions */
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
DebugInfo,
|
|
5
|
+
InMemoryDatabase,
|
|
6
|
+
MutableDebugInfo,
|
|
7
|
+
PreparedBindValues,
|
|
8
|
+
PreparedStatement,
|
|
9
|
+
} from '@livestore/common'
|
|
4
10
|
import { BoundArray, BoundMap, sql } from '@livestore/common'
|
|
5
11
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
6
12
|
import type * as otel from '@opentelemetry/api'
|
|
7
13
|
|
|
8
14
|
import QueryCache from './QueryCache.js'
|
|
9
15
|
import { getDurationMsFromSpan, getStartTimeHighResFromSpan } from './utils/otel.js'
|
|
10
|
-
import { type PreparedBindValues } from './utils/util.js'
|
|
11
16
|
|
|
12
17
|
export const emptyDebugInfo = (): DebugInfo => ({
|
|
13
18
|
slowQueries: new BoundArray(200),
|
|
@@ -29,16 +34,17 @@ export class MainDatabaseWrapper {
|
|
|
29
34
|
|
|
30
35
|
constructor({
|
|
31
36
|
db,
|
|
32
|
-
|
|
33
|
-
otelRootSpanContext,
|
|
37
|
+
otel,
|
|
34
38
|
}: {
|
|
35
39
|
db: InMemoryDatabase
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
otel: {
|
|
41
|
+
tracer: otel.Tracer
|
|
42
|
+
rootSpanContext: otel.Context
|
|
43
|
+
}
|
|
38
44
|
}) {
|
|
39
45
|
this.db = db
|
|
40
|
-
this.otelTracer =
|
|
41
|
-
this.otelRootSpanContext =
|
|
46
|
+
this.otelTracer = otel.tracer
|
|
47
|
+
this.otelRootSpanContext = otel.rootSpanContext
|
|
42
48
|
|
|
43
49
|
this.tablesUsedStmt = db.prepare(
|
|
44
50
|
`SELECT tbl_name FROM tables_used(?) AS u JOIN sqlite_master ON sqlite_master.name = u.name WHERE u.schema = 'main';`,
|
package/src/QueryCache.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import type { Bindable } from '@livestore/common'
|
|
1
2
|
import { BoundMap, BoundSet } from '@livestore/common'
|
|
2
3
|
|
|
3
|
-
import type { Bindable } from './utils/util.js'
|
|
4
|
-
|
|
5
4
|
type Opaque<BaseType, BrandType = unknown> = BaseType & {
|
|
6
5
|
readonly [Symbols.base]: BaseType
|
|
7
6
|
readonly [Symbols.brand]: BrandType
|
|
@@ -3,9 +3,9 @@ import { makeInMemoryAdapter } from '@livestore/web'
|
|
|
3
3
|
import type * as otel from '@opentelemetry/api'
|
|
4
4
|
import React from 'react'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { globalReactivityGraph } from '../../global-state.js'
|
|
7
7
|
import type { LiveStoreContext } from '../../index.js'
|
|
8
|
-
import { createStore, DbSchema,
|
|
8
|
+
import { createStore, DbSchema, makeReactivityGraph, makeSchema, ParseUtils, sql } from '../../index.js'
|
|
9
9
|
import * as LiveStoreReact from '../../react/index.js'
|
|
10
10
|
|
|
11
11
|
export type Todo = {
|
|
@@ -62,15 +62,15 @@ export const parseTodos = ParseUtils.many(todos)
|
|
|
62
62
|
export const makeTodoMvc = async ({
|
|
63
63
|
otelTracer,
|
|
64
64
|
otelContext,
|
|
65
|
-
|
|
65
|
+
useGlobalReactivityGraph = true,
|
|
66
66
|
strictMode = process.env.REACT_STRICT_MODE !== undefined,
|
|
67
67
|
}: {
|
|
68
68
|
otelTracer?: otel.Tracer
|
|
69
69
|
otelContext?: otel.Context
|
|
70
|
-
|
|
70
|
+
useGlobalReactivityGraph?: boolean
|
|
71
71
|
strictMode?: boolean
|
|
72
72
|
} = {}) => {
|
|
73
|
-
const
|
|
73
|
+
const reactivityGraph = useGlobalReactivityGraph ? globalReactivityGraph : makeReactivityGraph()
|
|
74
74
|
|
|
75
75
|
const makeRenderCount = () => {
|
|
76
76
|
let val = 0
|
|
@@ -91,9 +91,11 @@ export const makeTodoMvc = async ({
|
|
|
91
91
|
schema,
|
|
92
92
|
boot: (db) => db.execute(sql`INSERT OR IGNORE INTO app (id, newTodoText, filter) VALUES ('static', '', 'all');`),
|
|
93
93
|
adapter: makeInMemoryAdapter(),
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
reactivityGraph,
|
|
95
|
+
otelOptions: {
|
|
96
|
+
tracer: otelTracer,
|
|
97
|
+
rootSpanContext: otelContext,
|
|
98
|
+
},
|
|
97
99
|
})
|
|
98
100
|
|
|
99
101
|
// TODO improve typing of `LiveStoreContext`
|
|
@@ -115,7 +117,7 @@ export const makeTodoMvc = async ({
|
|
|
115
117
|
AppComponentSchema: userInfo,
|
|
116
118
|
AppRouterSchema,
|
|
117
119
|
store,
|
|
118
|
-
|
|
120
|
+
reactivityGraph,
|
|
119
121
|
makeRenderCount,
|
|
120
122
|
strictMode,
|
|
121
123
|
}
|
package/src/effect/LiveStore.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { GraphQLSchema } from 'graphql'
|
|
|
7
7
|
|
|
8
8
|
import type { MainDatabaseWrapper } from '../MainDatabaseWrapper.js'
|
|
9
9
|
import type { LiveQuery } from '../reactiveQueries/base-class.js'
|
|
10
|
-
import type { BaseGraphQLContext, GraphQLOptions, Store } from '../store.js'
|
|
10
|
+
import type { BaseGraphQLContext, GraphQLOptions, OtelOptions, Store } from '../store.js'
|
|
11
11
|
import { createStore } from '../store.js'
|
|
12
12
|
|
|
13
13
|
// TODO get rid of `LiveStoreContext` wrapper and only expose the `Store` directly
|
|
@@ -20,8 +20,7 @@ export type QueryDefinition = <TResult>(store: Store) => LiveQuery<TResult>
|
|
|
20
20
|
export type LiveStoreCreateStoreOptions<GraphQLContext extends BaseGraphQLContext> = {
|
|
21
21
|
schema: LiveStoreSchema
|
|
22
22
|
graphQLOptions?: GraphQLOptions<GraphQLContext>
|
|
23
|
-
|
|
24
|
-
otelRootSpanContext?: otel.Context
|
|
23
|
+
otelOptions?: OtelOptions
|
|
25
24
|
boot?: (db: BootDb, parentSpan: otel.Span) => unknown | Promise<unknown>
|
|
26
25
|
adapter: StoreAdapterFactory
|
|
27
26
|
batchUpdates?: (run: () => void) => void
|
|
@@ -92,8 +91,10 @@ export const makeLiveStoreContext = <GraphQLContext extends BaseGraphQLContext>(
|
|
|
92
91
|
createStore({
|
|
93
92
|
schema,
|
|
94
93
|
graphQLOptions,
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
otelOptions: {
|
|
95
|
+
tracer: otelTracer,
|
|
96
|
+
rootSpanContext: otelRootSpanContext,
|
|
97
|
+
},
|
|
97
98
|
boot,
|
|
98
99
|
adapter,
|
|
99
100
|
disableDevtools,
|
package/src/global-state.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import type { DbSchema } from '@livestore/common/schema'
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { makeReactivityGraph } from './reactiveQueries/base-class.js'
|
|
17
17
|
|
|
18
|
-
export const
|
|
18
|
+
export const globalReactivityGraph = makeReactivityGraph()
|
|
19
19
|
|
|
20
20
|
export const dynamicallyRegisteredTables: Map<string, DbSchema.TableDef> = new Map()
|
package/src/index.ts
CHANGED
|
@@ -20,18 +20,31 @@ export type {
|
|
|
20
20
|
export { LiveStoreJSQuery, computed } from './reactiveQueries/js.js'
|
|
21
21
|
export { LiveStoreSQLQuery, querySQL, type MapRows } from './reactiveQueries/sql.js'
|
|
22
22
|
export { LiveStoreGraphQLQuery, queryGraphQL } from './reactiveQueries/graphql.js'
|
|
23
|
-
export {
|
|
23
|
+
export {
|
|
24
|
+
type GetAtomResult,
|
|
25
|
+
type ReactivityGraph,
|
|
26
|
+
makeReactivityGraph,
|
|
27
|
+
type LiveQuery,
|
|
28
|
+
} from './reactiveQueries/base-class.js'
|
|
24
29
|
|
|
25
|
-
export {
|
|
30
|
+
export { globalReactivityGraph, dynamicallyRegisteredTables } from './global-state.js'
|
|
26
31
|
|
|
27
32
|
export { type RowResult, type RowResultEncoded, rowQuery, deriveColQuery } from './row-query.js'
|
|
28
33
|
|
|
29
34
|
export * from '@livestore/common/schema'
|
|
30
|
-
export {
|
|
35
|
+
export {
|
|
36
|
+
sql,
|
|
37
|
+
type BootDb,
|
|
38
|
+
type InMemoryDatabase,
|
|
39
|
+
type DebugInfo,
|
|
40
|
+
type MutableDebugInfo,
|
|
41
|
+
prepareBindValues,
|
|
42
|
+
type Bindable,
|
|
43
|
+
type PreparedBindValues,
|
|
44
|
+
} from '@livestore/common'
|
|
31
45
|
|
|
32
46
|
export { SqliteAst, SqliteDsl } from 'effect-db-schema'
|
|
33
47
|
|
|
34
|
-
export { prepareBindValues, type Bindable, type PreparedBindValues } from './utils/util.js'
|
|
35
48
|
export { isEqual } from 'lodash-es'
|
|
36
49
|
|
|
37
50
|
export type {
|
|
@@ -7,7 +7,7 @@ import React from 'react'
|
|
|
7
7
|
|
|
8
8
|
// TODO refactor so the `react` module doesn't depend on `effect` module
|
|
9
9
|
import type { LiveStoreContext as StoreContext_, LiveStoreCreateStoreOptions } from '../effect/LiveStore.js'
|
|
10
|
-
import type { BaseGraphQLContext, GraphQLOptions, Store } from '../store.js'
|
|
10
|
+
import type { BaseGraphQLContext, GraphQLOptions, OtelOptions, Store } from '../store.js'
|
|
11
11
|
import { createStore } from '../store.js'
|
|
12
12
|
import { LiveStoreContext } from './LiveStoreContext.js'
|
|
13
13
|
|
|
@@ -15,8 +15,7 @@ interface LiveStoreProviderProps<GraphQLContext> {
|
|
|
15
15
|
schema: LiveStoreSchema
|
|
16
16
|
boot?: (db: BootDb, parentSpan: otel.Span) => unknown | Promise<unknown>
|
|
17
17
|
graphQLOptions?: GraphQLOptions<GraphQLContext>
|
|
18
|
-
|
|
19
|
-
otelRootSpanContext?: otel.Context
|
|
18
|
+
otelOptions?: OtelOptions
|
|
20
19
|
fallback: ReactElement
|
|
21
20
|
adapter: StoreAdapterFactory
|
|
22
21
|
batchUpdates?: (run: () => void) => void
|
|
@@ -26,8 +25,7 @@ interface LiveStoreProviderProps<GraphQLContext> {
|
|
|
26
25
|
export const LiveStoreProvider = <GraphQLContext extends BaseGraphQLContext>({
|
|
27
26
|
fallback,
|
|
28
27
|
graphQLOptions,
|
|
29
|
-
|
|
30
|
-
otelRootSpanContext,
|
|
28
|
+
otelOptions,
|
|
31
29
|
children,
|
|
32
30
|
schema,
|
|
33
31
|
boot,
|
|
@@ -38,8 +36,7 @@ export const LiveStoreProvider = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
38
36
|
const storeCtx = useCreateStore({
|
|
39
37
|
schema,
|
|
40
38
|
graphQLOptions,
|
|
41
|
-
|
|
42
|
-
otelRootSpanContext,
|
|
39
|
+
otelOptions,
|
|
43
40
|
boot,
|
|
44
41
|
adapter,
|
|
45
42
|
batchUpdates,
|
|
@@ -58,8 +55,7 @@ export const LiveStoreProvider = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
58
55
|
const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
59
56
|
schema,
|
|
60
57
|
graphQLOptions,
|
|
61
|
-
|
|
62
|
-
otelRootSpanContext,
|
|
58
|
+
otelOptions,
|
|
63
59
|
boot,
|
|
64
60
|
adapter,
|
|
65
61
|
batchUpdates,
|
|
@@ -70,8 +66,7 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
70
66
|
const inputPropsCacheRef = React.useRef({
|
|
71
67
|
schema,
|
|
72
68
|
graphQLOptions,
|
|
73
|
-
|
|
74
|
-
otelRootSpanContext,
|
|
69
|
+
otelOptions,
|
|
75
70
|
boot,
|
|
76
71
|
adapter,
|
|
77
72
|
batchUpdates,
|
|
@@ -81,8 +76,7 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
81
76
|
if (
|
|
82
77
|
inputPropsCacheRef.current.schema !== schema ||
|
|
83
78
|
inputPropsCacheRef.current.graphQLOptions !== graphQLOptions ||
|
|
84
|
-
inputPropsCacheRef.current.
|
|
85
|
-
inputPropsCacheRef.current.otelRootSpanContext !== otelRootSpanContext ||
|
|
79
|
+
inputPropsCacheRef.current.otelOptions !== otelOptions ||
|
|
86
80
|
inputPropsCacheRef.current.boot !== boot ||
|
|
87
81
|
inputPropsCacheRef.current.adapter !== adapter ||
|
|
88
82
|
inputPropsCacheRef.current.batchUpdates !== batchUpdates
|
|
@@ -90,8 +84,7 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
90
84
|
inputPropsCacheRef.current = {
|
|
91
85
|
schema,
|
|
92
86
|
graphQLOptions,
|
|
93
|
-
|
|
94
|
-
otelRootSpanContext,
|
|
87
|
+
otelOptions,
|
|
95
88
|
boot,
|
|
96
89
|
adapter,
|
|
97
90
|
batchUpdates,
|
|
@@ -109,8 +102,7 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
109
102
|
store = await createStore({
|
|
110
103
|
schema,
|
|
111
104
|
graphQLOptions,
|
|
112
|
-
|
|
113
|
-
otelRootSpanContext,
|
|
105
|
+
otelOptions,
|
|
114
106
|
boot,
|
|
115
107
|
adapter,
|
|
116
108
|
batchUpdates,
|
|
@@ -129,7 +121,7 @@ const useCreateStore = <GraphQLContext extends BaseGraphQLContext>({
|
|
|
129
121
|
store?.destroy()
|
|
130
122
|
}
|
|
131
123
|
}
|
|
132
|
-
}, [schema, graphQLOptions,
|
|
124
|
+
}, [schema, graphQLOptions, otelOptions, boot, adapter, batchUpdates, disableDevtools])
|
|
133
125
|
|
|
134
126
|
return ctxValueRef.current
|
|
135
127
|
}
|
|
@@ -15,9 +15,9 @@ import type { StackInfo } from './utils/stack-info.js'
|
|
|
15
15
|
// NOTE running tests concurrently doesn't work with the default global db graph
|
|
16
16
|
describe.concurrent('useRow', () => {
|
|
17
17
|
it('should update the data based on component key', async () => {
|
|
18
|
-
using inputs = await makeTodoMvc({
|
|
18
|
+
using inputs = await makeTodoMvc({ useGlobalReactivityGraph: false })
|
|
19
19
|
|
|
20
|
-
const { wrapper, AppComponentSchema, store,
|
|
20
|
+
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount } = inputs
|
|
21
21
|
|
|
22
22
|
const renderCount = makeRenderCount()
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ describe.concurrent('useRow', () => {
|
|
|
25
25
|
(userId: string) => {
|
|
26
26
|
renderCount.inc()
|
|
27
27
|
|
|
28
|
-
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, {
|
|
28
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
29
29
|
return { state, setState }
|
|
30
30
|
},
|
|
31
31
|
{ wrapper, initialProps: 'u1' },
|
|
@@ -53,9 +53,9 @@ describe.concurrent('useRow', () => {
|
|
|
53
53
|
// TODO add a test that makes sure React doesn't re-render when a setter is used to set the same value
|
|
54
54
|
|
|
55
55
|
it('should update the data reactively - via setState', async () => {
|
|
56
|
-
using inputs = await makeTodoMvc({
|
|
56
|
+
using inputs = await makeTodoMvc({ useGlobalReactivityGraph: false })
|
|
57
57
|
|
|
58
|
-
const { wrapper, AppComponentSchema,
|
|
58
|
+
const { wrapper, AppComponentSchema, reactivityGraph, makeRenderCount } = inputs
|
|
59
59
|
|
|
60
60
|
const renderCount = makeRenderCount()
|
|
61
61
|
|
|
@@ -63,7 +63,7 @@ describe.concurrent('useRow', () => {
|
|
|
63
63
|
(userId: string) => {
|
|
64
64
|
renderCount.inc()
|
|
65
65
|
|
|
66
|
-
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, {
|
|
66
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
67
67
|
return { state, setState }
|
|
68
68
|
},
|
|
69
69
|
{ wrapper, initialProps: 'u1' },
|
|
@@ -81,9 +81,9 @@ describe.concurrent('useRow', () => {
|
|
|
81
81
|
})
|
|
82
82
|
|
|
83
83
|
it('should update the data reactively - via raw store mutation', async () => {
|
|
84
|
-
using inputs = await makeTodoMvc({
|
|
84
|
+
using inputs = await makeTodoMvc({ useGlobalReactivityGraph: false })
|
|
85
85
|
|
|
86
|
-
const { wrapper, AppComponentSchema, store,
|
|
86
|
+
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount } = inputs
|
|
87
87
|
|
|
88
88
|
const renderCount = makeRenderCount()
|
|
89
89
|
|
|
@@ -91,7 +91,7 @@ describe.concurrent('useRow', () => {
|
|
|
91
91
|
(userId: string) => {
|
|
92
92
|
renderCount.inc()
|
|
93
93
|
|
|
94
|
-
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, {
|
|
94
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
95
95
|
return { state, setState }
|
|
96
96
|
},
|
|
97
97
|
{ wrapper, initialProps: 'u1' },
|
|
@@ -115,17 +115,17 @@ describe.concurrent('useRow', () => {
|
|
|
115
115
|
})
|
|
116
116
|
|
|
117
117
|
it('should work for a larger app', async () => {
|
|
118
|
-
using inputs = await makeTodoMvc({
|
|
119
|
-
const { wrapper, store,
|
|
118
|
+
using inputs = await makeTodoMvc({ useGlobalReactivityGraph: false })
|
|
119
|
+
const { wrapper, store, reactivityGraph, makeRenderCount, AppRouterSchema } = inputs
|
|
120
120
|
|
|
121
|
-
const allTodos$ = LiveStore.querySQL<Todo[]>(`select * from todos`, { label: 'allTodos',
|
|
121
|
+
const allTodos$ = LiveStore.querySQL<Todo[]>(`select * from todos`, { label: 'allTodos', reactivityGraph })
|
|
122
122
|
|
|
123
123
|
const appRouterRenderCount = makeRenderCount()
|
|
124
124
|
let globalSetState: LiveStoreReact.StateSetters<typeof AppRouterSchema> | undefined
|
|
125
125
|
const AppRouter: React.FC = () => {
|
|
126
126
|
appRouterRenderCount.inc()
|
|
127
127
|
|
|
128
|
-
const [state, setState] = LiveStoreReact.useRow(AppRouterSchema, {
|
|
128
|
+
const [state, setState] = LiveStoreReact.useRow(AppRouterSchema, { reactivityGraph })
|
|
129
129
|
|
|
130
130
|
globalSetState = setState
|
|
131
131
|
|
|
@@ -153,7 +153,7 @@ describe.concurrent('useRow', () => {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
const TaskDetails: React.FC<{ id: string }> = ({ id }) => {
|
|
156
|
-
const [todo] = LiveStoreReact.useRow(todos, id, {
|
|
156
|
+
const [todo] = LiveStoreReact.useRow(todos, id, { reactivityGraph })
|
|
157
157
|
return <div role="content">{JSON.stringify(todo)}</div>
|
|
158
158
|
}
|
|
159
159
|
|
|
@@ -198,8 +198,8 @@ describe.concurrent('useRow', () => {
|
|
|
198
198
|
})
|
|
199
199
|
|
|
200
200
|
it('should work for a useRow query chained with a useTemporary query', async () => {
|
|
201
|
-
using inputs = await makeTodoMvc({
|
|
202
|
-
const { store, wrapper, AppComponentSchema,
|
|
201
|
+
using inputs = await makeTodoMvc({ useGlobalReactivityGraph: false })
|
|
202
|
+
const { store, wrapper, AppComponentSchema, reactivityGraph, makeRenderCount } = inputs
|
|
203
203
|
const renderCount = makeRenderCount()
|
|
204
204
|
|
|
205
205
|
store.mutate(
|
|
@@ -211,12 +211,12 @@ describe.concurrent('useRow', () => {
|
|
|
211
211
|
(userId: string) => {
|
|
212
212
|
renderCount.inc()
|
|
213
213
|
|
|
214
|
-
const [_row, _setRow, rowState$] = LiveStoreReact.useRow(AppComponentSchema, userId, {
|
|
214
|
+
const [_row, _setRow, rowState$] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
215
215
|
const todos = LiveStoreReact.useTemporaryQuery(
|
|
216
216
|
() =>
|
|
217
217
|
LiveStore.querySQL<any[]>(
|
|
218
218
|
(get) => LiveStore.sql`select * from todos where text like '%${get(rowState$).text}%'`,
|
|
219
|
-
{
|
|
219
|
+
{ reactivityGraph, label: 'todosFiltered' },
|
|
220
220
|
),
|
|
221
221
|
userId,
|
|
222
222
|
)
|
|
@@ -262,9 +262,9 @@ describe.concurrent('useRow', () => {
|
|
|
262
262
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
263
263
|
|
|
264
264
|
it('should update the data based on component key', async () => {
|
|
265
|
-
using inputs = await makeTodoMvc({
|
|
265
|
+
using inputs = await makeTodoMvc({ useGlobalReactivityGraph: false, otelContext, otelTracer })
|
|
266
266
|
|
|
267
|
-
const { wrapper, AppComponentSchema, store,
|
|
267
|
+
const { wrapper, AppComponentSchema, store, reactivityGraph, makeRenderCount, strictMode } = inputs
|
|
268
268
|
|
|
269
269
|
const renderCount = makeRenderCount()
|
|
270
270
|
|
|
@@ -272,7 +272,7 @@ describe.concurrent('useRow', () => {
|
|
|
272
272
|
(userId: string) => {
|
|
273
273
|
renderCount.inc()
|
|
274
274
|
|
|
275
|
-
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, {
|
|
275
|
+
const [state, setState] = LiveStoreReact.useRow(AppComponentSchema, userId, { reactivityGraph })
|
|
276
276
|
return { state, setState }
|
|
277
277
|
},
|
|
278
278
|
{ wrapper, initialProps: 'u1' },
|
package/src/react/useRow.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { SqliteDsl } from 'effect-db-schema'
|
|
|
8
8
|
import { mapValues } from 'lodash-es'
|
|
9
9
|
import React from 'react'
|
|
10
10
|
|
|
11
|
-
import type {
|
|
11
|
+
import type { LiveQuery, ReactivityGraph } from '../index.js'
|
|
12
12
|
import type { RowResult } from '../row-query.js'
|
|
13
13
|
import { rowQuery } from '../row-query.js'
|
|
14
14
|
import { useStore } from './LiveStoreContext.js'
|
|
@@ -26,7 +26,7 @@ export type UseRowOptionsDefaulValues<TTableDef extends DbSchema.TableDef> = {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export type UseRowOptionsBase = {
|
|
29
|
-
|
|
29
|
+
reactivityGraph?: ReactivityGraph
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
@@ -76,7 +76,7 @@ export const useRow: {
|
|
|
76
76
|
const id = typeof idOrOptions === 'string' ? idOrOptions : undefined
|
|
77
77
|
const options: (UseRowOptionsBase & UseRowOptionsDefaulValues<TTableDef>) | undefined =
|
|
78
78
|
typeof idOrOptions === 'string' ? options_ : idOrOptions
|
|
79
|
-
const { defaultValues,
|
|
79
|
+
const { defaultValues, reactivityGraph } = options ?? {}
|
|
80
80
|
|
|
81
81
|
type TComponentState = SqliteDsl.FromColumns.RowDecoded<TTableDef['sqliteDef']['columns']>
|
|
82
82
|
|
|
@@ -100,11 +100,11 @@ export const useRow: {
|
|
|
100
100
|
const { query$, otelContext } = useMakeTemporaryQuery(
|
|
101
101
|
(otelContext) =>
|
|
102
102
|
DbSchema.tableIsSingleton(table)
|
|
103
|
-
? (rowQuery(table, { otelContext,
|
|
103
|
+
? (rowQuery(table, { otelContext, reactivityGraph }) as LiveQuery<RowResult<TTableDef>, QueryInfo>)
|
|
104
104
|
: (rowQuery(table as TTableDef & { options: { isSingleton: false } }, id!, {
|
|
105
105
|
otelContext,
|
|
106
106
|
defaultValues: defaultValues!,
|
|
107
|
-
|
|
107
|
+
reactivityGraph,
|
|
108
108
|
}) as any as LiveQuery<RowResult<TTableDef>, QueryInfo>),
|
|
109
109
|
[id!, tableName],
|
|
110
110
|
{
|
|
@@ -53,8 +53,8 @@ export const useMakeTemporaryQuery = <TResult, TQueryInfo extends QueryInfo>(
|
|
|
53
53
|
const fullKey = React.useMemo(
|
|
54
54
|
// NOTE We're using the `makeQuery` function body string to make sure the key is unique across the app
|
|
55
55
|
// TODO we should figure out whether this could cause some problems and/or if there's a better way to do this
|
|
56
|
-
() => (Array.isArray(key) ? key.join('-') : key) + '-' + store.
|
|
57
|
-
[key, makeQuery, store.
|
|
56
|
+
() => (Array.isArray(key) ? key.join('-') : key) + '-' + store.reactivityGraph.id + '-' + makeQuery.toString(),
|
|
57
|
+
[key, makeQuery, store.reactivityGraph.id],
|
|
58
58
|
)
|
|
59
59
|
const fullKeyRef = React.useRef<string>()
|
|
60
60
|
|
package/src/reactive.ts
CHANGED
|
@@ -618,7 +618,9 @@ const serializeAtom = (atom: Atom<any, unknown, any>, includeResult: boolean): S
|
|
|
618
618
|
}
|
|
619
619
|
|
|
620
620
|
const previousResult: EncodedOption<string> = includeResult
|
|
621
|
-
? encodedOptionSome(
|
|
621
|
+
? encodedOptionSome(
|
|
622
|
+
atom.previousResult === NOT_REFRESHED_YET ? '"SYMBOL_NOT_REFRESHED_YET"' : JSON.stringify(atom.previousResult),
|
|
623
|
+
)
|
|
622
624
|
: encodedOptionNone()
|
|
623
625
|
|
|
624
626
|
if (atom._tag === 'ref') {
|
|
@@ -6,15 +6,15 @@ import type { StackInfo } from '../react/utils/stack-info.js'
|
|
|
6
6
|
import { type Atom, type GetAtom, ReactiveGraph, throwContextNotSetError, type Thunk } from '../reactive.js'
|
|
7
7
|
import type { QueryDebugInfo, RefreshReason, Store } from '../store.js'
|
|
8
8
|
|
|
9
|
-
export type
|
|
9
|
+
export type ReactivityGraph = ReactiveGraph<RefreshReason, QueryDebugInfo, QueryContext>
|
|
10
10
|
|
|
11
|
-
export const
|
|
12
|
-
new ReactiveGraph<RefreshReason, QueryDebugInfo,
|
|
11
|
+
export const makeReactivityGraph = (): ReactivityGraph =>
|
|
12
|
+
new ReactiveGraph<RefreshReason, QueryDebugInfo, QueryContext>({
|
|
13
13
|
// TODO also find a better way to only use this effects wrapper when used in a React app
|
|
14
14
|
effectsWrapper: (run) => ReactDOM.unstable_batchedUpdates(() => run()),
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
-
export type
|
|
17
|
+
export type QueryContext = {
|
|
18
18
|
store: Store
|
|
19
19
|
otelTracer: otel.Tracer
|
|
20
20
|
rootOtelContext: otel.Context
|
|
@@ -37,7 +37,7 @@ export interface LiveQuery<TResult, TQueryInfo extends QueryInfo = QueryInfoNone
|
|
|
37
37
|
'__result!': TResult
|
|
38
38
|
|
|
39
39
|
/** A reactive thunk representing the query results */
|
|
40
|
-
results$: Thunk<TResult,
|
|
40
|
+
results$: Thunk<TResult, QueryContext, RefreshReason>
|
|
41
41
|
|
|
42
42
|
label: string
|
|
43
43
|
|
|
@@ -72,11 +72,11 @@ export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
|
|
|
72
72
|
/** Human-readable label for the query for debugging */
|
|
73
73
|
abstract label: string
|
|
74
74
|
|
|
75
|
-
abstract results$: Thunk<TResult,
|
|
75
|
+
abstract results$: Thunk<TResult, QueryContext, RefreshReason>
|
|
76
76
|
|
|
77
77
|
activeSubscriptions: Set<StackInfo> = new Set()
|
|
78
78
|
|
|
79
|
-
protected abstract
|
|
79
|
+
protected abstract reactivityGraph: ReactivityGraph
|
|
80
80
|
|
|
81
81
|
abstract queryInfo: TQueryInfo
|
|
82
82
|
|
|
@@ -102,8 +102,8 @@ export abstract class LiveStoreQueryBase<TResult, TQueryInfo extends QueryInfo>
|
|
|
102
102
|
onUnsubsubscribe?: () => void,
|
|
103
103
|
options?: { label?: string; otelContext?: otel.Context } | undefined,
|
|
104
104
|
): (() => void) =>
|
|
105
|
-
this.
|
|
106
|
-
throwContextNotSetError(this.
|
|
105
|
+
this.reactivityGraph.context?.store.subscribe(this, onNewValue, onUnsubsubscribe, options) ??
|
|
106
|
+
throwContextNotSetError(this.reactivityGraph)
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
export type GetAtomResult = <T>(atom: Atom<T, any, RefreshReason> | LiveQuery<T, any>) => T
|
|
@@ -5,11 +5,11 @@ import { Schema, TreeFormatter } from '@livestore/utils/effect'
|
|
|
5
5
|
import * as otel from '@opentelemetry/api'
|
|
6
6
|
import * as graphql from 'graphql'
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { globalReactivityGraph } from '../global-state.js'
|
|
9
9
|
import { isThunk, type Thunk } from '../reactive.js'
|
|
10
10
|
import type { BaseGraphQLContext, RefreshReason, Store } from '../store.js'
|
|
11
11
|
import { getDurationMsFromSpan } from '../utils/otel.js'
|
|
12
|
-
import type {
|
|
12
|
+
import type { GetAtomResult, LiveQuery, QueryContext, ReactivityGraph } from './base-class.js'
|
|
13
13
|
import { LiveStoreQueryBase, makeGetAtomResult } from './base-class.js'
|
|
14
14
|
|
|
15
15
|
export type MapResult<To, From> = ((res: From, get: GetAtomResult) => To) | Schema.Schema<To, From>
|
|
@@ -21,9 +21,13 @@ export const queryGraphQL = <
|
|
|
21
21
|
>(
|
|
22
22
|
document: DocumentNode<TResult, TVariableValues>,
|
|
23
23
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues),
|
|
24
|
-
{
|
|
24
|
+
{
|
|
25
|
+
label,
|
|
26
|
+
reactivityGraph,
|
|
27
|
+
map,
|
|
28
|
+
}: { label?: string; reactivityGraph?: ReactivityGraph; map?: MapResult<TResultMapped, TResult> } = {},
|
|
25
29
|
): LiveQuery<TResultMapped, QueryInfoNone> =>
|
|
26
|
-
new LiveStoreGraphQLQuery({ document, genVariableValues, label,
|
|
30
|
+
new LiveStoreGraphQLQuery({ document, genVariableValues, label, reactivityGraph, map })
|
|
27
31
|
|
|
28
32
|
export class LiveStoreGraphQLQuery<
|
|
29
33
|
TResult extends Record<string, any>,
|
|
@@ -37,13 +41,13 @@ export class LiveStoreGraphQLQuery<
|
|
|
37
41
|
document: DocumentNode<TResult, TVariableValues>
|
|
38
42
|
|
|
39
43
|
/** A reactive thunk representing the query results */
|
|
40
|
-
results$: Thunk<TResultMapped,
|
|
44
|
+
results$: Thunk<TResultMapped, QueryContext, RefreshReason>
|
|
41
45
|
|
|
42
|
-
variableValues$: Thunk<TVariableValues,
|
|
46
|
+
variableValues$: Thunk<TVariableValues, QueryContext, RefreshReason> | undefined
|
|
43
47
|
|
|
44
48
|
label: string
|
|
45
49
|
|
|
46
|
-
protected
|
|
50
|
+
protected reactivityGraph: ReactivityGraph
|
|
47
51
|
|
|
48
52
|
queryInfo: QueryInfoNone = { _tag: 'None' }
|
|
49
53
|
|
|
@@ -53,13 +57,13 @@ export class LiveStoreGraphQLQuery<
|
|
|
53
57
|
document,
|
|
54
58
|
label,
|
|
55
59
|
genVariableValues,
|
|
56
|
-
|
|
60
|
+
reactivityGraph,
|
|
57
61
|
map,
|
|
58
62
|
}: {
|
|
59
63
|
document: DocumentNode<TResult, TVariableValues>
|
|
60
64
|
genVariableValues: TVariableValues | ((get: GetAtomResult) => TVariableValues)
|
|
61
65
|
label?: string
|
|
62
|
-
|
|
66
|
+
reactivityGraph?: ReactivityGraph
|
|
63
67
|
map?: MapResult<TResultMapped, TResult>
|
|
64
68
|
}) {
|
|
65
69
|
super()
|
|
@@ -69,7 +73,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
69
73
|
this.label = labelWithDefault
|
|
70
74
|
this.document = document
|
|
71
75
|
|
|
72
|
-
this.
|
|
76
|
+
this.reactivityGraph = reactivityGraph ?? globalReactivityGraph
|
|
73
77
|
|
|
74
78
|
this.mapResult =
|
|
75
79
|
map === undefined
|
|
@@ -92,7 +96,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
92
96
|
let variableValues$OrvariableValues
|
|
93
97
|
|
|
94
98
|
if (typeof genVariableValues === 'function') {
|
|
95
|
-
variableValues$OrvariableValues = this.
|
|
99
|
+
variableValues$OrvariableValues = this.reactivityGraph.makeThunk(
|
|
96
100
|
(get, _setDebugInfo, { rootOtelContext }, otelContext) => {
|
|
97
101
|
return genVariableValues(makeGetAtomResult(get, otelContext ?? rootOtelContext))
|
|
98
102
|
},
|
|
@@ -104,7 +108,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
const resultsLabel = `${labelWithDefault}:results`
|
|
107
|
-
this.results$ = this.
|
|
111
|
+
this.results$ = this.reactivityGraph.makeThunk<TResultMapped>(
|
|
108
112
|
(get, setDebugInfo, { store, otelTracer, rootOtelContext }, otelContext) => {
|
|
109
113
|
const variableValues = isThunk(variableValues$OrvariableValues)
|
|
110
114
|
? (get(variableValues$OrvariableValues) as TVariableValues)
|
|
@@ -145,7 +149,7 @@ export class LiveStoreGraphQLQuery<
|
|
|
145
149
|
// },
|
|
146
150
|
// label: `${this.label}:js`,
|
|
147
151
|
// onDestroy: () => this.destroy(),
|
|
148
|
-
//
|
|
152
|
+
// reactivityGraph: this.reactivityGraph,
|
|
149
153
|
// })
|
|
150
154
|
|
|
151
155
|
queryOnce = ({
|
|
@@ -217,9 +221,9 @@ export class LiveStoreGraphQLQuery<
|
|
|
217
221
|
|
|
218
222
|
destroy = () => {
|
|
219
223
|
if (this.variableValues$ !== undefined) {
|
|
220
|
-
this.
|
|
224
|
+
this.reactivityGraph.destroyNode(this.variableValues$)
|
|
221
225
|
}
|
|
222
226
|
|
|
223
|
-
this.
|
|
227
|
+
this.reactivityGraph.destroyNode(this.results$)
|
|
224
228
|
}
|
|
225
229
|
}
|