@livestore/common 0.3.0-dev.27 → 0.3.0-dev.29
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/__tests__/fixture.d.ts +83 -221
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +33 -11
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/adapter-types.d.ts +22 -15
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +15 -2
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +1 -0
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +21 -21
- package/dist/devtools/devtools-messages-common.d.ts +6 -6
- package/dist/devtools/devtools-messages-leader.d.ts +45 -45
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +11 -11
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/index.d.ts +2 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -5
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +25 -12
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +125 -89
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/{apply-mutation.d.ts → apply-event.d.ts} +7 -7
- package/dist/leader-thread/apply-event.d.ts.map +1 -0
- package/dist/leader-thread/apply-event.js +103 -0
- package/dist/leader-thread/apply-event.js.map +1 -0
- package/dist/leader-thread/eventlog.d.ts +27 -0
- package/dist/leader-thread/eventlog.d.ts.map +1 -0
- package/dist/leader-thread/eventlog.js +123 -0
- package/dist/leader-thread/eventlog.js.map +1 -0
- package/dist/leader-thread/leader-worker-devtools.js +18 -18
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +16 -4
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +23 -16
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -1
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -1
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +6 -8
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +11 -11
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/materializer-helper.d.ts +23 -0
- package/dist/materializer-helper.d.ts.map +1 -0
- package/dist/materializer-helper.js +70 -0
- package/dist/materializer-helper.js.map +1 -0
- package/dist/query-builder/api.d.ts +58 -53
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/query-builder/api.js +3 -5
- package/dist/query-builder/api.js.map +1 -1
- package/dist/query-builder/astToSql.d.ts.map +1 -1
- package/dist/query-builder/astToSql.js +59 -37
- package/dist/query-builder/astToSql.js.map +1 -1
- package/dist/query-builder/impl.d.ts +2 -3
- package/dist/query-builder/impl.d.ts.map +1 -1
- package/dist/query-builder/impl.js +48 -46
- package/dist/query-builder/impl.js.map +1 -1
- package/dist/query-builder/impl.test.d.ts +86 -1
- package/dist/query-builder/impl.test.d.ts.map +1 -1
- package/dist/query-builder/impl.test.js +244 -36
- package/dist/query-builder/impl.test.js.map +1 -1
- package/dist/rehydrate-from-eventlog.d.ts +14 -0
- package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
- package/dist/{rehydrate-from-mutationlog.js → rehydrate-from-eventlog.js} +25 -26
- package/dist/rehydrate-from-eventlog.js.map +1 -0
- package/dist/schema/EventDef.d.ts +136 -0
- package/dist/schema/EventDef.d.ts.map +1 -0
- package/dist/schema/EventDef.js +58 -0
- package/dist/schema/EventDef.js.map +1 -0
- package/dist/schema/EventId.d.ts +2 -2
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +8 -2
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/{MutationEvent.d.ts → LiveStoreEvent.d.ts} +56 -56
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
- package/dist/schema/{MutationEvent.js → LiveStoreEvent.js} +25 -25
- package/dist/schema/LiveStoreEvent.js.map +1 -0
- package/dist/schema/client-document-def.d.ts +223 -0
- package/dist/schema/client-document-def.d.ts.map +1 -0
- package/dist/schema/client-document-def.js +170 -0
- package/dist/schema/client-document-def.js.map +1 -0
- package/dist/schema/client-document-def.test.d.ts +2 -0
- package/dist/schema/client-document-def.test.d.ts.map +1 -0
- package/dist/schema/client-document-def.test.js +201 -0
- package/dist/schema/client-document-def.test.js.map +1 -0
- package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/events.d.ts +2 -0
- package/dist/schema/events.d.ts.map +1 -0
- package/dist/schema/events.js +2 -0
- package/dist/schema/events.js.map +1 -0
- package/dist/schema/mod.d.ts +4 -3
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +4 -3
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +27 -23
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +45 -43
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/sqlite-state.d.ts +12 -0
- package/dist/schema/sqlite-state.d.ts.map +1 -0
- package/dist/schema/sqlite-state.js +36 -0
- package/dist/schema/sqlite-state.js.map +1 -0
- package/dist/schema/system-tables.d.ts +67 -98
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +62 -48
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +26 -96
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +16 -64
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema/view.d.ts +3 -0
- package/dist/schema/view.d.ts.map +1 -0
- package/dist/schema/view.js +3 -0
- package/dist/schema/view.js.map +1 -0
- package/dist/schema-management/common.d.ts +4 -4
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +6 -6
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
- package/dist/schema-management/validate-mutation-defs.js +17 -17
- package/dist/schema-management/validate-mutation-defs.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +7 -7
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +31 -30
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/facts.d.ts +19 -19
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +2 -2
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +3 -3
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +1 -1
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.js +1 -1
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +7 -7
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -5
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +71 -71
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +60 -25
- package/dist/sync/next/test/event-fixtures.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +1 -1
- package/dist/sync/next/test/mod.d.ts.map +1 -1
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/next/test/mod.js.map +1 -1
- package/dist/sync/sync.d.ts +3 -3
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/syncstate.d.ts +32 -32
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +31 -25
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +165 -175
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts +2 -2
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/__tests__/fixture.ts +36 -15
- package/src/adapter-types.ts +23 -16
- package/src/debug-info.ts +1 -0
- package/src/devtools/devtools-messages-leader.ts +13 -13
- package/src/index.ts +2 -5
- package/src/leader-thread/LeaderSyncProcessor.ts +183 -122
- package/src/leader-thread/{apply-mutation.ts → apply-event.ts} +50 -74
- package/src/leader-thread/eventlog.ts +199 -0
- package/src/leader-thread/leader-worker-devtools.ts +18 -18
- package/src/leader-thread/make-leader-thread-layer.ts +51 -29
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/recreate-db.ts +6 -9
- package/src/leader-thread/types.ts +12 -12
- package/src/materializer-helper.ts +110 -0
- package/src/query-builder/api.ts +79 -105
- package/src/query-builder/astToSql.ts +68 -39
- package/src/query-builder/impl.test.ts +264 -42
- package/src/query-builder/impl.ts +72 -56
- package/src/{rehydrate-from-mutationlog.ts → rehydrate-from-eventlog.ts} +33 -40
- package/src/schema/EventDef.ts +216 -0
- package/src/schema/EventId.ts +11 -3
- package/src/schema/{MutationEvent.ts → LiveStoreEvent.ts} +68 -69
- package/src/schema/client-document-def.test.ts +239 -0
- package/src/schema/client-document-def.ts +444 -0
- package/src/schema/db-schema/dsl/mod.ts +0 -1
- package/src/schema/events.ts +1 -0
- package/src/schema/mod.ts +4 -3
- package/src/schema/schema.ts +79 -69
- package/src/schema/sqlite-state.ts +62 -0
- package/src/schema/system-tables.ts +42 -53
- package/src/schema/table-def.ts +53 -209
- package/src/schema/view.ts +2 -0
- package/src/schema-management/common.ts +4 -4
- package/src/schema-management/migrations.ts +8 -9
- package/src/schema-management/validate-mutation-defs.ts +22 -24
- package/src/sync/ClientSessionSyncProcessor.ts +37 -36
- package/src/sync/next/facts.ts +31 -32
- package/src/sync/next/history-dag-common.ts +4 -4
- package/src/sync/next/history-dag.ts +1 -1
- package/src/sync/next/rebase-events.ts +13 -13
- package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
- package/src/sync/next/test/compact-events.test.ts +73 -73
- package/src/sync/next/test/event-fixtures.ts +219 -0
- package/src/sync/next/test/mod.ts +1 -1
- package/src/sync/sync.ts +3 -3
- package/src/sync/syncstate.test.ts +168 -179
- package/src/sync/syncstate.ts +48 -38
- package/src/sync/validate-push-payload.ts +2 -2
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +1 -0
- package/dist/derived-mutations.d.ts +0 -109
- package/dist/derived-mutations.d.ts.map +0 -1
- package/dist/derived-mutations.js +0 -54
- package/dist/derived-mutations.js.map +0 -1
- package/dist/derived-mutations.test.d.ts +0 -2
- package/dist/derived-mutations.test.d.ts.map +0 -1
- package/dist/derived-mutations.test.js +0 -93
- package/dist/derived-mutations.test.js.map +0 -1
- package/dist/init-singleton-tables.d.ts +0 -4
- package/dist/init-singleton-tables.d.ts.map +0 -1
- package/dist/init-singleton-tables.js +0 -16
- package/dist/init-singleton-tables.js.map +0 -1
- package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
- package/dist/leader-thread/apply-mutation.js +0 -122
- package/dist/leader-thread/apply-mutation.js.map +0 -1
- package/dist/leader-thread/mutationlog.d.ts +0 -27
- package/dist/leader-thread/mutationlog.d.ts.map +0 -1
- package/dist/leader-thread/mutationlog.js +0 -124
- package/dist/leader-thread/mutationlog.js.map +0 -1
- package/dist/leader-thread/pull-queue-set.d.ts +0 -7
- package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
- package/dist/leader-thread/pull-queue-set.js +0 -38
- package/dist/leader-thread/pull-queue-set.js.map +0 -1
- package/dist/mutation.d.ts +0 -20
- package/dist/mutation.d.ts.map +0 -1
- package/dist/mutation.js +0 -68
- package/dist/mutation.js.map +0 -1
- package/dist/query-info.d.ts +0 -41
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -7
- package/dist/query-info.js.map +0 -1
- package/dist/rehydrate-from-mutationlog.d.ts +0 -15
- package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
- package/dist/rehydrate-from-mutationlog.js.map +0 -1
- package/dist/schema/MutationEvent.d.ts.map +0 -1
- package/dist/schema/MutationEvent.js.map +0 -1
- package/dist/schema/mutations.d.ts +0 -115
- package/dist/schema/mutations.d.ts.map +0 -1
- package/dist/schema/mutations.js +0 -42
- package/dist/schema/mutations.js.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
- package/src/derived-mutations.test.ts +0 -101
- package/src/derived-mutations.ts +0 -170
- package/src/init-singleton-tables.ts +0 -24
- package/src/leader-thread/mutationlog.ts +0 -202
- package/src/mutation.ts +0 -108
- package/src/query-info.ts +0 -83
- package/src/schema/mutations.ts +0 -193
- package/src/sync/next/test/mutation-fixtures.ts +0 -228
@@ -1,202 +0,0 @@
|
|
1
|
-
import { LS_DEV, shouldNeverHappen } from '@livestore/utils'
|
2
|
-
import { Effect, Option, Schema } from '@livestore/utils/effect'
|
3
|
-
|
4
|
-
import type { SqliteDb } from '../adapter-types.js'
|
5
|
-
import * as EventId from '../schema/EventId.js'
|
6
|
-
import * as MutationEvent from '../schema/MutationEvent.js'
|
7
|
-
import {
|
8
|
-
MUTATION_LOG_META_TABLE,
|
9
|
-
mutationLogMetaTable,
|
10
|
-
sessionChangesetMetaTable,
|
11
|
-
SYNC_STATUS_TABLE,
|
12
|
-
syncStatusTable,
|
13
|
-
} from '../schema/system-tables.js'
|
14
|
-
import { migrateTable } from '../schema-management/migrations.js'
|
15
|
-
import { insertRow, updateRows } from '../sql-queries/sql-queries.js'
|
16
|
-
import type { PreparedBindValues } from '../util.js'
|
17
|
-
import { prepareBindValues, sql } from '../util.js'
|
18
|
-
import { execSql } from './connection.js'
|
19
|
-
import type { InitialSyncInfo } from './types.js'
|
20
|
-
import { LeaderThreadCtx } from './types.js'
|
21
|
-
|
22
|
-
export const initMutationLogDb = (dbMutationLog: SqliteDb) =>
|
23
|
-
Effect.gen(function* () {
|
24
|
-
yield* migrateTable({
|
25
|
-
db: dbMutationLog,
|
26
|
-
behaviour: 'create-if-not-exists',
|
27
|
-
tableAst: mutationLogMetaTable.sqliteDef.ast,
|
28
|
-
skipMetaTable: true,
|
29
|
-
})
|
30
|
-
|
31
|
-
yield* migrateTable({
|
32
|
-
db: dbMutationLog,
|
33
|
-
behaviour: 'create-if-not-exists',
|
34
|
-
tableAst: syncStatusTable.sqliteDef.ast,
|
35
|
-
skipMetaTable: true,
|
36
|
-
})
|
37
|
-
|
38
|
-
// Create sync status row if it doesn't exist
|
39
|
-
yield* execSql(
|
40
|
-
dbMutationLog,
|
41
|
-
sql`INSERT INTO ${SYNC_STATUS_TABLE} (head)
|
42
|
-
SELECT ${EventId.ROOT.global}
|
43
|
-
WHERE NOT EXISTS (SELECT 1 FROM ${SYNC_STATUS_TABLE})`,
|
44
|
-
{},
|
45
|
-
)
|
46
|
-
})
|
47
|
-
|
48
|
-
/** Exclusive of the "since event" */
|
49
|
-
export const getMutationEventsSince = (
|
50
|
-
since: EventId.EventId,
|
51
|
-
): Effect.Effect<ReadonlyArray<MutationEvent.EncodedWithMeta>, never, LeaderThreadCtx> =>
|
52
|
-
Effect.gen(function* () {
|
53
|
-
const { dbMutationLog, dbReadModel } = yield* LeaderThreadCtx
|
54
|
-
|
55
|
-
const query = mutationLogMetaTable.query.where('idGlobal', '>=', since.global).asSql()
|
56
|
-
const pendingMutationEventsRaw = dbMutationLog.select(query.query, prepareBindValues(query.bindValues, query.query))
|
57
|
-
const pendingMutationEvents = Schema.decodeUnknownSync(mutationLogMetaTable.schema.pipe(Schema.Array))(
|
58
|
-
pendingMutationEventsRaw,
|
59
|
-
)
|
60
|
-
|
61
|
-
const sessionChangesetRows = sessionChangesetMetaTable.query.where('idGlobal', '>=', since.global).asSql()
|
62
|
-
const sessionChangesetRowsRaw = dbReadModel.select(
|
63
|
-
sessionChangesetRows.query,
|
64
|
-
prepareBindValues(sessionChangesetRows.bindValues, sessionChangesetRows.query),
|
65
|
-
)
|
66
|
-
const sessionChangesetRowsDecoded = Schema.decodeUnknownSync(sessionChangesetMetaTable.schema.pipe(Schema.Array))(
|
67
|
-
sessionChangesetRowsRaw,
|
68
|
-
)
|
69
|
-
|
70
|
-
return pendingMutationEvents
|
71
|
-
.map((mutationLogEvent) => {
|
72
|
-
const sessionChangeset = sessionChangesetRowsDecoded.find(
|
73
|
-
(readModelEvent) =>
|
74
|
-
readModelEvent.idGlobal === mutationLogEvent.idGlobal &&
|
75
|
-
readModelEvent.idClient === mutationLogEvent.idClient,
|
76
|
-
)
|
77
|
-
return MutationEvent.EncodedWithMeta.make({
|
78
|
-
mutation: mutationLogEvent.mutation,
|
79
|
-
args: mutationLogEvent.argsJson,
|
80
|
-
id: { global: mutationLogEvent.idGlobal, client: mutationLogEvent.idClient },
|
81
|
-
parentId: { global: mutationLogEvent.parentIdGlobal, client: mutationLogEvent.parentIdClient },
|
82
|
-
clientId: mutationLogEvent.clientId,
|
83
|
-
sessionId: mutationLogEvent.sessionId,
|
84
|
-
meta: {
|
85
|
-
sessionChangeset:
|
86
|
-
sessionChangeset && sessionChangeset.changeset !== null
|
87
|
-
? {
|
88
|
-
_tag: 'sessionChangeset' as const,
|
89
|
-
data: sessionChangeset.changeset,
|
90
|
-
debug: sessionChangeset.debug,
|
91
|
-
}
|
92
|
-
: { _tag: 'unset' as const },
|
93
|
-
syncMetadata: mutationLogEvent.syncMetadataJson,
|
94
|
-
},
|
95
|
-
})
|
96
|
-
})
|
97
|
-
.filter((_) => EventId.compare(_.id, since) > 0)
|
98
|
-
.sort((a, b) => EventId.compare(a.id, b.id))
|
99
|
-
})
|
100
|
-
|
101
|
-
export const getClientHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
|
102
|
-
const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idClient: EventId.ClientEventId }>(
|
103
|
-
sql`select idGlobal, idClient from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idClient DESC limit 1`,
|
104
|
-
)[0]
|
105
|
-
|
106
|
-
return res ? { global: res.idGlobal, client: res.idClient } : EventId.ROOT
|
107
|
-
}
|
108
|
-
|
109
|
-
export const getBackendHeadFromDb = (dbMutationLog: SqliteDb): EventId.GlobalEventId =>
|
110
|
-
dbMutationLog.select<{ head: EventId.GlobalEventId }>(sql`select head from ${SYNC_STATUS_TABLE}`)[0]?.head ??
|
111
|
-
EventId.ROOT.global
|
112
|
-
|
113
|
-
// TODO use prepared statements
|
114
|
-
export const updateBackendHead = (dbMutationLog: SqliteDb, head: EventId.EventId) =>
|
115
|
-
dbMutationLog.execute(sql`UPDATE ${SYNC_STATUS_TABLE} SET head = ${head.global}`)
|
116
|
-
|
117
|
-
export const insertIntoMutationLog = (
|
118
|
-
mutationEventEncoded: MutationEvent.EncodedWithMeta,
|
119
|
-
dbMutationLog: SqliteDb,
|
120
|
-
mutationDefSchemaHash: number,
|
121
|
-
clientId: string,
|
122
|
-
sessionId: string,
|
123
|
-
) =>
|
124
|
-
Effect.gen(function* () {
|
125
|
-
// Check history consistency during LS_DEV
|
126
|
-
if (LS_DEV && mutationEventEncoded.parentId.global !== EventId.ROOT.global) {
|
127
|
-
const parentMutationExists =
|
128
|
-
dbMutationLog.select<{ count: number }>(
|
129
|
-
`SELECT COUNT(*) as count FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ? AND idClient = ?`,
|
130
|
-
[mutationEventEncoded.parentId.global, mutationEventEncoded.parentId.client] as any as PreparedBindValues,
|
131
|
-
)[0]!.count === 1
|
132
|
-
|
133
|
-
if (parentMutationExists === false) {
|
134
|
-
shouldNeverHappen(
|
135
|
-
`Parent mutation ${mutationEventEncoded.parentId.global},${mutationEventEncoded.parentId.client} does not exist`,
|
136
|
-
)
|
137
|
-
}
|
138
|
-
}
|
139
|
-
|
140
|
-
// TODO use prepared statements
|
141
|
-
yield* execSql(
|
142
|
-
dbMutationLog,
|
143
|
-
...insertRow({
|
144
|
-
tableName: MUTATION_LOG_META_TABLE,
|
145
|
-
columns: mutationLogMetaTable.sqliteDef.columns,
|
146
|
-
values: {
|
147
|
-
idGlobal: mutationEventEncoded.id.global,
|
148
|
-
idClient: mutationEventEncoded.id.client,
|
149
|
-
parentIdGlobal: mutationEventEncoded.parentId.global,
|
150
|
-
parentIdClient: mutationEventEncoded.parentId.client,
|
151
|
-
mutation: mutationEventEncoded.mutation,
|
152
|
-
argsJson: mutationEventEncoded.args ?? {},
|
153
|
-
clientId,
|
154
|
-
sessionId,
|
155
|
-
schemaHash: mutationDefSchemaHash,
|
156
|
-
syncMetadataJson: mutationEventEncoded.meta.syncMetadata,
|
157
|
-
},
|
158
|
-
}),
|
159
|
-
)
|
160
|
-
})
|
161
|
-
|
162
|
-
export const updateSyncMetadata = (items: ReadonlyArray<MutationEvent.EncodedWithMeta>) =>
|
163
|
-
Effect.gen(function* () {
|
164
|
-
const { dbMutationLog } = yield* LeaderThreadCtx
|
165
|
-
|
166
|
-
// TODO try to do this in a single query
|
167
|
-
for (let i = 0; i < items.length; i++) {
|
168
|
-
const mutationEvent = items[i]!
|
169
|
-
|
170
|
-
yield* execSql(
|
171
|
-
dbMutationLog,
|
172
|
-
...updateRows({
|
173
|
-
tableName: MUTATION_LOG_META_TABLE,
|
174
|
-
columns: mutationLogMetaTable.sqliteDef.columns,
|
175
|
-
where: { idGlobal: mutationEvent.id.global, idClient: mutationEvent.id.client },
|
176
|
-
updateValues: { syncMetadataJson: mutationEvent.meta.syncMetadata },
|
177
|
-
}),
|
178
|
-
)
|
179
|
-
}
|
180
|
-
})
|
181
|
-
|
182
|
-
export const getSyncBackendCursorInfo = (remoteHead: EventId.GlobalEventId) =>
|
183
|
-
Effect.gen(function* () {
|
184
|
-
const { dbMutationLog } = yield* LeaderThreadCtx
|
185
|
-
|
186
|
-
if (remoteHead === EventId.ROOT.global) return Option.none()
|
187
|
-
|
188
|
-
const MutationlogQuerySchema = Schema.Struct({
|
189
|
-
syncMetadataJson: Schema.parseJson(Schema.Option(Schema.JsonValue)),
|
190
|
-
}).pipe(Schema.pluck('syncMetadataJson'), Schema.Array, Schema.head)
|
191
|
-
|
192
|
-
const syncMetadataOption = yield* Effect.sync(() =>
|
193
|
-
dbMutationLog.select<{ syncMetadataJson: string }>(
|
194
|
-
sql`SELECT syncMetadataJson FROM ${MUTATION_LOG_META_TABLE} WHERE idGlobal = ${remoteHead} ORDER BY idClient ASC LIMIT 1`,
|
195
|
-
),
|
196
|
-
).pipe(Effect.andThen(Schema.decode(MutationlogQuerySchema)), Effect.map(Option.flatten), Effect.orDie)
|
197
|
-
|
198
|
-
return Option.some({
|
199
|
-
cursor: { global: remoteHead, client: EventId.clientDefault },
|
200
|
-
metadata: syncMetadataOption,
|
201
|
-
}) satisfies InitialSyncInfo
|
202
|
-
}).pipe(Effect.withSpan('@livestore/common:mutationlog:getSyncBackendCursorInfo', { attributes: { remoteHead } }))
|
package/src/mutation.ts
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
import { Schema } from '@livestore/utils/effect'
|
2
|
-
|
3
|
-
import { SessionIdSymbol } from './adapter-types.js'
|
4
|
-
import type { QueryBuilder } from './query-builder/api.js'
|
5
|
-
import { isQueryBuilder } from './query-builder/api.js'
|
6
|
-
import type * as MutationEvent from './schema/MutationEvent.js'
|
7
|
-
import type { MutationDef, MutationHandlerResult } from './schema/mutations.js'
|
8
|
-
import type { BindValues } from './sql-queries/sql-queries.js'
|
9
|
-
import type { PreparedBindValues } from './util.js'
|
10
|
-
import { prepareBindValues } from './util.js'
|
11
|
-
|
12
|
-
export const getExecArgsFromMutation = ({
|
13
|
-
mutationDef,
|
14
|
-
mutationEvent,
|
15
|
-
}: {
|
16
|
-
mutationDef: MutationDef.Any
|
17
|
-
/** Both encoded and decoded mutation events are supported to reduce the number of times we need to decode/encode */
|
18
|
-
mutationEvent:
|
19
|
-
| {
|
20
|
-
decoded: MutationEvent.AnyDecoded | MutationEvent.PartialAnyDecoded
|
21
|
-
encoded: undefined
|
22
|
-
}
|
23
|
-
| {
|
24
|
-
decoded: undefined
|
25
|
-
encoded: MutationEvent.AnyEncoded | MutationEvent.PartialAnyEncoded
|
26
|
-
}
|
27
|
-
}): ReadonlyArray<{
|
28
|
-
statementSql: string
|
29
|
-
bindValues: PreparedBindValues
|
30
|
-
writeTables: ReadonlySet<string> | undefined
|
31
|
-
}> => {
|
32
|
-
let statementRes: ReadonlyArray<
|
33
|
-
string | { sql: string; bindValues: Record<string, unknown>; writeTables?: ReadonlySet<string> }
|
34
|
-
>
|
35
|
-
|
36
|
-
switch (typeof mutationDef.sql) {
|
37
|
-
case 'function': {
|
38
|
-
const mutationArgsDecoded =
|
39
|
-
mutationEvent.decoded?.args ?? Schema.decodeUnknownSync(mutationDef.schema)(mutationEvent.encoded!.args)
|
40
|
-
|
41
|
-
const res = mutationDef.sql(mutationArgsDecoded, {
|
42
|
-
clientOnly: mutationDef.options.clientOnly,
|
43
|
-
// TODO properly implement this
|
44
|
-
currentFacts: new Map(),
|
45
|
-
})
|
46
|
-
|
47
|
-
statementRes = (Array.isArray(res) ? res : [res]).map((_: QueryBuilder.Any | MutationHandlerResult) => {
|
48
|
-
if (isQueryBuilder(_)) {
|
49
|
-
const { query, bindValues } = _.asSql()
|
50
|
-
return { sql: query, bindValues: bindValues as BindValues }
|
51
|
-
}
|
52
|
-
|
53
|
-
return _
|
54
|
-
})
|
55
|
-
|
56
|
-
break
|
57
|
-
}
|
58
|
-
case 'string': {
|
59
|
-
statementRes = [mutationDef.sql]
|
60
|
-
break
|
61
|
-
}
|
62
|
-
default: {
|
63
|
-
statementRes = mutationDef.sql
|
64
|
-
break
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
return statementRes.map((statementRes) => {
|
69
|
-
const statementSql = typeof statementRes === 'string' ? statementRes : statementRes.sql
|
70
|
-
|
71
|
-
const mutationArgsEncoded =
|
72
|
-
mutationEvent.encoded?.args ?? Schema.encodeUnknownSync(mutationDef.schema)(mutationEvent.decoded!.args)
|
73
|
-
const bindValues = typeof statementRes === 'string' ? mutationArgsEncoded : statementRes.bindValues
|
74
|
-
|
75
|
-
const writeTables = typeof statementRes === 'string' ? undefined : statementRes.writeTables
|
76
|
-
|
77
|
-
return { statementSql, bindValues: prepareBindValues(bindValues ?? {}, statementSql), writeTables }
|
78
|
-
})
|
79
|
-
}
|
80
|
-
|
81
|
-
// NOTE we should explore whether there is a more elegant solution
|
82
|
-
// e.g. by leveraging the schema to replace the sessionIdSymbol
|
83
|
-
export const replaceSessionIdSymbol = (
|
84
|
-
bindValues: Record<string, unknown> | ReadonlyArray<unknown>,
|
85
|
-
sessionId: string,
|
86
|
-
) => {
|
87
|
-
deepReplaceValue(bindValues, SessionIdSymbol, sessionId)
|
88
|
-
}
|
89
|
-
|
90
|
-
const deepReplaceValue = <S, R>(input: any, searchValue: S, replaceValue: R): void => {
|
91
|
-
if (Array.isArray(input)) {
|
92
|
-
for (const i in input) {
|
93
|
-
if (input[i] === searchValue) {
|
94
|
-
input[i] = replaceValue
|
95
|
-
} else {
|
96
|
-
deepReplaceValue(input[i], searchValue, replaceValue)
|
97
|
-
}
|
98
|
-
}
|
99
|
-
} else if (typeof input === 'object' && input !== null) {
|
100
|
-
for (const key in input) {
|
101
|
-
if (input[key] === searchValue) {
|
102
|
-
input[key] = replaceValue
|
103
|
-
} else {
|
104
|
-
deepReplaceValue(input[key], searchValue, replaceValue)
|
105
|
-
}
|
106
|
-
}
|
107
|
-
}
|
108
|
-
}
|
package/src/query-info.ts
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
import type { SessionIdSymbol } from './adapter-types.js'
|
2
|
-
import type { DbSchema } from './schema/mod.js'
|
3
|
-
|
4
|
-
/**
|
5
|
-
* Semantic information about a query with supported cases being:
|
6
|
-
* - a whole row
|
7
|
-
* - a single column value
|
8
|
-
* - a sub value in a JSON column
|
9
|
-
*
|
10
|
-
* This information is currently only used for derived mutations.
|
11
|
-
*/
|
12
|
-
export type QueryInfo = QueryInfo.None | QueryInfo.Row | QueryInfo.Col | QueryInfo.ColJsonValue | QueryInfo.Write
|
13
|
-
// export type QueryInfo<TTableDef extends DbSchema.TableDefBase = DbSchema.TableDefBase> =
|
14
|
-
// | QueryInfo.None
|
15
|
-
// | QueryInfo.Row<TTableDef>
|
16
|
-
// | QueryInfo.ColJsonValue<TTableDef, GetJsonColumn<TTableDef>>
|
17
|
-
// | QueryInfo.Col<TTableDef, keyof TTableDef['sqliteDef']['columns']>
|
18
|
-
|
19
|
-
export namespace QueryInfo {
|
20
|
-
export type None = {
|
21
|
-
_tag: 'None'
|
22
|
-
}
|
23
|
-
|
24
|
-
export type Row = {
|
25
|
-
_tag: 'Row'
|
26
|
-
table: DbSchema.TableDefBase
|
27
|
-
id: string | SessionIdSymbol | number
|
28
|
-
}
|
29
|
-
|
30
|
-
export type Col = {
|
31
|
-
_tag: 'Col'
|
32
|
-
table: DbSchema.TableDefBase
|
33
|
-
id: string | SessionIdSymbol | number
|
34
|
-
column: string
|
35
|
-
}
|
36
|
-
|
37
|
-
export type ColJsonValue = {
|
38
|
-
_tag: 'ColJsonValue'
|
39
|
-
table: DbSchema.TableDefBase
|
40
|
-
id: string | SessionIdSymbol | number
|
41
|
-
column: string
|
42
|
-
/**
|
43
|
-
* example: `$.tabs[3].items[2]` (`$` referring to the column value)
|
44
|
-
*/
|
45
|
-
jsonPath: string
|
46
|
-
}
|
47
|
-
|
48
|
-
// NOTE Not yet used but we might want to use this in order to avoid write queries in read-only situations
|
49
|
-
export type Write = {
|
50
|
-
_tag: 'Write'
|
51
|
-
}
|
52
|
-
|
53
|
-
// NOTE maybe we want to bring back type-params back like below
|
54
|
-
// export type Row<TTableDef extends DbSchema.TableDefBase> = {
|
55
|
-
// _tag: 'Row'
|
56
|
-
// table: TTableDef
|
57
|
-
// id: string | SessionIdSymbol
|
58
|
-
// }
|
59
|
-
|
60
|
-
// export type Col<TTableDef extends DbSchema.TableDefBase, TColName extends keyof TTableDef['sqliteDef']['columns']> = {
|
61
|
-
// _tag: 'Col'
|
62
|
-
// table: TTableDef
|
63
|
-
// id: string | SessionIdSymbol
|
64
|
-
// column: TColName
|
65
|
-
// }
|
66
|
-
|
67
|
-
// export type ColJsonValue<TTableDef extends DbSchema.TableDefBase, TColName extends GetJsonColumn<TTableDef>> = {
|
68
|
-
// _tag: 'ColJsonValue'
|
69
|
-
// table: TTableDef
|
70
|
-
// id: string | SessionIdSymbol
|
71
|
-
// column: TColName
|
72
|
-
// /**
|
73
|
-
// * example: `$.tabs[3].items[2]` (`$` referring to the column value)
|
74
|
-
// */
|
75
|
-
// jsonPath: string
|
76
|
-
// }
|
77
|
-
}
|
78
|
-
|
79
|
-
// type GetJsonColumn<TTableDef extends DbSchema.TableDefBase> = keyof {
|
80
|
-
// [ColName in keyof TTableDef['sqliteDef']['columns'] as TTableDef['sqliteDef']['columns'][ColName]['columnType'] extends 'text'
|
81
|
-
// ? ColName
|
82
|
-
// : never]: {}
|
83
|
-
// }
|
package/src/schema/mutations.ts
DELETED
@@ -1,193 +0,0 @@
|
|
1
|
-
import { Schema } from '@livestore/utils/effect'
|
2
|
-
|
3
|
-
import type { QueryBuilder } from '../query-builder/mod.js'
|
4
|
-
import type { BindValues } from '../sql-queries/sql-queries.js'
|
5
|
-
|
6
|
-
export type MutationDefMap = {
|
7
|
-
map: Map<string | 'livestore.RawSql', MutationDef.Any>
|
8
|
-
wasProvided: boolean
|
9
|
-
}
|
10
|
-
export type MutationDefRecord = {
|
11
|
-
'livestore.RawSql': RawSqlMutation
|
12
|
-
[name: string]: MutationDef.Any
|
13
|
-
}
|
14
|
-
|
15
|
-
export type InternalMutationSchema<TRecord extends MutationDefRecord = MutationDefRecord> = {
|
16
|
-
_DefRecord: TRecord
|
17
|
-
|
18
|
-
map: Map<keyof TRecord, TRecord[keyof TRecord]>
|
19
|
-
schemaHashMap: Map<keyof TRecord, number>
|
20
|
-
}
|
21
|
-
|
22
|
-
export type MutationDefSqlResult<TTo> =
|
23
|
-
| SingleOrReadonlyArray<string>
|
24
|
-
| ((
|
25
|
-
args: TTo,
|
26
|
-
context: { currentFacts: MutationEventFacts; clientOnly: boolean },
|
27
|
-
) => SingleOrReadonlyArray<
|
28
|
-
| string
|
29
|
-
| {
|
30
|
-
sql: string
|
31
|
-
/** Note args need to be manually encoded to `BindValues` when returning this argument */
|
32
|
-
bindValues: BindValues
|
33
|
-
writeTables?: ReadonlySet<string>
|
34
|
-
}
|
35
|
-
| QueryBuilder.Any
|
36
|
-
>)
|
37
|
-
|
38
|
-
export type MutationHandlerResult = {
|
39
|
-
sql: string
|
40
|
-
bindValues: BindValues
|
41
|
-
writeTables?: ReadonlySet<string>
|
42
|
-
}
|
43
|
-
|
44
|
-
export type SingleOrReadonlyArray<T> = T | ReadonlyArray<T>
|
45
|
-
|
46
|
-
export type MutationDef<TName extends string, TFrom, TTo> = {
|
47
|
-
name: TName
|
48
|
-
schema: Schema.Schema<TTo, TFrom>
|
49
|
-
sql: MutationDefSqlResult<NoInfer<TTo>>
|
50
|
-
options: {
|
51
|
-
/** Warning: This feature is not fully implemented yet */
|
52
|
-
historyId: string
|
53
|
-
/**
|
54
|
-
* When set to true, the mutation won't be synced across clients but
|
55
|
-
*/
|
56
|
-
clientOnly: boolean
|
57
|
-
/** Warning: This feature is not fully implemented yet */
|
58
|
-
facts: FactsCallback<TTo> | undefined
|
59
|
-
}
|
60
|
-
|
61
|
-
/** Helper function to construct a partial mutation event */
|
62
|
-
(args: TTo): {
|
63
|
-
mutation: TName
|
64
|
-
args: TTo
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
export type FactsCallback<TTo> = (
|
69
|
-
args: TTo,
|
70
|
-
currentFacts: MutationEventFacts,
|
71
|
-
) => {
|
72
|
-
modify: {
|
73
|
-
set: Iterable<MutationEventFactInput>
|
74
|
-
unset: Iterable<MutationEventFactInput>
|
75
|
-
}
|
76
|
-
require: Iterable<MutationEventFactInput>
|
77
|
-
}
|
78
|
-
|
79
|
-
export namespace MutationDef {
|
80
|
-
export type Any = MutationDef<string, any, any>
|
81
|
-
}
|
82
|
-
|
83
|
-
export type MutationEventKey = string
|
84
|
-
export type MutationEventFact = string
|
85
|
-
export type MutationEventFacts = ReadonlyMap<string, any>
|
86
|
-
|
87
|
-
export type MutationEventFactsGroup = {
|
88
|
-
modifySet: MutationEventFacts
|
89
|
-
modifyUnset: MutationEventFacts
|
90
|
-
|
91
|
-
/**
|
92
|
-
* Events on independent "dependency" branches are commutative which can facilitate more prioritized syncing
|
93
|
-
*/
|
94
|
-
depRequire: MutationEventFacts
|
95
|
-
depRead: MutationEventFacts
|
96
|
-
}
|
97
|
-
|
98
|
-
export type MutationEventFactsSnapshot = Map<string, any>
|
99
|
-
|
100
|
-
export type MutationEventFactInput = string | readonly [string, any]
|
101
|
-
|
102
|
-
export const defineFacts = <
|
103
|
-
TRecord extends Record<string, MutationEventFactInput | ((...args: any[]) => MutationEventFactInput)>,
|
104
|
-
>(
|
105
|
-
record: TRecord,
|
106
|
-
): TRecord => record
|
107
|
-
|
108
|
-
export type DefineMutationOptions<TTo> = {
|
109
|
-
// TODO actually implement this
|
110
|
-
onError?: (error: any) => void
|
111
|
-
historyId?: string
|
112
|
-
/** Warning: This feature is not fully implemented yet */
|
113
|
-
facts?: (
|
114
|
-
args: TTo,
|
115
|
-
currentFacts: MutationEventFacts,
|
116
|
-
) => {
|
117
|
-
modify?: {
|
118
|
-
set?: Iterable<MutationEventFactInput>
|
119
|
-
unset?: Iterable<MutationEventFactInput>
|
120
|
-
}
|
121
|
-
/**
|
122
|
-
* Two purposes: constrain history and constrain compaction
|
123
|
-
*/
|
124
|
-
require?: Iterable<MutationEventFactInput>
|
125
|
-
}
|
126
|
-
/**
|
127
|
-
* When set to true, the mutation won't be synced over the network
|
128
|
-
*/
|
129
|
-
clientOnly?: boolean
|
130
|
-
}
|
131
|
-
|
132
|
-
// TODO possibly also allow for mutation event subsumption behaviour
|
133
|
-
export const defineMutation = <TName extends string, TFrom, TTo>(
|
134
|
-
name: TName,
|
135
|
-
schema: Schema.Schema<TTo, TFrom>,
|
136
|
-
sql: MutationDefSqlResult<NoInfer<TTo>>,
|
137
|
-
options?: DefineMutationOptions<TTo>,
|
138
|
-
): MutationDef<TName, TFrom, TTo> => {
|
139
|
-
const makePartialEvent = (args: TTo) => ({ mutation: name, args })
|
140
|
-
|
141
|
-
Object.defineProperty(makePartialEvent, 'name', { value: name })
|
142
|
-
Object.defineProperty(makePartialEvent, 'schema', { value: schema })
|
143
|
-
Object.defineProperty(makePartialEvent, 'sql', { value: sql })
|
144
|
-
Object.defineProperty(makePartialEvent, 'options', {
|
145
|
-
value: {
|
146
|
-
historyId: options?.historyId ?? 'main',
|
147
|
-
clientOnly: options?.clientOnly ?? false,
|
148
|
-
facts: options?.facts
|
149
|
-
? (args, currentFacts) => {
|
150
|
-
const res = options.facts!(args, currentFacts)
|
151
|
-
return {
|
152
|
-
modify: {
|
153
|
-
set: res.modify?.set ? new Set(res.modify.set) : new Set(),
|
154
|
-
unset: res.modify?.unset ? new Set(res.modify.unset) : new Set(),
|
155
|
-
},
|
156
|
-
require: res.require ? new Set(res.require) : new Set(),
|
157
|
-
}
|
158
|
-
}
|
159
|
-
: undefined,
|
160
|
-
} satisfies MutationDef.Any['options'],
|
161
|
-
})
|
162
|
-
|
163
|
-
return makePartialEvent as MutationDef<TName, TFrom, TTo>
|
164
|
-
}
|
165
|
-
|
166
|
-
export const makeMutationDefRecord = <TInputRecord extends Record<string, MutationDef.Any>>(
|
167
|
-
inputRecord: TInputRecord,
|
168
|
-
): {
|
169
|
-
[K in TInputRecord[keyof TInputRecord]['name']]: Extract<TInputRecord[keyof TInputRecord], { name: K }>
|
170
|
-
} => {
|
171
|
-
const result: any = {}
|
172
|
-
|
173
|
-
for (const [name, def] of Object.entries(inputRecord)) {
|
174
|
-
result[name] = def
|
175
|
-
}
|
176
|
-
|
177
|
-
result['livestore.RawSql'] = rawSqlMutation
|
178
|
-
|
179
|
-
return result
|
180
|
-
}
|
181
|
-
|
182
|
-
export const rawSqlMutation = defineMutation(
|
183
|
-
'livestore.RawSql',
|
184
|
-
Schema.Struct({
|
185
|
-
sql: Schema.String,
|
186
|
-
bindValues: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
|
187
|
-
writeTables: Schema.optional(Schema.ReadonlySet(Schema.String)),
|
188
|
-
}),
|
189
|
-
({ sql, bindValues, writeTables }) => ({ sql, bindValues: bindValues ?? {}, writeTables }),
|
190
|
-
)
|
191
|
-
|
192
|
-
export type RawSqlMutation = typeof rawSqlMutation
|
193
|
-
export type RawSqlMutationEvent = ReturnType<typeof rawSqlMutation>
|