@livestore/livestore 0.0.47-dev.0 → 0.0.48-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/MainDatabaseWrapper.d.ts +2 -2
- package/dist/MainDatabaseWrapper.d.ts.map +1 -1
- package/dist/MainDatabaseWrapper.js.map +1 -1
- package/dist/__tests__/react/fixture.d.ts +262 -158
- package/dist/__tests__/react/fixture.d.ts.map +1 -1
- package/dist/__tests__/react/fixture.js +14 -12
- package/dist/__tests__/react/fixture.js.map +1 -1
- package/dist/__tests__/react/utils/otel.d.ts +1 -1
- package/dist/__tests__/react/utils/otel.d.ts.map +1 -1
- package/dist/effect/LiveStore.d.ts +5 -5
- package/dist/effect/LiveStore.d.ts.map +1 -1
- package/dist/effect/LiveStore.js +5 -4
- package/dist/effect/LiveStore.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/react/LiveStoreProvider.d.ts +4 -4
- package/dist/react/LiveStoreProvider.d.ts.map +1 -1
- package/dist/react/LiveStoreProvider.js +8 -8
- package/dist/react/LiveStoreProvider.js.map +1 -1
- package/dist/react/LiveStoreProvider.test.js +3 -4
- package/dist/react/LiveStoreProvider.test.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/useAtom.d.ts +5 -2
- package/dist/react/useAtom.d.ts.map +1 -1
- package/dist/react/useAtom.js +20 -4
- package/dist/react/useAtom.js.map +1 -1
- package/dist/react/useLocalId.d.ts +10 -0
- package/dist/react/useLocalId.d.ts.map +1 -0
- package/dist/react/useLocalId.js +15 -0
- package/dist/react/useLocalId.js.map +1 -0
- package/dist/react/useQuery.test.js +7 -7
- package/dist/react/useQuery.test.js.map +1 -1
- package/dist/react/useRow.d.ts +3 -1
- package/dist/react/useRow.d.ts.map +1 -1
- package/dist/react/useRow.js +25 -8
- package/dist/react/useRow.js.map +1 -1
- package/dist/react/useRow.test.js +58 -29
- package/dist/react/useRow.test.js.map +1 -1
- package/dist/react/useTemporaryQuery.d.ts +1 -1
- package/dist/react/useTemporaryQuery.d.ts.map +1 -1
- package/dist/react/useTemporaryQuery.js.map +1 -1
- package/dist/react/useTemporaryQuery.test.js +3 -3
- package/dist/react/useTemporaryQuery.test.js.map +1 -1
- package/dist/react/utils/useStateRefWithReactiveInput.d.ts.map +1 -1
- package/dist/reactive.test.js +1 -1
- package/dist/reactive.test.js.map +1 -1
- package/dist/reactiveQueries/base-class.d.ts +1 -1
- package/dist/reactiveQueries/base-class.d.ts.map +1 -1
- package/dist/reactiveQueries/base-class.js.map +1 -1
- package/dist/reactiveQueries/graphql.d.ts +4 -4
- package/dist/reactiveQueries/graphql.d.ts.map +1 -1
- package/dist/reactiveQueries/graphql.js +2 -1
- package/dist/reactiveQueries/graphql.js.map +1 -1
- package/dist/reactiveQueries/js.d.ts +1 -1
- package/dist/reactiveQueries/js.d.ts.map +1 -1
- package/dist/reactiveQueries/js.js.map +1 -1
- package/dist/reactiveQueries/sql.d.ts +1 -1
- package/dist/reactiveQueries/sql.d.ts.map +1 -1
- package/dist/reactiveQueries/sql.js +2 -2
- package/dist/reactiveQueries/sql.js.map +1 -1
- package/dist/row-query.d.ts +3 -3
- package/dist/row-query.d.ts.map +1 -1
- package/dist/row-query.js +47 -34
- package/dist/row-query.js.map +1 -1
- package/dist/store.d.ts +20 -19
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +67 -41
- 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/util.d.ts +0 -1
- package/dist/utils/util.d.ts.map +1 -1
- package/dist/utils/util.js.map +1 -1
- package/package.json +16 -16
- package/src/MainDatabaseWrapper.ts +3 -3
- package/src/__tests__/react/fixture.tsx +32 -18
- package/src/effect/LiveStore.ts +9 -8
- package/src/index.ts +7 -5
- package/src/react/LiveStoreProvider.test.tsx +5 -5
- package/src/react/LiveStoreProvider.tsx +11 -11
- package/src/react/index.ts +1 -0
- package/src/react/useAtom.ts +31 -5
- package/src/react/useLocalId.ts +25 -0
- package/src/react/useQuery.test.tsx +8 -8
- package/src/react/useRow.test.tsx +60 -35
- package/src/react/useRow.ts +43 -12
- package/src/react/useTemporaryQuery.test.tsx +4 -4
- package/src/react/useTemporaryQuery.ts +1 -1
- package/src/reactive.test.ts +1 -1
- package/src/reactiveQueries/base-class.ts +1 -1
- package/src/reactiveQueries/graphql.ts +3 -2
- package/src/reactiveQueries/js.ts +1 -1
- package/src/reactiveQueries/sql.ts +3 -3
- package/src/row-query.ts +67 -55
- package/src/store.ts +89 -59
- package/src/utils/util.ts +0 -2
- package/dist/cud.d.ts +0 -28
- package/dist/cud.d.ts.map +0 -1
- package/dist/cud.js +0 -47
- package/dist/cud.js.map +0 -1
- package/dist/cud.test.d.ts +0 -2
- package/dist/cud.test.d.ts.map +0 -1
- package/dist/cud.test.js +0 -47
- package/dist/cud.test.js.map +0 -1
- package/dist/migrations.d.ts +0 -16
- package/dist/migrations.d.ts.map +0 -1
- package/dist/migrations.js +0 -98
- package/dist/migrations.js.map +0 -1
- package/dist/query-info.d.ts +0 -48
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -39
- package/dist/query-info.js.map +0 -1
- package/src/cud.test.ts +0 -52
- package/src/cud.ts +0 -88
- package/src/migrations.ts +0 -151
- package/src/query-info.ts +0 -104
package/src/store.ts
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type DatabaseImpl,
|
|
4
|
-
getExecArgsFromMutation,
|
|
5
|
-
type PreparedBindValues,
|
|
6
|
-
} from '@livestore/common'
|
|
1
|
+
import type { BootDb, PreparedBindValues, ResetMode, StoreAdapter, StoreAdapterFactory } from '@livestore/common'
|
|
2
|
+
import { getExecArgsFromMutation } from '@livestore/common'
|
|
7
3
|
import type { LiveStoreSchema, MutationEvent, MutationEventSchema } from '@livestore/common/schema'
|
|
8
4
|
import { makeMutationEventSchema } from '@livestore/common/schema'
|
|
9
5
|
import { assertNever, isPromise, makeNoopTracer, shouldNeverHappen } from '@livestore/utils'
|
|
10
|
-
import { Schema } from '@livestore/utils/effect'
|
|
6
|
+
import { Effect, Schema, Stream } from '@livestore/utils/effect'
|
|
11
7
|
import * as otel from '@opentelemetry/api'
|
|
12
8
|
import type { GraphQLSchema } from 'graphql'
|
|
13
9
|
|
|
@@ -36,9 +32,7 @@ export type StoreOptions<
|
|
|
36
32
|
TGraphQLContext extends BaseGraphQLContext,
|
|
37
33
|
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
|
38
34
|
> = {
|
|
39
|
-
|
|
40
|
-
// /** A `Proxy`d version of `db` except that it also mirrors `execute` calls to the storage */
|
|
41
|
-
// dbProxy: InMemoryDatabase
|
|
35
|
+
adapter: StoreAdapter
|
|
42
36
|
schema: TSchema
|
|
43
37
|
graphQLOptions?: GraphQLOptions<TGraphQLContext>
|
|
44
38
|
otelTracer: otel.Tracer
|
|
@@ -81,13 +75,6 @@ export type StoreOtel = {
|
|
|
81
75
|
let storeCount = 0
|
|
82
76
|
const uniqueStoreId = () => `store-${++storeCount}`
|
|
83
77
|
|
|
84
|
-
export type BootDb = {
|
|
85
|
-
execute(queryStr: string, bindValues?: ParamsObject): void
|
|
86
|
-
mutate: <const TMutationArg extends ReadonlyArray<MutationEvent.Any>>(...list: TMutationArg) => void
|
|
87
|
-
select<T>(queryStr: string, bindValues?: ParamsObject): ReadonlyArray<T>
|
|
88
|
-
txn(callback: () => void): void
|
|
89
|
-
}
|
|
90
|
-
|
|
91
78
|
export class Store<
|
|
92
79
|
TGraphQLContext extends BaseGraphQLContext = BaseGraphQLContext,
|
|
93
80
|
TSchema extends LiveStoreSchema = LiveStoreSchema,
|
|
@@ -98,7 +85,7 @@ export class Store<
|
|
|
98
85
|
// TODO refactor
|
|
99
86
|
// _proxyDb: InMemoryDatabase
|
|
100
87
|
// TODO
|
|
101
|
-
|
|
88
|
+
adapter: StoreAdapter
|
|
102
89
|
schema: LiveStoreSchema
|
|
103
90
|
graphQLSchema?: GraphQLSchema
|
|
104
91
|
graphQLContext?: TGraphQLContext
|
|
@@ -109,14 +96,17 @@ export class Store<
|
|
|
109
96
|
*/
|
|
110
97
|
tableRefs: { [key: string]: Ref<null, DbContext, RefreshReason> }
|
|
111
98
|
|
|
99
|
+
// TODO remove this temporary solution and find a better way to avoid re-processing the same mutation
|
|
100
|
+
__processedMutationIds = new Set<string>()
|
|
101
|
+
__processedMutationWithoutRefreshIds = new Set<string>()
|
|
102
|
+
|
|
112
103
|
/** RC-based set to see which queries are currently subscribed to */
|
|
113
104
|
activeQueries: ReferenceCountedSet<LiveQuery<any>>
|
|
114
105
|
|
|
115
106
|
private mutationEventSchema
|
|
116
107
|
|
|
117
108
|
private constructor({
|
|
118
|
-
|
|
119
|
-
// dbProxy,
|
|
109
|
+
adapter,
|
|
120
110
|
schema,
|
|
121
111
|
graphQLOptions,
|
|
122
112
|
dbGraph,
|
|
@@ -124,9 +114,8 @@ export class Store<
|
|
|
124
114
|
otelRootSpanContext,
|
|
125
115
|
mutationEventSchema,
|
|
126
116
|
}: StoreOptions<TGraphQLContext, TSchema>) {
|
|
127
|
-
this.mainDbWrapper = new MainDatabaseWrapper({ otelTracer, otelRootSpanContext, db:
|
|
128
|
-
this.
|
|
129
|
-
// this._proxyDb = dbProxy
|
|
117
|
+
this.mainDbWrapper = new MainDatabaseWrapper({ otelTracer, otelRootSpanContext, db: adapter.mainDb })
|
|
118
|
+
this.adapter = adapter
|
|
130
119
|
this.schema = schema
|
|
131
120
|
|
|
132
121
|
// TODO refactor
|
|
@@ -136,7 +125,6 @@ export class Store<
|
|
|
136
125
|
// TODO generalize the `tableRefs` concept to allow finer-grained refs
|
|
137
126
|
this.tableRefs = {}
|
|
138
127
|
this.activeQueries = new ReferenceCountedSet()
|
|
139
|
-
// this.storage = storage
|
|
140
128
|
|
|
141
129
|
const mutationsSpan = otelTracer.startSpan('LiveStore:mutations', {}, otelRootSpanContext)
|
|
142
130
|
const otelMuationsSpanContext = otel.trace.setSpan(otel.context.active(), mutationsSpan)
|
|
@@ -147,6 +135,15 @@ export class Store<
|
|
|
147
135
|
this.graph = dbGraph
|
|
148
136
|
this.graph.context = { store: this as any, otelTracer, rootOtelContext: otelQueriesSpanContext }
|
|
149
137
|
|
|
138
|
+
this.adapter.coordinator.syncMutations.pipe(
|
|
139
|
+
Stream.tapSync((mutationEventDecoded) => {
|
|
140
|
+
this.mutate({ wasSyncMessage: true }, mutationEventDecoded)
|
|
141
|
+
}),
|
|
142
|
+
Stream.runDrain,
|
|
143
|
+
Effect.tapCauseLogPretty,
|
|
144
|
+
Effect.runFork,
|
|
145
|
+
)
|
|
146
|
+
|
|
150
147
|
this.otel = {
|
|
151
148
|
tracer: otelTracer,
|
|
152
149
|
mutationsSpanContext: otelMuationsSpanContext,
|
|
@@ -246,7 +243,7 @@ export class Store<
|
|
|
246
243
|
otel.trace.getSpan(this.otel.mutationsSpanContext)!.end()
|
|
247
244
|
otel.trace.getSpan(this.otel.queriesSpanContext)!.end()
|
|
248
245
|
|
|
249
|
-
await this.
|
|
246
|
+
await this.adapter.coordinator.shutdown()
|
|
250
247
|
}
|
|
251
248
|
|
|
252
249
|
mutate: {
|
|
@@ -255,22 +252,24 @@ export class Store<
|
|
|
255
252
|
txn: <const TMutationArg extends ReadonlyArray<MutationEvent.ForSchema<TSchema>>>(...list: TMutationArg) => void,
|
|
256
253
|
): void
|
|
257
254
|
<const TMutationArg extends ReadonlyArray<MutationEvent.ForSchema<TSchema>>>(
|
|
258
|
-
options: { label?: string; skipRefresh?: boolean },
|
|
255
|
+
options: { label?: string; skipRefresh?: boolean; wasSyncMessage?: boolean },
|
|
259
256
|
...list: TMutationArg
|
|
260
257
|
): void
|
|
261
258
|
(
|
|
262
|
-
options: { label?: string; skipRefresh?: boolean },
|
|
259
|
+
options: { label?: string; skipRefresh?: boolean; wasSyncMessage?: boolean },
|
|
263
260
|
txn: <const TMutationArg extends ReadonlyArray<MutationEvent.ForSchema<TSchema>>>(...list: TMutationArg) => void,
|
|
264
261
|
): void
|
|
265
262
|
} = (firstMutationOrTxnFnOrOptions: any, ...restMutations: any[]) => {
|
|
266
263
|
let mutationsEvents: MutationEvent.ForSchema<TSchema>[]
|
|
267
|
-
let options: { label?: string; skipRefresh?: boolean } | undefined
|
|
264
|
+
let options: { label?: string; skipRefresh?: boolean; wasSyncMessage?: boolean } | undefined
|
|
268
265
|
|
|
269
266
|
if (typeof firstMutationOrTxnFnOrOptions === 'function') {
|
|
267
|
+
// TODO ensure that function is synchronous and isn't called in a async way (also write tests for this)
|
|
270
268
|
mutationsEvents = firstMutationOrTxnFnOrOptions((arg: any) => mutationsEvents.push(arg))
|
|
271
269
|
} else if (
|
|
272
270
|
firstMutationOrTxnFnOrOptions?.label !== undefined ||
|
|
273
|
-
firstMutationOrTxnFnOrOptions?.skipRefresh !== undefined
|
|
271
|
+
firstMutationOrTxnFnOrOptions?.skipRefresh !== undefined ||
|
|
272
|
+
firstMutationOrTxnFnOrOptions?.wasSyncMessage !== undefined
|
|
274
273
|
) {
|
|
275
274
|
options = firstMutationOrTxnFnOrOptions
|
|
276
275
|
mutationsEvents = restMutations
|
|
@@ -278,13 +277,26 @@ export class Store<
|
|
|
278
277
|
mutationsEvents = [firstMutationOrTxnFnOrOptions, ...restMutations]
|
|
279
278
|
}
|
|
280
279
|
|
|
280
|
+
mutationsEvents = mutationsEvents.filter((_) => !this.__processedMutationIds.has(_.id))
|
|
281
|
+
|
|
282
|
+
if (mutationsEvents.length === 0) {
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
for (const mutationEvent of mutationsEvents) {
|
|
287
|
+
this.__processedMutationIds.add(mutationEvent.id)
|
|
288
|
+
}
|
|
289
|
+
|
|
281
290
|
const label = options?.label ?? 'mutate'
|
|
282
291
|
const skipRefresh = options?.skipRefresh ?? false
|
|
292
|
+
const wasSyncMessage = options?.wasSyncMessage ?? false
|
|
283
293
|
|
|
284
294
|
const mutationsSpan = otel.trace.getSpan(this.otel.mutationsSpanContext)!
|
|
285
295
|
mutationsSpan.addEvent('mutate')
|
|
286
296
|
|
|
287
|
-
// console.
|
|
297
|
+
// console.group('LiveStore.mutate', { skipRefresh, wasSyncMessage, label })
|
|
298
|
+
// mutationsEvents.forEach((_) => console.log(_.mutation, _.id, _.args))
|
|
299
|
+
// console.groupEnd()
|
|
288
300
|
|
|
289
301
|
return this.otel.tracer.startActiveSpan(
|
|
290
302
|
'LiveStore:mutate',
|
|
@@ -307,7 +319,11 @@ export class Store<
|
|
|
307
319
|
const applyMutations = () => {
|
|
308
320
|
for (const mutationEvent of mutationsEvents) {
|
|
309
321
|
try {
|
|
310
|
-
const { writeTables: writeTablesForEvent } = this.mutateWithoutRefresh(
|
|
322
|
+
const { writeTables: writeTablesForEvent } = this.mutateWithoutRefresh(
|
|
323
|
+
mutationEvent,
|
|
324
|
+
otelContext,
|
|
325
|
+
wasSyncMessage,
|
|
326
|
+
)
|
|
311
327
|
for (const tableName of writeTablesForEvent) {
|
|
312
328
|
writeTables.add(tableName)
|
|
313
329
|
}
|
|
@@ -319,7 +335,7 @@ export class Store<
|
|
|
319
335
|
}
|
|
320
336
|
|
|
321
337
|
if (mutationsEvents.length > 1) {
|
|
322
|
-
// TODO: what to do about
|
|
338
|
+
// TODO: what to do about coordinator transaction here?
|
|
323
339
|
this.mainDbWrapper.txn(applyMutations)
|
|
324
340
|
} else {
|
|
325
341
|
applyMutations()
|
|
@@ -383,10 +399,20 @@ export class Store<
|
|
|
383
399
|
* This is an internal method that doesn't trigger a refresh;
|
|
384
400
|
* the caller must refresh queries after calling this method.
|
|
385
401
|
*/
|
|
386
|
-
|
|
402
|
+
mutateWithoutRefresh = (
|
|
387
403
|
mutationEventDecoded: MutationEvent.ForSchema<TSchema>,
|
|
388
404
|
otelContext: otel.Context,
|
|
405
|
+
skipStorage: boolean = false,
|
|
389
406
|
): { writeTables: ReadonlySet<string>; durationMs: number } => {
|
|
407
|
+
// NOTE we also need this temporary workaround here since some code-paths use `mutateWithoutRefresh` directly
|
|
408
|
+
// e.g. the row-query functionality
|
|
409
|
+
if (this.__processedMutationWithoutRefreshIds.has(mutationEventDecoded.id)) {
|
|
410
|
+
// NOTE this data should never be used
|
|
411
|
+
return { writeTables: new Set(), durationMs: 0 }
|
|
412
|
+
} else {
|
|
413
|
+
this.__processedMutationWithoutRefreshIds.add(mutationEventDecoded.id)
|
|
414
|
+
}
|
|
415
|
+
|
|
390
416
|
return this.otel.tracer.startActiveSpan(
|
|
391
417
|
'LiveStore:mutatetWithoutRefresh',
|
|
392
418
|
{
|
|
@@ -413,15 +439,20 @@ export class Store<
|
|
|
413
439
|
bindValues,
|
|
414
440
|
writeTables = this.mainDbWrapper.getTablesUsed(statementSql),
|
|
415
441
|
} of execArgsArr) {
|
|
442
|
+
// TODO when the store doesn't have the lock, we need wait for the coordinator to confirm the mutation
|
|
443
|
+
// before executing the mutation on the main db
|
|
416
444
|
const { durationMs } = this.mainDbWrapper.execute(statementSql, bindValues, writeTables, { otelContext })
|
|
417
445
|
|
|
418
446
|
durationMsTotal += durationMs
|
|
419
447
|
writeTables.forEach((table) => allWriteTables.add(table))
|
|
420
448
|
}
|
|
421
449
|
|
|
422
|
-
// Asynchronously apply mutation to a persistent storage (we're not awaiting this promise here)
|
|
423
450
|
const mutationEventEncoded = Schema.encodeUnknownSync(this.mutationEventSchema)(mutationEventDecoded)
|
|
424
|
-
|
|
451
|
+
|
|
452
|
+
if (skipStorage === false) {
|
|
453
|
+
// Asynchronously apply mutation to a persistent storage (we're not awaiting this promise here)
|
|
454
|
+
void this.adapter.coordinator.mutate(mutationEventEncoded, span)
|
|
455
|
+
}
|
|
425
456
|
|
|
426
457
|
// Uncomment to print a list of queries currently registered on the store
|
|
427
458
|
// console.debug(JSON.parse(JSON.stringify([...this.queries].map((q) => `${labelForKey(q.componentKey)}/${q.label}`))))
|
|
@@ -447,7 +478,7 @@ export class Store<
|
|
|
447
478
|
this.mainDbWrapper.execute(query, prepareBindValues(params, query), writeTables, { otelContext })
|
|
448
479
|
|
|
449
480
|
const parentSpan = otel.trace.getSpan(otel.context.active())
|
|
450
|
-
this.
|
|
481
|
+
this.adapter.coordinator.execute(query, prepareBindValues(params, query), parentSpan)
|
|
451
482
|
}
|
|
452
483
|
|
|
453
484
|
select = (query: string, params: ParamsObject = {}) => {
|
|
@@ -467,12 +498,12 @@ export class Store<
|
|
|
467
498
|
}
|
|
468
499
|
|
|
469
500
|
__devDownloadMutationLogDb = async () => {
|
|
470
|
-
const data = await this.
|
|
501
|
+
const data = await this.adapter.coordinator.getMutationLogData()
|
|
471
502
|
downloadBlob(data, `livestore-mutationlog-${Date.now()}.db`)
|
|
472
503
|
}
|
|
473
504
|
|
|
474
505
|
// TODO allow for graceful store reset without requiring a full page reload (which should also call .boot)
|
|
475
|
-
dangerouslyResetStorage = () => this.
|
|
506
|
+
dangerouslyResetStorage = (mode: ResetMode) => this.adapter.coordinator.dangerouslyReset(mode)
|
|
476
507
|
}
|
|
477
508
|
|
|
478
509
|
/** Create a new LiveStore Store */
|
|
@@ -484,7 +515,7 @@ export const createStore = async <
|
|
|
484
515
|
graphQLOptions,
|
|
485
516
|
otelTracer = makeNoopTracer(),
|
|
486
517
|
otelRootSpanContext = otel.context.active(),
|
|
487
|
-
|
|
518
|
+
adapter: adapterFactory,
|
|
488
519
|
boot,
|
|
489
520
|
dbGraph = globalDbGraph,
|
|
490
521
|
batchUpdates,
|
|
@@ -493,7 +524,7 @@ export const createStore = async <
|
|
|
493
524
|
graphQLOptions?: GraphQLOptions<TGraphQLContext>
|
|
494
525
|
otelTracer?: otel.Tracer
|
|
495
526
|
otelRootSpanContext?: otel.Context
|
|
496
|
-
|
|
527
|
+
adapter: StoreAdapterFactory
|
|
497
528
|
boot?: (db: BootDb, parentSpan: otel.Span) => unknown | Promise<unknown>
|
|
498
529
|
dbGraph?: DbGraph
|
|
499
530
|
batchUpdates?: (run: () => void) => void
|
|
@@ -503,8 +534,8 @@ export const createStore = async <
|
|
|
503
534
|
performance.mark('livestore:db-creating')
|
|
504
535
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
|
505
536
|
|
|
506
|
-
const
|
|
507
|
-
const
|
|
537
|
+
const adapterPromise = adapterFactory({ otelTracer, otelContext, schema })
|
|
538
|
+
const adapter = adapterPromise instanceof Promise ? await adapterPromise : adapterPromise
|
|
508
539
|
performance.mark('livestore:db-created')
|
|
509
540
|
performance.measure('livestore:db-create', 'livestore:db-creating', 'livestore:db-created')
|
|
510
541
|
|
|
@@ -520,15 +551,15 @@ export const createStore = async <
|
|
|
520
551
|
let txnExecuteStmnts: [string, PreparedBindValues | undefined][] = []
|
|
521
552
|
|
|
522
553
|
const bootDbImpl: BootDb = {
|
|
554
|
+
_tag: 'BootDb',
|
|
523
555
|
execute: (queryStr, bindValues) => {
|
|
524
|
-
const stmt =
|
|
525
|
-
|
|
526
|
-
stmt.execute(preparedBindValues)
|
|
556
|
+
const stmt = adapter.mainDb.prepare(queryStr)
|
|
557
|
+
stmt.execute(bindValues)
|
|
527
558
|
|
|
528
559
|
if (isInTxn === true) {
|
|
529
|
-
txnExecuteStmnts.push([queryStr,
|
|
560
|
+
txnExecuteStmnts.push([queryStr, bindValues])
|
|
530
561
|
} else {
|
|
531
|
-
void
|
|
562
|
+
void adapter.coordinator.execute(queryStr, bindValues, undefined)
|
|
532
563
|
}
|
|
533
564
|
},
|
|
534
565
|
mutate: (...list) => {
|
|
@@ -541,34 +572,33 @@ export const createStore = async <
|
|
|
541
572
|
// const { bindValues, statementSql } = getExecArgsFromMutation({ mutationDef, mutationEventDecoded })
|
|
542
573
|
|
|
543
574
|
for (const { statementSql, bindValues } of execArgsArr) {
|
|
544
|
-
|
|
575
|
+
adapter.mainDb.execute(statementSql, bindValues)
|
|
545
576
|
}
|
|
546
577
|
|
|
547
578
|
const mutationEventEncoded = Schema.encodeUnknownSync(mutationEventSchema)(mutationEventDecoded)
|
|
548
|
-
void
|
|
579
|
+
void adapter.coordinator.mutate(mutationEventEncoded, span)
|
|
549
580
|
}
|
|
550
581
|
},
|
|
551
582
|
select: (queryStr, bindValues) => {
|
|
552
|
-
const stmt =
|
|
553
|
-
|
|
554
|
-
return stmt.select(preparedBindValues)
|
|
583
|
+
const stmt = adapter.mainDb.prepare(queryStr)
|
|
584
|
+
return stmt.select(bindValues)
|
|
555
585
|
},
|
|
556
586
|
txn: (callback) => {
|
|
557
587
|
try {
|
|
558
588
|
isInTxn = true
|
|
559
|
-
|
|
589
|
+
adapter.mainDb.execute('BEGIN', undefined)
|
|
560
590
|
|
|
561
591
|
callback()
|
|
562
592
|
|
|
563
|
-
|
|
593
|
+
adapter.mainDb.execute('COMMIT', undefined)
|
|
564
594
|
|
|
565
|
-
//
|
|
595
|
+
// adapter.coordinator.execute('BEGIN', undefined, undefined)
|
|
566
596
|
for (const [queryStr, bindValues] of txnExecuteStmnts) {
|
|
567
|
-
|
|
597
|
+
adapter.coordinator.execute(queryStr, bindValues, undefined)
|
|
568
598
|
}
|
|
569
|
-
//
|
|
599
|
+
// adapter.coordinator.execute('COMMIT', undefined, undefined)
|
|
570
600
|
} catch (e: any) {
|
|
571
|
-
|
|
601
|
+
adapter.mainDb.execute('ROLLBACK', undefined)
|
|
572
602
|
throw e
|
|
573
603
|
} finally {
|
|
574
604
|
isInTxn = false
|
|
@@ -588,7 +618,7 @@ export const createStore = async <
|
|
|
588
618
|
// Think about what to do about this case.
|
|
589
619
|
// await applySchema(db, schema)
|
|
590
620
|
return Store.createStore<TGraphQLContext, TSchema>(
|
|
591
|
-
{
|
|
621
|
+
{ adapter: adapter, schema, graphQLOptions, otelTracer, otelRootSpanContext, dbGraph, mutationEventSchema },
|
|
592
622
|
span,
|
|
593
623
|
)
|
|
594
624
|
} finally {
|
package/src/utils/util.ts
CHANGED
package/dist/cud.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { RawSqlMutationEvent } from '@livestore/common/schema';
|
|
2
|
-
import { DbSchema } from '@livestore/common/schema';
|
|
3
|
-
import type { SqliteDsl } from 'effect-db-schema';
|
|
4
|
-
import type { RowResult } from './row-query.js';
|
|
5
|
-
import { type GetValForKey } from './utils/util.js';
|
|
6
|
-
export declare const makeCudMutations: <TTableDef extends DbSchema.TableDef<DbSchema.DefaultSqliteTableDefConstrained, boolean, DbSchema.TableOptions, import("@effect/schema/Schema").Schema<any, any, never>>>(tables: Iterable<TTableDef> | Record<string, TTableDef>) => CudMutations<TTableDef>;
|
|
7
|
-
export type UpdateMutation<TTableDef extends DbSchema.TableDef> = (args: {
|
|
8
|
-
where: Partial<RowResult<TTableDef>>;
|
|
9
|
-
values: Partial<RowResult<TTableDef>>;
|
|
10
|
-
}) => RawSqlMutationEvent;
|
|
11
|
-
export type RowInsert<TTableDef extends DbSchema.TableDef> = TTableDef['isSingleColumn'] extends true ? GetValForKey<SqliteDsl.FromColumns.InsertRowDecoded<TTableDef['sqliteDef']['columns']>, 'value'> : SqliteDsl.FromColumns.InsertRowDecoded<TTableDef['sqliteDef']['columns']>;
|
|
12
|
-
export type InsertMutation<TTableDef extends DbSchema.TableDef> = (values: RowInsert<TTableDef>) => RawSqlMutationEvent;
|
|
13
|
-
export type DeleteMutation<TTableDef extends DbSchema.TableDef> = (args: {
|
|
14
|
-
where: Partial<RowResult<TTableDef>>;
|
|
15
|
-
}) => RawSqlMutationEvent;
|
|
16
|
-
export type CudMutation<TTableDef extends DbSchema.TableDef> = {
|
|
17
|
-
insert: InsertMutation<TTableDef>;
|
|
18
|
-
update: UpdateMutation<TTableDef>;
|
|
19
|
-
delete: DeleteMutation<TTableDef>;
|
|
20
|
-
};
|
|
21
|
-
export type CudMutations<TTableDef extends DbSchema.TableDef> = {
|
|
22
|
-
[TTableName in TTableDef['sqliteDef']['name']]: CudMutation<Extract<TTableDef, {
|
|
23
|
-
sqliteDef: {
|
|
24
|
-
name: TTableName;
|
|
25
|
-
};
|
|
26
|
-
}>>;
|
|
27
|
-
};
|
|
28
|
-
//# sourceMappingURL=cud.d.ts.map
|
package/dist/cud.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cud.d.ts","sourceRoot":"","sources":["../src/cud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAkB,MAAM,0BAA0B,CAAA;AAGnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEnD,eAAO,MAAM,gBAAgB,oLACnB,SAAS,SAAS,CAAC,GAAG,OAAO,MAAM,EAAE,SAAS,CAAC,KACtD,aAAa,SAAS,CAWxB,CAAA;AAyCD,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE;IAEvE,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAA;IACpC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAA;CACtC,KAAK,mBAAmB,CAAA;AAEzB,MAAM,MAAM,SAAS,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI,SAAS,CAAC,gBAAgB,CAAC,SAAS,IAAI,GACjG,YAAY,CAAC,SAAS,CAAC,WAAW,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,GAChG,SAAS,CAAC,WAAW,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,CAAA;AAE7E,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,SAAS,CAAC,KAAK,mBAAmB,CAAA;AAEvH,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE;IACvE,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAA;CACrC,KAAK,mBAAmB,CAAA;AAEzB,MAAM,MAAM,WAAW,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI;IAC7D,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACjC,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACjC,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,YAAY,CAAC,SAAS,SAAS,QAAQ,CAAC,QAAQ,IAAI;KAC7D,UAAU,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE;QAAE,SAAS,EAAE;YAAE,IAAI,EAAE,UAAU,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CACrH,CAAA"}
|
package/dist/cud.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { DbSchema, rawSqlMutation } from '@livestore/common/schema';
|
|
2
|
-
import { deleteRows, insertRow, updateRows } from '@livestore/common/sql-queries';
|
|
3
|
-
import { isIterable } from '@livestore/utils';
|
|
4
|
-
export const makeCudMutations = (tables) => {
|
|
5
|
-
const cudMutationRecord = {};
|
|
6
|
-
const tables_ = isIterable(tables) ? tables : Object.values(tables);
|
|
7
|
-
for (const tableDef of tables_) {
|
|
8
|
-
const [tableName, cudMutation] = cudMutationsForTable(tableDef);
|
|
9
|
-
cudMutationRecord[tableName] = cudMutation;
|
|
10
|
-
}
|
|
11
|
-
return cudMutationRecord;
|
|
12
|
-
};
|
|
13
|
-
const cudMutationsForTable = (tableDef) => {
|
|
14
|
-
const table = tableDef.sqliteDef;
|
|
15
|
-
const writeTables = new Set([table.name]);
|
|
16
|
-
const api = {
|
|
17
|
-
insert: (values_) => {
|
|
18
|
-
const values = DbSchema.getDefaultValuesDecoded(tableDef, values_);
|
|
19
|
-
const [sql, bindValues] = insertRow({
|
|
20
|
-
tableName: table.name,
|
|
21
|
-
columns: table.columns,
|
|
22
|
-
options: { orReplace: false },
|
|
23
|
-
values: values,
|
|
24
|
-
});
|
|
25
|
-
return rawSqlMutation({ sql, bindValues, writeTables });
|
|
26
|
-
},
|
|
27
|
-
update: ({ where, values }) => {
|
|
28
|
-
const [sql, bindValues] = updateRows({
|
|
29
|
-
tableName: table.name,
|
|
30
|
-
columns: table.columns,
|
|
31
|
-
where: where,
|
|
32
|
-
updateValues: values,
|
|
33
|
-
});
|
|
34
|
-
return rawSqlMutation({ sql, bindValues, writeTables });
|
|
35
|
-
},
|
|
36
|
-
delete: ({ where }) => {
|
|
37
|
-
const [sql, bindValues] = deleteRows({
|
|
38
|
-
tableName: table.name,
|
|
39
|
-
columns: table.columns,
|
|
40
|
-
where: where,
|
|
41
|
-
});
|
|
42
|
-
return rawSqlMutation({ sql, bindValues, writeTables });
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
return [tableDef.sqliteDef.name, api];
|
|
46
|
-
};
|
|
47
|
-
//# sourceMappingURL=cud.js.map
|
package/dist/cud.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cud.js","sourceRoot":"","sources":["../src/cud.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAA;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAM7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAuD,EAC9B,EAAE;IAC3B,MAAM,iBAAiB,GAA4B,EAAS,CAAA;IAE5D,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAEnE,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;QAC/D,iBAAiB,CAAC,SAAS,CAAC,GAAG,WAAkB,CAAA;IACnD,CAAC;IAED,OAAO,iBAAiB,CAAA;AAC1B,CAAC,CAAA;AAED,MAAM,oBAAoB,GAAG,CAC3B,QAAmB,EACuC,EAAE;IAC5D,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAA;IAChC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IACzC,MAAM,GAAG,GAAG;QACV,MAAM,EAAE,CAAC,OAAY,EAAE,EAAE;YACvB,MAAM,MAAM,GAAG,QAAQ,CAAC,uBAAuB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YAElE,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC;gBAClC,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,OAAO,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;gBAC7B,MAAM,EAAE,MAAa;aACtB,CAAC,CAAA;YACF,OAAO,cAAc,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE;YAC5B,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC;gBACnC,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,KAAK;gBACZ,YAAY,EAAE,MAAM;aACrB,CAAC,CAAA;YACF,OAAO,cAAc,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAA;QACzD,CAAC;QACD,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;YACpB,MAAM,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,UAAU,CAAC;gBACnC,SAAS,EAAE,KAAK,CAAC,IAAI;gBACrB,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,KAAK;aACb,CAAC,CAAA;YACF,OAAO,cAAc,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAA;QACzD,CAAC;KAC+B,CAAA;IAElC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;AACvC,CAAC,CAAA"}
|
package/dist/cud.test.d.ts
DELETED
package/dist/cud.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cud.test.d.ts","sourceRoot":"","sources":["../src/cud.test.ts"],"names":[],"mappings":""}
|
package/dist/cud.test.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest';
|
|
2
|
-
import { tables } from './__tests__/react/fixture.js';
|
|
3
|
-
import { makeCudMutations } from './cud.js';
|
|
4
|
-
describe('cud mutations', () => {
|
|
5
|
-
const cud = makeCudMutations(tables);
|
|
6
|
-
test('basic', () => {
|
|
7
|
-
expect(patchId(cud.todos.insert({ id: 't1', completed: true, text: 'Task 1' }))).toMatchInlineSnapshot(`
|
|
8
|
-
{
|
|
9
|
-
"args": {
|
|
10
|
-
"bindValues": {
|
|
11
|
-
"completed": 1,
|
|
12
|
-
"id": "t1",
|
|
13
|
-
"text": "Task 1",
|
|
14
|
-
},
|
|
15
|
-
"sql": "INSERT INTO todos (id, text, completed) VALUES ($id, $text, $completed)",
|
|
16
|
-
"writeTables": Set {
|
|
17
|
-
"todos",
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
"id": "00000000-0000-0000-0000-000000000000",
|
|
21
|
-
"mutation": "livestore.RawSql",
|
|
22
|
-
}
|
|
23
|
-
`);
|
|
24
|
-
expect(patchId(cud.todos.update({ where: { id: 't1' }, values: { text: 'Task 1 - fixed' } })))
|
|
25
|
-
.toMatchInlineSnapshot(`
|
|
26
|
-
{
|
|
27
|
-
"args": {
|
|
28
|
-
"bindValues": {
|
|
29
|
-
"update_text": "Task 1 - fixed",
|
|
30
|
-
"where_id": "t1",
|
|
31
|
-
},
|
|
32
|
-
"sql": "UPDATE todos SET text = $update_text WHERE id = $where_id",
|
|
33
|
-
"writeTables": Set {
|
|
34
|
-
"todos",
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
"id": "00000000-0000-0000-0000-000000000000",
|
|
38
|
-
"mutation": "livestore.RawSql",
|
|
39
|
-
}
|
|
40
|
-
`);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
const patchId = (muationEvent) => {
|
|
44
|
-
const id = `00000000-0000-0000-0000-000000000000`;
|
|
45
|
-
return { ...muationEvent, id };
|
|
46
|
-
};
|
|
47
|
-
//# sourceMappingURL=cud.test.js.map
|
package/dist/cud.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cud.test.js","sourceRoot":"","sources":["../src/cud.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAG3C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,MAAM,GAAG,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAEpC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;QACjB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;KAgBtG,CAAC,CAAA;QAEF,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC;aAC3F,qBAAqB,CAAC;;;;;;;;;;;;;;;OAetB,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,MAAM,OAAO,GAAG,CAAC,YAA+B,EAAE,EAAE;IAClD,MAAM,EAAE,GAAG,sCAAsC,CAAA;IACjD,OAAO,EAAE,GAAG,YAAY,EAAE,EAAE,EAAE,CAAA;AAChC,CAAC,CAAA"}
|
package/dist/migrations.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { type DatabaseImpl } from '@livestore/common';
|
|
2
|
-
import type { LiveStoreSchema } from '@livestore/common/schema';
|
|
3
|
-
import type * as otel from '@opentelemetry/api';
|
|
4
|
-
import { SqliteAst } from 'effect-db-schema';
|
|
5
|
-
export declare const migrateDb: ({ db, otelContext, schema, }: {
|
|
6
|
-
db: DatabaseImpl;
|
|
7
|
-
otelContext: otel.Context;
|
|
8
|
-
schema: LiveStoreSchema;
|
|
9
|
-
}) => void;
|
|
10
|
-
export declare const migrateTable: ({ db, tableAst, schemaHash, }: {
|
|
11
|
-
db: DatabaseImpl;
|
|
12
|
-
tableAst: SqliteAst.Table;
|
|
13
|
-
otelContext: otel.Context;
|
|
14
|
-
schemaHash: number;
|
|
15
|
-
}) => void;
|
|
16
|
-
//# sourceMappingURL=migrations.d.ts.map
|
package/dist/migrations.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAO,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,0BAA0B,CAAA;AAG9E,OAAO,KAAK,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAa,MAAM,kBAAkB,CAAA;AAoCvD,eAAO,MAAM,SAAS;QAKhB,YAAY;iBACH,KAAK,OAAO;YACjB,eAAe;UAiCxB,CAAA;AAED,eAAO,MAAM,YAAY;QAMnB,YAAY;cACN,UAAU,KAAK;iBACZ,KAAK,OAAO;gBACb,MAAM;UAwBnB,CAAA"}
|
package/dist/migrations.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { sql } from '@livestore/common';
|
|
2
|
-
import { SCHEMA_META_TABLE, systemTables } from '@livestore/common/schema';
|
|
3
|
-
import { Schema as EffectSchema } from '@livestore/utils/effect';
|
|
4
|
-
import { SqliteAst, SqliteDsl } from 'effect-db-schema';
|
|
5
|
-
import { memoize } from 'lodash-es';
|
|
6
|
-
import { prepareBindValues } from './utils/util.js';
|
|
7
|
-
const getMemoizedTimestamp = memoize(() => new Date().toISOString());
|
|
8
|
-
// TODO bring back statement caching
|
|
9
|
-
// const cachedStmts = new Map<string, PreparedStatement>()
|
|
10
|
-
const dbExecute = (db, queryStr, bindValues) => {
|
|
11
|
-
// let stmt = cachedStmts.get(queryStr)
|
|
12
|
-
// if (!stmt) {
|
|
13
|
-
const stmt = db.mainDb.prepare(queryStr);
|
|
14
|
-
// cachedStmts.set(queryStr, stmt)
|
|
15
|
-
// }
|
|
16
|
-
const preparedBindValues = bindValues ? prepareBindValues(bindValues, queryStr) : undefined;
|
|
17
|
-
stmt.execute(preparedBindValues);
|
|
18
|
-
void db.storageDb.execute(queryStr, preparedBindValues, undefined);
|
|
19
|
-
};
|
|
20
|
-
const dbSelect = (db, queryStr, bindValues) => {
|
|
21
|
-
// let stmt = cachedStmts.get(queryStr)
|
|
22
|
-
// if (!stmt) {
|
|
23
|
-
const stmt = db.mainDb.prepare(queryStr);
|
|
24
|
-
// cachedStmts.set(queryStr, stmt)
|
|
25
|
-
// }
|
|
26
|
-
return stmt.select(bindValues ? prepareBindValues(bindValues, queryStr) : undefined);
|
|
27
|
-
};
|
|
28
|
-
// TODO more graceful DB migration (e.g. backup DB before destructive migrations)
|
|
29
|
-
export const migrateDb = ({ db, otelContext, schema, }) => {
|
|
30
|
-
dbExecute(db,
|
|
31
|
-
// TODO use schema migration definition from schema.ts instead
|
|
32
|
-
sql `create table if not exists ${SCHEMA_META_TABLE} (tableName text primary key, schemaHash text, updatedAt text);`);
|
|
33
|
-
const schemaMetaRows = dbSelect(db, sql `SELECT * FROM ${SCHEMA_META_TABLE}`);
|
|
34
|
-
const dbSchemaHashByTable = Object.fromEntries(schemaMetaRows.map(({ tableName, schemaHash }) => [tableName, schemaHash]));
|
|
35
|
-
const tableDefs = new Set([
|
|
36
|
-
// NOTE it's important the `SCHEMA_META_TABLE` comes first since we're writing to it below
|
|
37
|
-
...systemTables,
|
|
38
|
-
...Array.from(schema.tables.values()).filter((_) => _.sqliteDef.name !== SCHEMA_META_TABLE),
|
|
39
|
-
]);
|
|
40
|
-
for (const tableDef of tableDefs) {
|
|
41
|
-
const tableAst = tableDef.sqliteDef.ast;
|
|
42
|
-
const tableName = tableAst.name;
|
|
43
|
-
const dbSchemaHash = dbSchemaHashByTable[tableName];
|
|
44
|
-
const schemaHash = SqliteAst.hash(tableAst);
|
|
45
|
-
if (schemaHash !== dbSchemaHash && import.meta.env.VITE_LIVESTORE_SKIP_MIGRATIONS === undefined) {
|
|
46
|
-
console.log(`Schema hash mismatch for table '${tableName}' (DB: ${dbSchemaHash}, expected: ${schemaHash}), migrating table...`);
|
|
47
|
-
migrateTable({ db, tableAst, otelContext, schemaHash });
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
export const migrateTable = ({ db, tableAst,
|
|
52
|
-
// otelContext,
|
|
53
|
-
schemaHash, }) => {
|
|
54
|
-
console.log(`Migrating table '${tableAst.name}'...`);
|
|
55
|
-
const tableName = tableAst.name;
|
|
56
|
-
const columnSpec = makeColumnSpec(tableAst);
|
|
57
|
-
// TODO need to possibly handle cascading deletes due to foreign keys
|
|
58
|
-
dbExecute(db, sql `drop table if exists ${tableName}`);
|
|
59
|
-
dbExecute(db, sql `create table if not exists ${tableName} (${columnSpec})`);
|
|
60
|
-
for (const index of tableAst.indexes) {
|
|
61
|
-
dbExecute(db, createIndexFromDefinition(tableName, index));
|
|
62
|
-
}
|
|
63
|
-
const updatedAt = getMemoizedTimestamp();
|
|
64
|
-
dbExecute(db, sql `
|
|
65
|
-
INSERT INTO ${SCHEMA_META_TABLE} (tableName, schemaHash, updatedAt) VALUES ($tableName, $schemaHash, $updatedAt)
|
|
66
|
-
ON CONFLICT (tableName) DO UPDATE SET schemaHash = $schemaHash, updatedAt = $updatedAt;
|
|
67
|
-
`, { tableName, schemaHash, updatedAt });
|
|
68
|
-
};
|
|
69
|
-
const createIndexFromDefinition = (tableName, index) => {
|
|
70
|
-
const uniqueStr = index.unique ? 'UNIQUE' : '';
|
|
71
|
-
return sql `create ${uniqueStr} index ${index.name} on ${tableName} (${index.columns.join(', ')})`;
|
|
72
|
-
};
|
|
73
|
-
const makeColumnSpec = (tableAst) => {
|
|
74
|
-
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name);
|
|
75
|
-
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec);
|
|
76
|
-
if (primaryKeys.length > 0) {
|
|
77
|
-
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`);
|
|
78
|
-
}
|
|
79
|
-
return columnDefStrs.join(', ');
|
|
80
|
-
};
|
|
81
|
-
/** NOTE primary keys are applied on a table level not on a column level to account for multi-column primary keys */
|
|
82
|
-
const toSqliteColumnSpec = (column) => {
|
|
83
|
-
const columnTypeStr = column.type._tag;
|
|
84
|
-
const nullableStr = column.nullable === false ? 'not null' : '';
|
|
85
|
-
const defaultValueStr = (() => {
|
|
86
|
-
if (column.default._tag === 'None')
|
|
87
|
-
return '';
|
|
88
|
-
if (SqliteDsl.isSqlDefaultValue(column.default.value))
|
|
89
|
-
return `default ${column.default.value.sql}`;
|
|
90
|
-
const encodeValue = EffectSchema.encodeSync(column.schema);
|
|
91
|
-
const encodedDefaultValue = encodeValue(column.default.value);
|
|
92
|
-
if (columnTypeStr === 'text')
|
|
93
|
-
return `default '${encodedDefaultValue}'`;
|
|
94
|
-
return `default ${encodedDefaultValue}`;
|
|
95
|
-
})();
|
|
96
|
-
return `${column.name} ${columnTypeStr} ${nullableStr} ${defaultValueStr}`;
|
|
97
|
-
};
|
|
98
|
-
//# sourceMappingURL=migrations.js.map
|
package/dist/migrations.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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"}
|