@livestore/common 0.0.0-snapshot-909cdd1ac2fd591945c2be2b0f53e14d87f3c9d4
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 -0
- package/dist/__tests__/fixture.d.ts +72 -0
- package/dist/__tests__/fixture.d.ts.map +1 -0
- package/dist/__tests__/fixture.js +16 -0
- package/dist/__tests__/fixture.js.map +1 -0
- package/dist/adapter-types.d.ts +202 -0
- package/dist/adapter-types.d.ts.map +1 -0
- package/dist/adapter-types.js +49 -0
- package/dist/adapter-types.js.map +1 -0
- package/dist/bounded-collections.d.ts +36 -0
- package/dist/bounded-collections.d.ts.map +1 -0
- package/dist/bounded-collections.js +98 -0
- package/dist/bounded-collections.js.map +1 -0
- package/dist/debug-info.d.ts +122 -0
- package/dist/debug-info.d.ts.map +1 -0
- package/dist/debug-info.js +47 -0
- package/dist/debug-info.js.map +1 -0
- package/dist/derived-mutations.d.ts +109 -0
- package/dist/derived-mutations.d.ts.map +1 -0
- package/dist/derived-mutations.js +54 -0
- package/dist/derived-mutations.js.map +1 -0
- package/dist/derived-mutations.test.d.ts +2 -0
- package/dist/derived-mutations.test.d.ts.map +1 -0
- package/dist/derived-mutations.test.js +93 -0
- package/dist/derived-mutations.test.js.map +1 -0
- package/dist/devtools/devtools-bridge.d.ts +12 -0
- package/dist/devtools/devtools-bridge.d.ts.map +1 -0
- package/dist/devtools/devtools-bridge.js +2 -0
- package/dist/devtools/devtools-bridge.js.map +1 -0
- package/dist/devtools/devtools-messages.d.ts +705 -0
- package/dist/devtools/devtools-messages.d.ts.map +1 -0
- package/dist/devtools/devtools-messages.js +178 -0
- package/dist/devtools/devtools-messages.js.map +1 -0
- package/dist/devtools/devtools-window-message.d.ts +29 -0
- package/dist/devtools/devtools-window-message.d.ts.map +1 -0
- package/dist/devtools/devtools-window-message.js +33 -0
- package/dist/devtools/devtools-window-message.js.map +1 -0
- package/dist/devtools/index.d.ts +42 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/index.js +49 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/init-singleton-tables.d.ts +4 -0
- package/dist/init-singleton-tables.d.ts.map +1 -0
- package/dist/init-singleton-tables.js +16 -0
- package/dist/init-singleton-tables.js.map +1 -0
- package/dist/mutation.d.ts +13 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +43 -0
- package/dist/mutation.js.map +1 -0
- package/dist/query-info.d.ts +47 -0
- package/dist/query-info.d.ts.map +1 -0
- package/dist/query-info.js +38 -0
- package/dist/query-info.js.map +1 -0
- package/dist/rehydrate-from-mutationlog.d.ts +14 -0
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -0
- package/dist/rehydrate-from-mutationlog.js +72 -0
- package/dist/rehydrate-from-mutationlog.js.map +1 -0
- package/dist/schema/index.d.ts +60 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +66 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/mutations.d.ts +227 -0
- package/dist/schema/mutations.d.ts.map +1 -0
- package/dist/schema/mutations.js +68 -0
- package/dist/schema/mutations.js.map +1 -0
- package/dist/schema/schema-helpers.d.ts +4 -0
- package/dist/schema/schema-helpers.d.ts.map +1 -0
- package/dist/schema/schema-helpers.js +30 -0
- package/dist/schema/schema-helpers.js.map +1 -0
- package/dist/schema/system-tables.d.ts +331 -0
- package/dist/schema/system-tables.d.ts.map +1 -0
- package/dist/schema/system-tables.js +46 -0
- package/dist/schema/system-tables.js.map +1 -0
- package/dist/schema/table-def.d.ts +135 -0
- package/dist/schema/table-def.d.ts.map +1 -0
- package/dist/schema/table-def.js +70 -0
- package/dist/schema/table-def.js.map +1 -0
- package/dist/schema-management/common.d.ts +13 -0
- package/dist/schema-management/common.d.ts.map +1 -0
- package/dist/schema-management/common.js +25 -0
- package/dist/schema-management/common.js.map +1 -0
- package/dist/schema-management/migrations.d.ts +23 -0
- package/dist/schema-management/migrations.d.ts.map +1 -0
- package/dist/schema-management/migrations.js +116 -0
- package/dist/schema-management/migrations.js.map +1 -0
- package/dist/schema-management/validate-mutation-defs.d.ts +8 -0
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -0
- package/dist/schema-management/validate-mutation-defs.js +39 -0
- package/dist/schema-management/validate-mutation-defs.js.map +1 -0
- package/dist/sql-queries/index.d.ts +4 -0
- package/dist/sql-queries/index.d.ts.map +1 -0
- package/dist/sql-queries/index.js +4 -0
- package/dist/sql-queries/index.js.map +1 -0
- package/dist/sql-queries/misc.d.ts +2 -0
- package/dist/sql-queries/misc.d.ts.map +1 -0
- package/dist/sql-queries/misc.js +2 -0
- package/dist/sql-queries/misc.js.map +1 -0
- package/dist/sql-queries/sql-queries.d.ts +72 -0
- package/dist/sql-queries/sql-queries.d.ts.map +1 -0
- package/dist/sql-queries/sql-queries.js +191 -0
- package/dist/sql-queries/sql-queries.js.map +1 -0
- package/dist/sql-queries/sql-query-builder.d.ts +47 -0
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -0
- package/dist/sql-queries/sql-query-builder.js +60 -0
- package/dist/sql-queries/sql-query-builder.js.map +1 -0
- package/dist/sql-queries/types.d.ts +50 -0
- package/dist/sql-queries/types.d.ts.map +1 -0
- package/dist/sql-queries/types.js +5 -0
- package/dist/sql-queries/types.js.map +1 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +2 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts +15 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -0
- package/dist/sync/next/compact-events.js +176 -0
- package/dist/sync/next/compact-events.js.map +1 -0
- package/dist/sync/next/facts.d.ts +37 -0
- package/dist/sync/next/facts.d.ts.map +1 -0
- package/dist/sync/next/facts.js +156 -0
- package/dist/sync/next/facts.js.map +1 -0
- package/dist/sync/next/graphology.d.ts +8 -0
- package/dist/sync/next/graphology.d.ts.map +1 -0
- package/dist/sync/next/graphology.js +36 -0
- package/dist/sync/next/graphology.js.map +1 -0
- package/dist/sync/next/graphology_.d.ts +3 -0
- package/dist/sync/next/graphology_.d.ts.map +1 -0
- package/dist/sync/next/graphology_.js +3 -0
- package/dist/sync/next/graphology_.js.map +1 -0
- package/dist/sync/next/history-dag.d.ts +30 -0
- package/dist/sync/next/history-dag.d.ts.map +1 -0
- package/dist/sync/next/history-dag.js +69 -0
- package/dist/sync/next/history-dag.js.map +1 -0
- package/dist/sync/next/mod.d.ts +5 -0
- package/dist/sync/next/mod.d.ts.map +1 -0
- package/dist/sync/next/mod.js +5 -0
- package/dist/sync/next/mod.js.map +1 -0
- package/dist/sync/next/rebase-events.d.ts +27 -0
- package/dist/sync/next/rebase-events.d.ts.map +1 -0
- package/dist/sync/next/rebase-events.js +41 -0
- package/dist/sync/next/rebase-events.js.map +1 -0
- package/dist/sync/next/test/compact-events.calculator.test.d.ts +2 -0
- package/dist/sync/next/test/compact-events.calculator.test.d.ts.map +1 -0
- package/dist/sync/next/test/compact-events.calculator.test.js +101 -0
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -0
- package/dist/sync/next/test/compact-events.test.d.ts +2 -0
- package/dist/sync/next/test/compact-events.test.d.ts.map +1 -0
- package/dist/sync/next/test/compact-events.test.js +201 -0
- package/dist/sync/next/test/compact-events.test.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +2 -0
- package/dist/sync/next/test/mod.d.ts.map +1 -0
- package/dist/sync/next/test/mod.js +2 -0
- package/dist/sync/next/test/mod.js.map +1 -0
- package/dist/sync/next/test/mutation-fixtures.d.ts +73 -0
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/mutation-fixtures.js +161 -0
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -0
- package/dist/sync/sync.d.ts +45 -0
- package/dist/sync/sync.d.ts.map +1 -0
- package/dist/sync/sync.js +12 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/util.d.ts +25 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +38 -0
- package/dist/util.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +12 -0
- package/dist/version.js.map +1 -0
- package/package.json +61 -0
- package/src/__tests__/fixture.ts +23 -0
- package/src/adapter-types.ts +216 -0
- package/src/ambient.d.ts +3 -0
- package/src/bounded-collections.ts +121 -0
- package/src/debug-info.ts +76 -0
- package/src/derived-mutations.test.ts +101 -0
- package/src/derived-mutations.ts +170 -0
- package/src/devtools/devtools-bridge.ts +13 -0
- package/src/devtools/devtools-messages.ts +247 -0
- package/src/devtools/devtools-window-message.ts +27 -0
- package/src/devtools/index.ts +49 -0
- package/src/index.ts +20 -0
- package/src/init-singleton-tables.ts +24 -0
- package/src/mutation.ts +69 -0
- package/src/query-info.ts +104 -0
- package/src/rehydrate-from-mutationlog.ts +131 -0
- package/src/schema/index.ts +144 -0
- package/src/schema/mutations.ts +313 -0
- package/src/schema/schema-helpers.ts +49 -0
- package/src/schema/system-tables.ts +84 -0
- package/src/schema/table-def.ts +312 -0
- package/src/schema-management/common.ts +44 -0
- package/src/schema-management/migrations.ts +188 -0
- package/src/schema-management/validate-mutation-defs.ts +63 -0
- package/src/sql-queries/index.ts +3 -0
- package/src/sql-queries/misc.ts +2 -0
- package/src/sql-queries/sql-queries.ts +359 -0
- package/src/sql-queries/sql-query-builder.ts +135 -0
- package/src/sql-queries/types.ts +97 -0
- package/src/sync/index.ts +1 -0
- package/src/sync/next/ambient.d.ts +3 -0
- package/src/sync/next/compact-events.ts +218 -0
- package/src/sync/next/facts.ts +229 -0
- package/src/sync/next/graphology.ts +49 -0
- package/src/sync/next/graphology_.ts +2 -0
- package/src/sync/next/history-dag.ts +109 -0
- package/src/sync/next/mod.ts +4 -0
- package/src/sync/next/rebase-events.ts +97 -0
- package/src/sync/next/test/compact-events.calculator.test.ts +121 -0
- package/src/sync/next/test/compact-events.test.ts +232 -0
- package/src/sync/next/test/mod.ts +1 -0
- package/src/sync/next/test/mutation-fixtures.ts +230 -0
- package/src/sync/sync.ts +46 -0
- package/src/util.ts +56 -0
- package/src/version.ts +13 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { Cause, Queue, Scope, SubscriptionRef, WebChannel } from '@livestore/utils/effect'
|
|
2
|
+
import { Effect, Schema, Stream } from '@livestore/utils/effect'
|
|
3
|
+
|
|
4
|
+
import type * as Devtools from './devtools/index.js'
|
|
5
|
+
import type { LiveStoreSchema, MutationEvent } from './schema/index.js'
|
|
6
|
+
import type { PreparedBindValues } from './util.js'
|
|
7
|
+
|
|
8
|
+
export interface PreparedStatement {
|
|
9
|
+
execute(bindValues: PreparedBindValues | undefined, options?: { onRowsChanged?: (rowsChanged: number) => void }): void
|
|
10
|
+
select<T>(bindValues: PreparedBindValues | undefined): ReadonlyArray<T>
|
|
11
|
+
finalize(): void
|
|
12
|
+
sql: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ClientSession = {
|
|
16
|
+
/** SQLite database with synchronous API running in the same thread (usually in-memory) */
|
|
17
|
+
syncDb: SynchronousDatabase
|
|
18
|
+
/** The coordinator is responsible for persisting the database, syncing etc */
|
|
19
|
+
coordinator: Coordinator
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SynchronousDatabase = {
|
|
23
|
+
_tag: 'SynchronousDatabase'
|
|
24
|
+
prepare(queryStr: string): PreparedStatement
|
|
25
|
+
execute(
|
|
26
|
+
queryStr: string,
|
|
27
|
+
bindValues?: PreparedBindValues | undefined,
|
|
28
|
+
options?: { onRowsChanged?: (rowsChanged: number) => void },
|
|
29
|
+
): void
|
|
30
|
+
select<T>(queryStr: string, bindValues?: PreparedBindValues | undefined): ReadonlyArray<T>
|
|
31
|
+
export(): Uint8Array
|
|
32
|
+
close(): void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type ResetMode = 'all-data' | 'only-app-db'
|
|
36
|
+
|
|
37
|
+
export const NetworkStatus = Schema.Struct({
|
|
38
|
+
isConnected: Schema.Boolean,
|
|
39
|
+
timestampMs: Schema.Number,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export type NetworkStatus = {
|
|
43
|
+
isConnected: boolean
|
|
44
|
+
timestampMs: number
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const BootStateProgress = Schema.Struct({
|
|
48
|
+
done: Schema.Number,
|
|
49
|
+
total: Schema.Number,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
export const BootStatus = Schema.Union(
|
|
53
|
+
Schema.Struct({ stage: Schema.Literal('loading') }),
|
|
54
|
+
Schema.Struct({ stage: Schema.Literal('migrating'), progress: BootStateProgress }),
|
|
55
|
+
Schema.Struct({ stage: Schema.Literal('rehydrating'), progress: BootStateProgress }),
|
|
56
|
+
Schema.Struct({ stage: Schema.Literal('syncing'), progress: BootStateProgress }),
|
|
57
|
+
Schema.Struct({ stage: Schema.Literal('done') }),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
export type BootStatus = typeof BootStatus.Type
|
|
61
|
+
|
|
62
|
+
export type Coordinator = {
|
|
63
|
+
devtools: {
|
|
64
|
+
enabled: boolean
|
|
65
|
+
// TODO incorporate sessionId and rethink appHostId
|
|
66
|
+
appHostId: string
|
|
67
|
+
}
|
|
68
|
+
sessionId: string
|
|
69
|
+
// TODO is exposing the lock status really needed (or only relevant for web adapter?)
|
|
70
|
+
lockStatus: SubscriptionRef.SubscriptionRef<LockStatus>
|
|
71
|
+
syncMutations: Stream.Stream<MutationEvent.Any, UnexpectedError>
|
|
72
|
+
execute(queryStr: string, bindValues: PreparedBindValues | undefined): Effect.Effect<void, UnexpectedError>
|
|
73
|
+
mutate(
|
|
74
|
+
mutationEventEncoded: MutationEvent.AnyEncoded,
|
|
75
|
+
options: { persisted: boolean },
|
|
76
|
+
): Effect.Effect<void, UnexpectedError>
|
|
77
|
+
/** Can be called synchronously */
|
|
78
|
+
nextMutationEventIdPair: (opts: { localOnly: boolean }) => Effect.Effect<EventIdPair, UnexpectedError>
|
|
79
|
+
/** Used to initially get the current mutation event id to use as `parentId` for the next mutation event */
|
|
80
|
+
getCurrentMutationEventId: Effect.Effect<EventId, UnexpectedError>
|
|
81
|
+
export: Effect.Effect<Uint8Array | undefined, UnexpectedError>
|
|
82
|
+
getMutationLogData: Effect.Effect<Uint8Array, UnexpectedError>
|
|
83
|
+
networkStatus: SubscriptionRef.SubscriptionRef<NetworkStatus>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Can be used in queries to refer to the current session id.
|
|
88
|
+
* Will be replaced with the actual session id at runtime
|
|
89
|
+
*
|
|
90
|
+
* Example:
|
|
91
|
+
* ```ts
|
|
92
|
+
* const query$ = rowQuery(tables.app, SessionIdSymbol)
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export const SessionIdSymbol = Symbol.for('@livestore/session-id')
|
|
96
|
+
export type SessionIdSymbol = typeof SessionIdSymbol
|
|
97
|
+
|
|
98
|
+
export type LockStatus = 'has-lock' | 'no-lock'
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* LiveStore event id value consisting of a globally unique event sequence number
|
|
102
|
+
* and a local sequence number.
|
|
103
|
+
*
|
|
104
|
+
* The local sequence number is only used for localOnly mutations and starts from 0 for each global sequence number.
|
|
105
|
+
*/
|
|
106
|
+
export type EventId = { global: number; local: number }
|
|
107
|
+
|
|
108
|
+
export const EventId = Schema.Struct({
|
|
109
|
+
global: Schema.Number,
|
|
110
|
+
local: Schema.Number,
|
|
111
|
+
}).annotations({ title: 'LiveStore.EventId' })
|
|
112
|
+
|
|
113
|
+
export type EventIdPair = { id: EventId; parentId: EventId }
|
|
114
|
+
|
|
115
|
+
export const ROOT_ID = { global: -1, local: 0 } satisfies EventId
|
|
116
|
+
|
|
117
|
+
export type BootDb = {
|
|
118
|
+
_tag: 'BootDb'
|
|
119
|
+
execute(queryStr: string, bindValues?: PreparedBindValues): void
|
|
120
|
+
mutate: <const TMutationArg extends ReadonlyArray<MutationEvent.PartialAny>>(...list: TMutationArg) => void
|
|
121
|
+
select<T>(queryStr: string, bindValues?: PreparedBindValues): ReadonlyArray<T>
|
|
122
|
+
txn(callback: () => void): void
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export class UnexpectedError extends Schema.TaggedError<UnexpectedError>()('LiveStore.UnexpectedError', {
|
|
126
|
+
cause: Schema.Defect,
|
|
127
|
+
note: Schema.optional(Schema.String),
|
|
128
|
+
payload: Schema.optional(Schema.Any),
|
|
129
|
+
}) {
|
|
130
|
+
static mapToUnexpectedError = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
|
131
|
+
effect.pipe(
|
|
132
|
+
Effect.mapError((cause) => (Schema.is(UnexpectedError)(cause) ? cause : new UnexpectedError({ cause }))),
|
|
133
|
+
Effect.catchAllDefect((cause) => new UnexpectedError({ cause })),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
static mapToUnexpectedErrorStream = <A, E, R>(stream: Stream.Stream<A, E, R>) =>
|
|
137
|
+
stream.pipe(
|
|
138
|
+
Stream.mapError((cause) => (Schema.is(UnexpectedError)(cause) ? cause : new UnexpectedError({ cause }))),
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export class IntentionalShutdownCause extends Schema.TaggedError<IntentionalShutdownCause>()(
|
|
143
|
+
'LiveStore.IntentionalShutdownCause',
|
|
144
|
+
{
|
|
145
|
+
reason: Schema.Literal('devtools-reset', 'devtools-import'),
|
|
146
|
+
},
|
|
147
|
+
) {}
|
|
148
|
+
|
|
149
|
+
export class SqliteError extends Schema.TaggedError<SqliteError>()('LiveStore.SqliteError', {
|
|
150
|
+
query: Schema.optional(
|
|
151
|
+
Schema.Struct({
|
|
152
|
+
sql: Schema.String,
|
|
153
|
+
bindValues: Schema.Union(Schema.Record({ key: Schema.String, value: Schema.Any }), Schema.Array(Schema.Any)),
|
|
154
|
+
}),
|
|
155
|
+
),
|
|
156
|
+
/** The SQLite result code */
|
|
157
|
+
code: Schema.optional(Schema.Number),
|
|
158
|
+
/** The original SQLite3 error */
|
|
159
|
+
cause: Schema.Defect,
|
|
160
|
+
}) {}
|
|
161
|
+
|
|
162
|
+
// TODO possibly allow a combination of these options
|
|
163
|
+
// TODO allow a way to stream the migration progress back to the app
|
|
164
|
+
export type MigrationOptions<TSchema extends LiveStoreSchema = LiveStoreSchema> =
|
|
165
|
+
| MigrationOptionsFromMutationLog<TSchema>
|
|
166
|
+
| {
|
|
167
|
+
strategy: 'hard-reset'
|
|
168
|
+
hooks?: Partial<MigrationHooks>
|
|
169
|
+
}
|
|
170
|
+
| {
|
|
171
|
+
strategy: 'manual'
|
|
172
|
+
migrate: (oldDb: Uint8Array) => Uint8Array | Promise<Uint8Array> | Effect.Effect<Uint8Array, unknown>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export type MigrationHooks = {
|
|
176
|
+
/** Runs on the empty in-memory database with no database schemas applied yet */
|
|
177
|
+
init: MigrationHook
|
|
178
|
+
/** Runs before applying the migration strategy but after table schemas have been applied and singleton rows have been created */
|
|
179
|
+
pre: MigrationHook
|
|
180
|
+
/** Runs after applying the migration strategy before creating export snapshot and closing the database */
|
|
181
|
+
post: MigrationHook
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type MigrationHook = (db: SynchronousDatabase) => void | Promise<void> | Effect.Effect<void, unknown>
|
|
185
|
+
|
|
186
|
+
export type MigrationOptionsFromMutationLog<TSchema extends LiveStoreSchema = LiveStoreSchema> = {
|
|
187
|
+
strategy: 'from-mutation-log'
|
|
188
|
+
/**
|
|
189
|
+
* Mutations to exclude in the mutation log
|
|
190
|
+
*
|
|
191
|
+
* @default new Set(['livestore.RawSql'])
|
|
192
|
+
*/
|
|
193
|
+
excludeMutations?: ReadonlySet<keyof TSchema['_MutationDefMapType'] & string>
|
|
194
|
+
hooks?: Partial<MigrationHooks>
|
|
195
|
+
logging?: {
|
|
196
|
+
excludeAffectedRows?: (sqlStmt: string) => boolean
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export type StoreDevtoolsChannel = WebChannel.WebChannel<
|
|
201
|
+
Devtools.MessageToAppHostStore,
|
|
202
|
+
Devtools.MessageFromAppHostStore
|
|
203
|
+
>
|
|
204
|
+
|
|
205
|
+
export type ConnectDevtoolsToStore = (
|
|
206
|
+
storeDevtoolsChannel: StoreDevtoolsChannel,
|
|
207
|
+
) => Effect.Effect<void, UnexpectedError, Scope.Scope>
|
|
208
|
+
|
|
209
|
+
export type Adapter = (opts: {
|
|
210
|
+
schema: LiveStoreSchema
|
|
211
|
+
storeId: string
|
|
212
|
+
devtoolsEnabled: boolean
|
|
213
|
+
bootStatusQueue: Queue.Queue<BootStatus>
|
|
214
|
+
shutdown: (cause: Cause.Cause<any>) => Effect.Effect<void>
|
|
215
|
+
connectDevtoolsToStore: ConnectDevtoolsToStore
|
|
216
|
+
}) => Effect.Effect<ClientSession, UnexpectedError, Scope.Scope>
|
package/src/ambient.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a map that has a fixed number of entries.
|
|
3
|
+
* Once hitting the bound, earliest insertions are removed
|
|
4
|
+
*/
|
|
5
|
+
export class BoundMap<K, V> {
|
|
6
|
+
#map = new Map<K, V>()
|
|
7
|
+
#sizeLimit: number
|
|
8
|
+
|
|
9
|
+
constructor(sizeLimit: number) {
|
|
10
|
+
this.#sizeLimit = sizeLimit
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
onEvict: ((key: K, value: V) => void) | undefined
|
|
14
|
+
|
|
15
|
+
set = (key: K, value: V) => {
|
|
16
|
+
this.#map.set(key, value)
|
|
17
|
+
// console.log(this.#map.size, this.#sizeLimit);
|
|
18
|
+
if (this.#map.size > this.#sizeLimit) {
|
|
19
|
+
const firstKey = this.#map.keys().next().value as K
|
|
20
|
+
const deletedValue = this.#map.get(firstKey)!
|
|
21
|
+
this.#map.delete(firstKey)
|
|
22
|
+
if (this.onEvict) {
|
|
23
|
+
this.onEvict(firstKey, deletedValue)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get = (key: K): V | undefined => {
|
|
29
|
+
return this.#map.get(key)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
delete = (key: K) => {
|
|
33
|
+
this.#map.delete(key)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
keys = () => {
|
|
37
|
+
return this.#map.keys()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class BoundSet<V> {
|
|
42
|
+
#map: BoundMap<V, V>
|
|
43
|
+
|
|
44
|
+
constructor(sizeLimit: number) {
|
|
45
|
+
this.#map = new BoundMap(sizeLimit)
|
|
46
|
+
this.#map.onEvict = this.#onEvict
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#onEvict = (v: V) => {
|
|
50
|
+
if (this.onEvict) {
|
|
51
|
+
this.onEvict(v)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onEvict: ((key: V) => void) | undefined
|
|
56
|
+
|
|
57
|
+
add = (v: V) => {
|
|
58
|
+
this.#map.set(v, v)
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
[Symbol.iterator] = () => {
|
|
62
|
+
return this.#map.keys()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class BoundArray<V> {
|
|
67
|
+
#array: V[] = []
|
|
68
|
+
public sizeLimit: number
|
|
69
|
+
|
|
70
|
+
constructor(sizeLimit: number) {
|
|
71
|
+
this.sizeLimit = sizeLimit
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static make = <V>(sizeLimit: number, initial: Iterable<V> = []): BoundArray<V> => {
|
|
75
|
+
const b = new BoundArray<V>(sizeLimit)
|
|
76
|
+
for (const v of initial) {
|
|
77
|
+
b.push(v)
|
|
78
|
+
}
|
|
79
|
+
return b
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onEvict: ((key: V) => void) | undefined
|
|
83
|
+
|
|
84
|
+
push = (v: V) => {
|
|
85
|
+
this.#array.push(v)
|
|
86
|
+
if (this.#array.length > this.sizeLimit) {
|
|
87
|
+
const first = this.#array.shift()
|
|
88
|
+
if (first && this.onEvict) {
|
|
89
|
+
this.onEvict(first)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get = (index: number): V | undefined => {
|
|
95
|
+
return this.#array[index]
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
delete = (index: number) => {
|
|
99
|
+
this.#array.splice(index, 1)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
get length() {
|
|
103
|
+
return this.#array.length
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
[Symbol.iterator] = (): IterableIterator<V> => {
|
|
107
|
+
return this.#array[Symbol.iterator]()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
map = <T>(fn: (v: V) => T): T[] => {
|
|
111
|
+
return this.#array.map(fn)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
clear = () => {
|
|
115
|
+
this.#array = []
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
sort = (fn?: (a: V, b: V) => number) => {
|
|
119
|
+
return this.#array.sort(fn)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ParseResult, Schema } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import { BoundArray } from './bounded-collections.js'
|
|
4
|
+
import { PreparedBindValues } from './util.js'
|
|
5
|
+
|
|
6
|
+
export type SlowQueryInfo = {
|
|
7
|
+
queryStr: string
|
|
8
|
+
bindValues: PreparedBindValues | undefined
|
|
9
|
+
durationMs: number
|
|
10
|
+
rowsCount: number | undefined
|
|
11
|
+
queriedTables: Set<string>
|
|
12
|
+
startTimePerfNow: DOMHighResTimeStamp
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const SlowQueryInfo = Schema.Struct({
|
|
16
|
+
queryStr: Schema.String,
|
|
17
|
+
bindValues: Schema.UndefinedOr(PreparedBindValues),
|
|
18
|
+
durationMs: Schema.Number,
|
|
19
|
+
rowsCount: Schema.UndefinedOr(Schema.Number),
|
|
20
|
+
queriedTables: Schema.ReadonlySet(Schema.String),
|
|
21
|
+
startTimePerfNow: Schema.Number,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const BoundArraySchemaFromSelf = <A, I, R>(
|
|
25
|
+
item: Schema.Schema<A, I, R>,
|
|
26
|
+
): Schema.Schema<BoundArray<A>, BoundArray<I>, R> =>
|
|
27
|
+
Schema.declare(
|
|
28
|
+
[item],
|
|
29
|
+
{
|
|
30
|
+
decode: (item) => (input, parseOptions, ast) => {
|
|
31
|
+
if (input instanceof BoundArray) {
|
|
32
|
+
const elements = ParseResult.decodeUnknown(Schema.Array(item))([...input], parseOptions)
|
|
33
|
+
return ParseResult.map(elements, (as): BoundArray<A> => BoundArray.make(input.sizeLimit, as))
|
|
34
|
+
}
|
|
35
|
+
return ParseResult.fail(new ParseResult.Type(ast, input))
|
|
36
|
+
},
|
|
37
|
+
encode: (item) => (input, parseOptions, ast) => {
|
|
38
|
+
if (input instanceof BoundArray) {
|
|
39
|
+
const elements = ParseResult.encodeUnknown(Schema.Array(item))([...input], parseOptions)
|
|
40
|
+
return ParseResult.map(elements, (is): BoundArray<I> => BoundArray.make(input.sizeLimit, is))
|
|
41
|
+
}
|
|
42
|
+
return ParseResult.fail(new ParseResult.Type(ast, input))
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
description: `BoundArray<${Schema.format(item)}>`,
|
|
47
|
+
pretty: () => (_) => `BoundArray(${_.length})`,
|
|
48
|
+
arbitrary: () => (fc) => fc.anything() as any,
|
|
49
|
+
equivalence: () => (a, b) => a === b,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
export const BoundArraySchema = <ItemDecoded, ItemEncoded>(elSchema: Schema.Schema<ItemDecoded, ItemEncoded>) =>
|
|
54
|
+
Schema.transform(
|
|
55
|
+
Schema.Struct({
|
|
56
|
+
size: Schema.Number,
|
|
57
|
+
items: Schema.Array(elSchema),
|
|
58
|
+
}),
|
|
59
|
+
BoundArraySchemaFromSelf(Schema.typeSchema(elSchema)),
|
|
60
|
+
{
|
|
61
|
+
encode: (_) => ({ size: _.sizeLimit, items: [..._] }),
|
|
62
|
+
decode: (_) => BoundArray.make(_.size, _.items),
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export const DebugInfo = Schema.Struct({
|
|
67
|
+
slowQueries: BoundArraySchema(SlowQueryInfo),
|
|
68
|
+
queryFrameDuration: Schema.Number,
|
|
69
|
+
queryFrameCount: Schema.Number,
|
|
70
|
+
events: BoundArraySchema(Schema.Tuple(Schema.String, Schema.Any)),
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export type DebugInfo = typeof DebugInfo.Type
|
|
74
|
+
|
|
75
|
+
export const MutableDebugInfo = Schema.mutable(DebugInfo)
|
|
76
|
+
export type MutableDebugInfo = typeof MutableDebugInfo.Type
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { appConfig, todos } from './__tests__/fixture.js'
|
|
4
|
+
import type { MutationEvent } from './schema/mutations.js'
|
|
5
|
+
|
|
6
|
+
describe('derived mutations', () => {
|
|
7
|
+
test('todos', () => {
|
|
8
|
+
expect(patchId(todos.insert({ id: 't1', completed: true, text: 'Task 1' }))).toMatchInlineSnapshot(`
|
|
9
|
+
{
|
|
10
|
+
"args": {
|
|
11
|
+
"completed": true,
|
|
12
|
+
"id": "t1",
|
|
13
|
+
"text": "Task 1",
|
|
14
|
+
},
|
|
15
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
16
|
+
"mutation": "_Derived_Create_todos",
|
|
17
|
+
}
|
|
18
|
+
`)
|
|
19
|
+
|
|
20
|
+
expect(patchId(todos.update({ where: { id: 't1' }, values: { text: 'Task 1 - fixed' } }))).toMatchInlineSnapshot(`
|
|
21
|
+
{
|
|
22
|
+
"args": {
|
|
23
|
+
"values": {
|
|
24
|
+
"text": "Task 1 - fixed",
|
|
25
|
+
},
|
|
26
|
+
"where": {
|
|
27
|
+
"id": "t1",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
31
|
+
"mutation": "_Derived_Update_todos",
|
|
32
|
+
}
|
|
33
|
+
`)
|
|
34
|
+
|
|
35
|
+
expect(patchId(todos.delete({ where: { id: 't1' } }))).toMatchInlineSnapshot(`
|
|
36
|
+
{
|
|
37
|
+
"args": {
|
|
38
|
+
"where": {
|
|
39
|
+
"id": "t1",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
43
|
+
"mutation": "_Derived_Delete_todos",
|
|
44
|
+
}
|
|
45
|
+
`)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('app_config', () => {
|
|
49
|
+
expect(patchId(appConfig.insert())).toMatchInlineSnapshot(`
|
|
50
|
+
{
|
|
51
|
+
"args": {
|
|
52
|
+
"id": "singleton",
|
|
53
|
+
"value": {
|
|
54
|
+
"value": undefined,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
58
|
+
"mutation": "_Derived_Create_app_config",
|
|
59
|
+
}
|
|
60
|
+
`)
|
|
61
|
+
|
|
62
|
+
expect(patchId(appConfig.insert({ fontSize: 12, theme: 'dark' }))).toMatchInlineSnapshot(`
|
|
63
|
+
{
|
|
64
|
+
"args": {
|
|
65
|
+
"id": "singleton",
|
|
66
|
+
"value": {
|
|
67
|
+
"value": {
|
|
68
|
+
"fontSize": 12,
|
|
69
|
+
"theme": "dark",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
74
|
+
"mutation": "_Derived_Create_app_config",
|
|
75
|
+
}
|
|
76
|
+
`)
|
|
77
|
+
|
|
78
|
+
expect(patchId(appConfig.update({ fontSize: 13 }))).toMatchInlineSnapshot(`
|
|
79
|
+
{
|
|
80
|
+
"args": {
|
|
81
|
+
"values": {
|
|
82
|
+
"value": {
|
|
83
|
+
"fontSize": 13,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
"where": {
|
|
87
|
+
"id": "singleton",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
"id": "00000000-0000-0000-0000-000000000000",
|
|
91
|
+
"mutation": "_Derived_Update_app_config",
|
|
92
|
+
}
|
|
93
|
+
`)
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const patchId = (muationEvent: MutationEvent.PartialAny) => {
|
|
98
|
+
// TODO use new id paradigm
|
|
99
|
+
const id = `00000000-0000-0000-0000-000000000000`
|
|
100
|
+
return { ...muationEvent, id }
|
|
101
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { SqliteDsl } from '@livestore/db-schema'
|
|
2
|
+
import type { GetValForKey } from '@livestore/utils'
|
|
3
|
+
import { ReadonlyRecord, Schema } from '@livestore/utils/effect'
|
|
4
|
+
|
|
5
|
+
import type { MutationEvent } from './schema/mutations.js'
|
|
6
|
+
import { defineMutation } from './schema/mutations.js'
|
|
7
|
+
import { getDefaultValuesDecoded } from './schema/schema-helpers.js'
|
|
8
|
+
import type * as DbSchema from './schema/table-def.js'
|
|
9
|
+
import { deleteRows, insertRow, updateRows } from './sql-queries/sql-queries.js'
|
|
10
|
+
|
|
11
|
+
export const makeDerivedMutationDefsForTable = <
|
|
12
|
+
TTableDef extends DbSchema.TableDef<
|
|
13
|
+
DbSchema.DefaultSqliteTableDefConstrained,
|
|
14
|
+
boolean,
|
|
15
|
+
DbSchema.TableOptions & { deriveMutations: { enabled: true } }
|
|
16
|
+
>,
|
|
17
|
+
>(
|
|
18
|
+
table: TTableDef,
|
|
19
|
+
) => ({
|
|
20
|
+
insert: deriveCreateMutationDef(table),
|
|
21
|
+
update: deriveUpdateMutationDef(table),
|
|
22
|
+
delete: deriveDeleteMutationDef(table),
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const deriveCreateMutationDef = <
|
|
26
|
+
TTableDef extends DbSchema.TableDef<
|
|
27
|
+
DbSchema.DefaultSqliteTableDefConstrained,
|
|
28
|
+
boolean,
|
|
29
|
+
DbSchema.TableOptions & { deriveMutations: { enabled: true } }
|
|
30
|
+
>,
|
|
31
|
+
>(
|
|
32
|
+
table: TTableDef,
|
|
33
|
+
) => {
|
|
34
|
+
const tableName = table.sqliteDef.name
|
|
35
|
+
|
|
36
|
+
const [optionalFields, requiredColumns] = ReadonlyRecord.partition(
|
|
37
|
+
(table.sqliteDef as DbSchema.DefaultSqliteTableDef).columns,
|
|
38
|
+
(col) => col.nullable === false && col.default._tag === 'None',
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const insertSchema = Schema.Struct(ReadonlyRecord.map(requiredColumns, (col) => col.schema))
|
|
42
|
+
.pipe(Schema.extend(Schema.partial(Schema.Struct(ReadonlyRecord.map(optionalFields, (col) => col.schema)))))
|
|
43
|
+
.annotations({ title: `${tableName}:Insert` })
|
|
44
|
+
|
|
45
|
+
return defineMutation(
|
|
46
|
+
`_Derived_Create_${tableName}`,
|
|
47
|
+
insertSchema,
|
|
48
|
+
({ id, ...explicitDefaultValues }) => {
|
|
49
|
+
const defaultValues = getDefaultValuesDecoded(table, explicitDefaultValues)
|
|
50
|
+
|
|
51
|
+
const [sql, bindValues] = insertRow({
|
|
52
|
+
tableName: table.sqliteDef.name,
|
|
53
|
+
columns: table.sqliteDef.columns,
|
|
54
|
+
values: { ...defaultValues, id },
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return { sql, bindValues, writeTables: new Set([tableName]) }
|
|
58
|
+
},
|
|
59
|
+
{ localOnly: table.options.deriveMutations.localOnly },
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const deriveUpdateMutationDef = <
|
|
64
|
+
TTableDef extends DbSchema.TableDef<
|
|
65
|
+
DbSchema.DefaultSqliteTableDefConstrained,
|
|
66
|
+
boolean,
|
|
67
|
+
DbSchema.TableOptions & { deriveMutations: { enabled: true } }
|
|
68
|
+
>,
|
|
69
|
+
>(
|
|
70
|
+
table: TTableDef,
|
|
71
|
+
) => {
|
|
72
|
+
const tableName = table.sqliteDef.name
|
|
73
|
+
|
|
74
|
+
return defineMutation(
|
|
75
|
+
`_Derived_Update_${tableName}`,
|
|
76
|
+
Schema.Struct({
|
|
77
|
+
where: Schema.partial(table.schema),
|
|
78
|
+
values: Schema.partial(table.schema),
|
|
79
|
+
}).annotations({ title: `${tableName}:Update` }),
|
|
80
|
+
({ where, values }) => {
|
|
81
|
+
const [sql, bindValues] = updateRows({
|
|
82
|
+
tableName: table.sqliteDef.name,
|
|
83
|
+
columns: table.sqliteDef.columns,
|
|
84
|
+
where,
|
|
85
|
+
updateValues: values,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return { sql, bindValues, writeTables: new Set([tableName]) }
|
|
89
|
+
},
|
|
90
|
+
{ localOnly: table.options.deriveMutations.localOnly },
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const deriveDeleteMutationDef = <
|
|
95
|
+
TTableDef extends DbSchema.TableDef<
|
|
96
|
+
DbSchema.DefaultSqliteTableDefConstrained,
|
|
97
|
+
boolean,
|
|
98
|
+
DbSchema.TableOptions & { deriveMutations: { enabled: true } }
|
|
99
|
+
>,
|
|
100
|
+
>(
|
|
101
|
+
table: TTableDef,
|
|
102
|
+
) => {
|
|
103
|
+
const tableName = table.sqliteDef.name
|
|
104
|
+
|
|
105
|
+
return defineMutation(
|
|
106
|
+
`_Derived_Delete_${tableName}`,
|
|
107
|
+
Schema.Struct({
|
|
108
|
+
where: Schema.partial(table.schema),
|
|
109
|
+
}),
|
|
110
|
+
({ where }) => {
|
|
111
|
+
const [sql, bindValues] = deleteRows({
|
|
112
|
+
tableName: table.sqliteDef.name,
|
|
113
|
+
columns: table.sqliteDef.columns,
|
|
114
|
+
where,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return { sql, bindValues, writeTables: new Set([tableName]) }
|
|
118
|
+
},
|
|
119
|
+
{ localOnly: table.options.deriveMutations.localOnly },
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Convenience helper functions on top of the derived mutation definitions.
|
|
125
|
+
*/
|
|
126
|
+
export type DerivedMutationHelperFns<
|
|
127
|
+
TColumns extends SqliteDsl.ConstraintColumns,
|
|
128
|
+
TOptions extends DbSchema.TableOptions,
|
|
129
|
+
> = {
|
|
130
|
+
insert: DerivedMutationHelperFns.InsertMutationFn<TColumns, TOptions>
|
|
131
|
+
update: DerivedMutationHelperFns.UpdateMutationFn<TColumns, TOptions>
|
|
132
|
+
delete: DerivedMutationHelperFns.DeleteMutationFn<TColumns, TOptions>
|
|
133
|
+
// TODO also consider adding upsert and deep json mutations (like lenses)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export namespace DerivedMutationHelperFns {
|
|
137
|
+
export type InsertMutationFn<
|
|
138
|
+
TColumns extends SqliteDsl.ConstraintColumns,
|
|
139
|
+
TOptions extends DbSchema.TableOptions,
|
|
140
|
+
> = SqliteDsl.AnyIfConstained<
|
|
141
|
+
TColumns,
|
|
142
|
+
UseShortcut<TOptions> extends true
|
|
143
|
+
? (values?: GetValForKey<SqliteDsl.FromColumns.InsertRowDecoded<TColumns>, 'value'>) => MutationEvent.PartialAny
|
|
144
|
+
: (values: SqliteDsl.FromColumns.InsertRowDecoded<TColumns>) => MutationEvent.PartialAny
|
|
145
|
+
>
|
|
146
|
+
|
|
147
|
+
export type UpdateMutationFn<
|
|
148
|
+
TColumns extends SqliteDsl.ConstraintColumns,
|
|
149
|
+
TOptions extends DbSchema.TableOptions,
|
|
150
|
+
> = SqliteDsl.AnyIfConstained<
|
|
151
|
+
TColumns,
|
|
152
|
+
UseShortcut<TOptions> extends true
|
|
153
|
+
? (values: Partial<GetValForKey<SqliteDsl.FromColumns.RowDecoded<TColumns>, 'value'>>) => MutationEvent.PartialAny
|
|
154
|
+
: (args: {
|
|
155
|
+
where: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>
|
|
156
|
+
values: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>>
|
|
157
|
+
}) => MutationEvent.PartialAny
|
|
158
|
+
>
|
|
159
|
+
|
|
160
|
+
export type DeleteMutationFn<
|
|
161
|
+
TColumns extends SqliteDsl.ConstraintColumns,
|
|
162
|
+
_TOptions extends DbSchema.TableOptions,
|
|
163
|
+
> = (args: { where: Partial<SqliteDsl.FromColumns.RowDecoded<TColumns>> }) => MutationEvent.PartialAny
|
|
164
|
+
|
|
165
|
+
type UseShortcut<TOptions extends DbSchema.TableOptions> = TOptions['isSingleColumn'] extends true
|
|
166
|
+
? TOptions['isSingleton'] extends true
|
|
167
|
+
? true
|
|
168
|
+
: false
|
|
169
|
+
: false
|
|
170
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Effect, PubSub } from '@livestore/utils/effect'
|
|
2
|
+
|
|
3
|
+
import type * as Devtools from './devtools-messages.js'
|
|
4
|
+
|
|
5
|
+
export type PrepareDevtoolsBridge = {
|
|
6
|
+
/** Messages coming from the app host (usually responses to requests) */
|
|
7
|
+
responsePubSub: PubSub.PubSub<Devtools.MessageFromAppHostCoordinator | Devtools.MessageFromAppHostStore>
|
|
8
|
+
sendToAppHost: (msg: Devtools.MessageToAppHostCoordinator | Devtools.MessageToAppHostStore) => Effect.Effect<void>
|
|
9
|
+
appHostId: string
|
|
10
|
+
copyToClipboard: (text: string) => Effect.Effect<void>
|
|
11
|
+
sendEscapeKey?: Effect.Effect<void>
|
|
12
|
+
isLeader: boolean
|
|
13
|
+
}
|