@livestore/common 0.3.0-dev.2 → 0.3.0-dev.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixture.d.ts +21 -21
- package/dist/adapter-types.d.ts +97 -53
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +17 -0
- 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 +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/derived-mutations.d.ts +5 -5
- package/dist/derived-mutations.d.ts.map +1 -1
- package/dist/derived-mutations.js +3 -3
- package/dist/derived-mutations.js.map +1 -1
- package/dist/derived-mutations.test.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +389 -0
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-client-session.js +96 -0
- package/dist/devtools/devtools-messages-client-session.js.map +1 -0
- package/dist/devtools/devtools-messages-common.d.ts +61 -0
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-common.js +54 -0
- package/dist/devtools/devtools-messages-common.js.map +1 -0
- package/dist/devtools/devtools-messages-leader.d.ts +393 -0
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-leader.js +148 -0
- package/dist/devtools/devtools-messages-leader.js.map +1 -0
- package/dist/devtools/devtools-messages.d.ts +3 -592
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +3 -171
- package/dist/devtools/devtools-messages.js.map +1 -1
- package/dist/devtools/devtools-sessioninfo.d.ts +28 -0
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -0
- package/dist/devtools/devtools-sessioninfo.js +34 -0
- package/dist/devtools/devtools-sessioninfo.js.map +1 -0
- package/dist/devtools/mod.d.ts +39 -0
- package/dist/devtools/mod.d.ts.map +1 -0
- package/dist/devtools/mod.js +27 -0
- package/dist/devtools/mod.js.map +1 -0
- package/dist/index.d.ts +2 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/init-singleton-tables.d.ts +2 -2
- package/dist/init-singleton-tables.d.ts.map +1 -1
- package/dist/init-singleton-tables.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +39 -0
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -0
- package/dist/leader-thread/LeaderSyncProcessor.js +527 -0
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
- package/dist/leader-thread/apply-mutation.d.ts +5 -2
- package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
- package/dist/leader-thread/apply-mutation.js +55 -35
- package/dist/leader-thread/apply-mutation.js.map +1 -1
- package/dist/leader-thread/connection.d.ts +34 -6
- package/dist/leader-thread/connection.d.ts.map +1 -1
- package/dist/leader-thread/connection.js +22 -7
- package/dist/leader-thread/connection.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +147 -124
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +12 -11
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +55 -18
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +6 -19
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +12 -9
- package/dist/leader-thread/mutationlog.js.map +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts +3 -3
- package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
- package/dist/leader-thread/pull-queue-set.js +9 -0
- package/dist/leader-thread/pull-queue-set.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +4 -2
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +32 -21
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -5
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -4
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/types.d.ts +58 -26
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +1 -3
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/mutation.d.ts +9 -2
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +5 -5
- package/dist/mutation.js.map +1 -1
- package/dist/otel.d.ts +2 -0
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +5 -0
- package/dist/otel.js.map +1 -1
- package/dist/query-builder/api.d.ts +3 -3
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/query-builder/impl.d.ts +4 -4
- package/dist/query-builder/impl.d.ts.map +1 -1
- package/dist/query-builder/impl.js.map +1 -1
- package/dist/query-builder/impl.test.js +16 -1
- package/dist/query-builder/impl.test.js.map +1 -1
- package/dist/query-info.d.ts +3 -3
- package/dist/query-info.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts +5 -5
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +23 -27
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +27 -16
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +36 -11
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/EventId.test.d.ts +2 -0
- package/dist/schema/EventId.test.d.ts.map +1 -0
- package/dist/schema/EventId.test.js +11 -0
- package/dist/schema/EventId.test.js.map +1 -0
- package/dist/schema/MutationEvent.d.ts +76 -82
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +53 -20
- package/dist/schema/MutationEvent.js.map +1 -1
- package/dist/schema/db-schema/ast/sqlite.d.ts +69 -0
- package/dist/schema/db-schema/ast/sqlite.d.ts.map +1 -0
- package/dist/schema/db-schema/ast/sqlite.js +71 -0
- package/dist/schema/db-schema/ast/sqlite.js.map +1 -0
- package/dist/schema/db-schema/ast/validate.d.ts +3 -0
- package/dist/schema/db-schema/ast/validate.d.ts.map +1 -0
- package/dist/schema/db-schema/ast/validate.js +12 -0
- package/dist/schema/db-schema/ast/validate.js.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.d.ts +90 -0
- package/dist/schema/db-schema/dsl/field-defs.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.js +87 -0
- package/dist/schema/db-schema/dsl/field-defs.js.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.test.d.ts +2 -0
- package/dist/schema/db-schema/dsl/field-defs.test.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/field-defs.test.js +29 -0
- package/dist/schema/db-schema/dsl/field-defs.test.js.map +1 -0
- package/dist/schema/db-schema/dsl/mod.d.ts +88 -0
- package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/mod.js +35 -0
- package/dist/schema/db-schema/dsl/mod.js.map +1 -0
- package/dist/schema/db-schema/hash.d.ts +2 -0
- package/dist/schema/db-schema/hash.d.ts.map +1 -0
- package/dist/schema/db-schema/hash.js +14 -0
- package/dist/schema/db-schema/hash.js.map +1 -0
- package/dist/schema/db-schema/mod.d.ts +3 -0
- package/dist/schema/db-schema/mod.d.ts.map +1 -0
- package/dist/schema/db-schema/mod.js +3 -0
- package/dist/schema/db-schema/mod.js.map +1 -0
- package/dist/schema/mod.d.ts +1 -0
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +1 -0
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/mutations.d.ts +8 -9
- package/dist/schema/mutations.d.ts.map +1 -1
- package/dist/schema/mutations.js +2 -2
- package/dist/schema/mutations.js.map +1 -1
- package/dist/schema/schema-helpers.d.ts.map +1 -1
- package/dist/schema/schema-helpers.js +1 -1
- package/dist/schema/schema-helpers.js.map +1 -1
- package/dist/schema/schema.d.ts +5 -2
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +20 -9
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/system-tables.d.ts +65 -47
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +24 -13
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +18 -24
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +3 -4
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema-management/common.d.ts +3 -3
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/common.js.map +1 -1
- package/dist/schema-management/migrations.d.ts +6 -6
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +13 -8
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
- package/dist/schema-management/validate-mutation-defs.js +2 -2
- package/dist/schema-management/validate-mutation-defs.js.map +1 -1
- package/dist/sql-queries/misc.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.d.ts +1 -1
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js.map +1 -1
- package/dist/sql-queries/types.d.ts +2 -1
- package/dist/sql-queries/types.d.ts.map +1 -1
- package/dist/sql-queries/types.js.map +1 -1
- package/dist/sync/{client-session-sync-processor.d.ts → ClientSessionSyncProcessor.d.ts} +25 -14
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -0
- package/dist/sync/ClientSessionSyncProcessor.js +199 -0
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -0
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +1 -1
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +3 -4
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +3 -1
- package/dist/sync/next/history-dag-common.js.map +1 -1
- package/dist/sync/next/history-dag.d.ts.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 +6 -4
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +6 -3
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +12 -12
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +43 -43
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts +4 -4
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.js +12 -16
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
- package/dist/sync/sync.d.ts +31 -16
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js +7 -3
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +177 -44
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +188 -56
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +162 -92
- 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 +2 -2
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/util.d.ts +2 -2
- package/dist/util.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +6 -6
- package/src/adapter-types.ts +80 -56
- package/src/derived-mutations.test.ts +1 -1
- package/src/derived-mutations.ts +13 -9
- package/src/devtools/devtools-messages-client-session.ts +141 -0
- package/src/devtools/devtools-messages-common.ts +106 -0
- package/src/devtools/devtools-messages-leader.ts +192 -0
- package/src/devtools/devtools-messages.ts +3 -243
- package/src/devtools/devtools-sessioninfo.ts +99 -0
- package/src/devtools/mod.ts +36 -0
- package/src/index.ts +2 -8
- package/src/init-singleton-tables.ts +2 -2
- package/src/leader-thread/LeaderSyncProcessor.ts +833 -0
- package/src/leader-thread/apply-mutation.ts +87 -43
- package/src/leader-thread/connection.ts +54 -9
- package/src/leader-thread/leader-worker-devtools.ts +199 -174
- package/src/leader-thread/make-leader-thread-layer.ts +89 -35
- package/src/leader-thread/mutationlog.ts +20 -14
- package/src/leader-thread/pull-queue-set.ts +10 -1
- package/src/leader-thread/recreate-db.ts +38 -25
- package/src/leader-thread/shutdown-channel.ts +2 -4
- package/src/leader-thread/types.ts +68 -34
- package/src/mutation.ts +17 -7
- package/src/otel.ts +8 -0
- package/src/query-builder/api.ts +4 -4
- package/src/query-builder/impl.test.ts +22 -1
- package/src/query-builder/impl.ts +2 -2
- package/src/query-info.ts +3 -3
- package/src/rehydrate-from-mutationlog.ts +28 -34
- package/src/schema/EventId.test.ts +12 -0
- package/src/schema/EventId.ts +49 -15
- package/src/schema/MutationEvent.ts +78 -31
- package/src/schema/db-schema/ast/sqlite.ts +142 -0
- package/src/schema/db-schema/ast/validate.ts +13 -0
- package/src/schema/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +206 -0
- package/src/schema/db-schema/dsl/field-defs.test.ts +35 -0
- package/src/schema/db-schema/dsl/field-defs.ts +242 -0
- package/src/schema/db-schema/dsl/mod.ts +195 -0
- package/src/schema/db-schema/hash.ts +14 -0
- package/src/schema/db-schema/mod.ts +2 -0
- package/src/schema/mod.ts +1 -0
- package/src/schema/mutations.ts +10 -20
- package/src/schema/schema-helpers.ts +1 -1
- package/src/schema/schema.ts +22 -10
- package/src/schema/system-tables.ts +24 -13
- package/src/schema/table-def.ts +17 -17
- package/src/schema-management/common.ts +3 -3
- package/src/schema-management/migrations.ts +19 -15
- package/src/schema-management/validate-mutation-defs.ts +2 -2
- package/src/sql-queries/sql-queries.ts +1 -1
- package/src/sql-queries/sql-query-builder.ts +1 -2
- package/src/sql-queries/types.ts +3 -1
- package/src/sync/ClientSessionSyncProcessor.ts +313 -0
- package/src/sync/index.ts +1 -1
- package/src/sync/next/facts.ts +1 -1
- package/src/sync/next/history-dag-common.ts +5 -1
- package/src/sync/next/history-dag.ts +1 -1
- package/src/sync/next/rebase-events.ts +13 -7
- package/src/sync/next/test/compact-events.calculator.test.ts +12 -12
- package/src/sync/next/test/compact-events.test.ts +43 -43
- package/src/sync/next/test/mutation-fixtures.ts +16 -19
- package/src/sync/sync.ts +26 -10
- package/src/sync/syncstate.test.ts +178 -98
- package/src/sync/syncstate.ts +170 -83
- package/src/sync/validate-push-payload.ts +7 -4
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +1 -1
- package/dist/devtools/devtools-bridge.d.ts +0 -12
- package/dist/devtools/devtools-bridge.d.ts.map +0 -1
- package/dist/devtools/devtools-bridge.js +0 -2
- package/dist/devtools/devtools-bridge.js.map +0 -1
- package/dist/devtools/index.d.ts +0 -42
- package/dist/devtools/index.d.ts.map +0 -1
- package/dist/devtools/index.js +0 -48
- package/dist/devtools/index.js.map +0 -1
- package/dist/leader-thread/leader-sync-processor.d.ts +0 -47
- package/dist/leader-thread/leader-sync-processor.d.ts.map +0 -1
- package/dist/leader-thread/leader-sync-processor.js +0 -422
- package/dist/leader-thread/leader-sync-processor.js.map +0 -1
- package/dist/sync/client-session-sync-processor.d.ts.map +0 -1
- package/dist/sync/client-session-sync-processor.js +0 -131
- package/dist/sync/client-session-sync-processor.js.map +0 -1
- package/src/devtools/devtools-bridge.ts +0 -13
- package/src/devtools/index.ts +0 -48
- package/src/leader-thread/leader-sync-processor.ts +0 -666
- package/src/sync/client-session-sync-processor.ts +0 -207
@@ -1,8 +1,8 @@
|
|
1
|
-
import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
|
2
1
|
import { memoizeByStringifyArgs } from '@livestore/utils'
|
3
2
|
import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
|
4
3
|
|
5
|
-
import type {
|
4
|
+
import type { MigrationsReport, MigrationsReportEntry, SqliteDb, UnexpectedError } from '../adapter-types.js'
|
5
|
+
import { SqliteAst, SqliteDsl } from '../schema/db-schema/mod.js'
|
6
6
|
import type { LiveStoreSchema } from '../schema/mod.js'
|
7
7
|
import type { SchemaMetaRow, SchemaMutationsMetaRow } from '../schema/system-tables.js'
|
8
8
|
import {
|
@@ -19,7 +19,7 @@ import { validateSchema } from './validate-mutation-defs.js'
|
|
19
19
|
|
20
20
|
const getMemoizedTimestamp = memoizeByStringifyArgs(() => new Date().toISOString())
|
21
21
|
|
22
|
-
export const makeSchemaManager = (db:
|
22
|
+
export const makeSchemaManager = (db: SqliteDb): Effect.Effect<SchemaManager> =>
|
23
23
|
Effect.gen(function* () {
|
24
24
|
yield* migrateTable({
|
25
25
|
db,
|
@@ -51,10 +51,10 @@ export const migrateDb = ({
|
|
51
51
|
schema,
|
52
52
|
onProgress,
|
53
53
|
}: {
|
54
|
-
db:
|
54
|
+
db: SqliteDb
|
55
55
|
schema: LiveStoreSchema
|
56
56
|
onProgress?: (opts: { done: number; total: number }) => Effect.Effect<void>
|
57
|
-
}) =>
|
57
|
+
}): Effect.Effect<MigrationsReport, UnexpectedError> =>
|
58
58
|
Effect.gen(function* () {
|
59
59
|
yield* migrateTable({
|
60
60
|
db,
|
@@ -81,6 +81,7 @@ export const migrateDb = ({
|
|
81
81
|
|
82
82
|
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: number }>()
|
83
83
|
|
84
|
+
const migrationsReportEntries: MigrationsReportEntry[] = []
|
84
85
|
for (const tableDef of tableDefs) {
|
85
86
|
const tableAst = tableDef.sqliteDef.ast
|
86
87
|
const tableName = tableAst.name
|
@@ -90,9 +91,10 @@ export const migrateDb = ({
|
|
90
91
|
if (schemaHash !== dbSchemaHash) {
|
91
92
|
tablesToMigrate.add({ tableAst, schemaHash })
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
migrationsReportEntries.push({
|
95
|
+
tableName,
|
96
|
+
hashes: { expected: schemaHash, actual: dbSchemaHash },
|
97
|
+
})
|
96
98
|
}
|
97
99
|
}
|
98
100
|
|
@@ -107,6 +109,8 @@ export const migrateDb = ({
|
|
107
109
|
yield* onProgress({ done: processedTables, total: tablesCount })
|
108
110
|
}
|
109
111
|
}
|
112
|
+
|
113
|
+
return { migrations: migrationsReportEntries }
|
110
114
|
})
|
111
115
|
|
112
116
|
export const migrateTable = ({
|
@@ -116,7 +120,7 @@ export const migrateTable = ({
|
|
116
120
|
behaviour,
|
117
121
|
skipMetaTable = false,
|
118
122
|
}: {
|
119
|
-
db:
|
123
|
+
db: SqliteDb
|
120
124
|
tableAst: SqliteAst.Table
|
121
125
|
schemaHash?: number
|
122
126
|
behaviour: 'drop-and-recreate' | 'create-if-not-exists'
|
@@ -129,10 +133,10 @@ export const migrateTable = ({
|
|
129
133
|
|
130
134
|
if (behaviour === 'drop-and-recreate') {
|
131
135
|
// TODO need to possibly handle cascading deletes due to foreign keys
|
132
|
-
dbExecute(db, sql`drop table if exists ${tableName}`)
|
133
|
-
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
136
|
+
dbExecute(db, sql`drop table if exists '${tableName}'`)
|
137
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
134
138
|
} else if (behaviour === 'create-if-not-exists') {
|
135
|
-
dbExecute(db, sql`create table if not exists ${tableName} (${columnSpec}) strict`)
|
139
|
+
dbExecute(db, sql`create table if not exists '${tableName}' (${columnSpec}) strict`)
|
136
140
|
}
|
137
141
|
|
138
142
|
for (const index of tableAst.indexes) {
|
@@ -162,11 +166,11 @@ export const migrateTable = ({
|
|
162
166
|
|
163
167
|
const createIndexFromDefinition = (tableName: string, index: SqliteAst.Index) => {
|
164
168
|
const uniqueStr = index.unique ? 'UNIQUE' : ''
|
165
|
-
return sql`create ${uniqueStr} index if not exists ${index.name} on ${tableName} (${index.columns.join(', ')})`
|
169
|
+
return sql`create ${uniqueStr} index if not exists '${index.name}' on '${tableName}' (${index.columns.join(', ')})`
|
166
170
|
}
|
167
171
|
|
168
172
|
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
169
|
-
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => _.name)
|
173
|
+
const primaryKeys = tableAst.columns.filter((_) => _.primaryKey).map((_) => `'${_.name}'`)
|
170
174
|
const columnDefStrs = tableAst.columns.map(toSqliteColumnSpec)
|
171
175
|
if (primaryKeys.length > 0) {
|
172
176
|
columnDefStrs.push(`PRIMARY KEY (${primaryKeys.join(', ')})`)
|
@@ -191,5 +195,5 @@ const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
191
195
|
return `default ${encodedDefaultValue}`
|
192
196
|
})()
|
193
197
|
|
194
|
-
return
|
198
|
+
return `'${column.name}' ${columnTypeStr} ${nullableStr} ${defaultValueStr}`
|
195
199
|
}
|
@@ -11,7 +11,7 @@ export const validateSchema = (schema: LiveStoreSchema, schemaManager: SchemaMan
|
|
11
11
|
const registeredMutationDefInfos = schemaManager.getMutationDefInfos()
|
12
12
|
|
13
13
|
const missingMutationDefs = registeredMutationDefInfos.filter(
|
14
|
-
(registeredMutationDefInfo) => !schema.mutations.has(registeredMutationDefInfo.mutationName),
|
14
|
+
(registeredMutationDefInfo) => !schema.mutations.map.has(registeredMutationDefInfo.mutationName),
|
15
15
|
)
|
16
16
|
|
17
17
|
if (missingMutationDefs.length > 0) {
|
@@ -20,7 +20,7 @@ export const validateSchema = (schema: LiveStoreSchema, schemaManager: SchemaMan
|
|
20
20
|
})
|
21
21
|
}
|
22
22
|
|
23
|
-
for (const [, mutationDef] of schema.mutations) {
|
23
|
+
for (const [, mutationDef] of schema.mutations.map) {
|
24
24
|
const registeredMutationDefInfo = registeredMutationDefInfos.find(
|
25
25
|
(info) => info.mutationName === mutationDef.name,
|
26
26
|
)
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import type { SqliteDsl } from '@livestore/db-schema'
|
2
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
3
2
|
import { pipe, ReadonlyArray, Schema, TreeFormatter } from '@livestore/utils/effect'
|
4
3
|
|
4
|
+
import type { SqliteDsl } from '../schema/db-schema/mod.js'
|
5
5
|
import { sql } from '../util.js'
|
6
6
|
import { objectEntries } from './misc.js'
|
7
7
|
import * as ClientTypes from './types.js'
|
package/src/sql-queries/types.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
import type { Prettify
|
1
|
+
import type { Prettify } from '@livestore/utils'
|
2
2
|
import type { Schema } from '@livestore/utils/effect'
|
3
3
|
|
4
|
+
import type { SqliteDsl } from '../schema/db-schema/mod.js'
|
5
|
+
|
4
6
|
export type DecodedValuesForTableAll<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = {
|
5
7
|
[K in keyof GetColumns<TSchema, TTableName>]: Schema.Schema.Type<GetColumn<TSchema, TTableName, K>['schema']>
|
6
8
|
}
|
@@ -0,0 +1,313 @@
|
|
1
|
+
import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
2
|
+
import type { Runtime, Scope } from '@livestore/utils/effect'
|
3
|
+
import { BucketQueue, Effect, FiberHandle, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
|
4
|
+
import * as otel from '@opentelemetry/api'
|
5
|
+
|
6
|
+
import type { ClientSession, UnexpectedError } from '../adapter-types.js'
|
7
|
+
import * as EventId from '../schema/EventId.js'
|
8
|
+
import { getMutationDef, type LiveStoreSchema } from '../schema/mod.js'
|
9
|
+
import * as MutationEvent from '../schema/MutationEvent.js'
|
10
|
+
import * as SyncState from './syncstate.js'
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Rebase behaviour:
|
14
|
+
* - We continously pull mutations from the leader and apply them to the local store.
|
15
|
+
* - If there was a race condition (i.e. the leader and client session have both advacned),
|
16
|
+
* we'll need to rebase the local pending mutations on top of the leader's head.
|
17
|
+
* - The goal is to never block the UI, so we'll interrupt rebasing if a new mutations is pushed by the client session.
|
18
|
+
* - We also want to avoid "backwards-jumping" in the UI, so we'll transactionally apply a read model changes during a rebase.
|
19
|
+
* - We might need to make the rebase behaviour configurable e.g. to let users manually trigger a rebase
|
20
|
+
*/
|
21
|
+
export const makeClientSessionSyncProcessor = ({
|
22
|
+
schema,
|
23
|
+
clientSession,
|
24
|
+
runtime,
|
25
|
+
applyMutation,
|
26
|
+
rollback,
|
27
|
+
refreshTables,
|
28
|
+
span,
|
29
|
+
params,
|
30
|
+
confirmUnsavedChanges,
|
31
|
+
}: {
|
32
|
+
schema: LiveStoreSchema
|
33
|
+
clientSession: ClientSession
|
34
|
+
runtime: Runtime.Runtime<Scope.Scope>
|
35
|
+
applyMutation: (
|
36
|
+
mutationEventDecoded: MutationEvent.PartialAnyDecoded,
|
37
|
+
options: { otelContext: otel.Context; withChangeset: boolean },
|
38
|
+
) => {
|
39
|
+
writeTables: Set<string>
|
40
|
+
sessionChangeset: Uint8Array | undefined
|
41
|
+
}
|
42
|
+
rollback: (changeset: Uint8Array) => void
|
43
|
+
refreshTables: (tables: Set<string>) => void
|
44
|
+
span: otel.Span
|
45
|
+
params: {
|
46
|
+
leaderPushBatchSize: number
|
47
|
+
}
|
48
|
+
/**
|
49
|
+
* Currently only used in the web adapter:
|
50
|
+
* If true, registers a beforeunload event listener to confirm unsaved changes.
|
51
|
+
*/
|
52
|
+
confirmUnsavedChanges: boolean
|
53
|
+
}): ClientSessionSyncProcessor => {
|
54
|
+
const mutationEventSchema = MutationEvent.makeMutationEventSchemaMemo(schema)
|
55
|
+
|
56
|
+
const syncStateRef = {
|
57
|
+
current: new SyncState.SyncState({
|
58
|
+
localHead: clientSession.leaderThread.initialState.leaderHead,
|
59
|
+
upstreamHead: clientSession.leaderThread.initialState.leaderHead,
|
60
|
+
pending: [],
|
61
|
+
// TODO init rollbackTail from leader to be ready for backend rebasing
|
62
|
+
rollbackTail: [],
|
63
|
+
}),
|
64
|
+
}
|
65
|
+
|
66
|
+
const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>().pipe(Effect.runSync)
|
67
|
+
const isLocalEvent = (mutationEventEncoded: MutationEvent.EncodedWithMeta) =>
|
68
|
+
getMutationDef(schema, mutationEventEncoded.mutation).options.clientOnly
|
69
|
+
|
70
|
+
/** We're queuing push requests to reduce the number of messages sent to the leader by batching them */
|
71
|
+
const leaderPushQueue = BucketQueue.make<MutationEvent.EncodedWithMeta>().pipe(Effect.runSync)
|
72
|
+
|
73
|
+
const push: ClientSessionSyncProcessor['push'] = (batch, { otelContext }) => {
|
74
|
+
// TODO validate batch
|
75
|
+
|
76
|
+
let baseEventId = syncStateRef.current.localHead
|
77
|
+
const encodedMutationEvents = batch.map((mutationEvent) => {
|
78
|
+
const mutationDef = getMutationDef(schema, mutationEvent.mutation)
|
79
|
+
const nextIdPair = EventId.nextPair(baseEventId, mutationDef.options.clientOnly)
|
80
|
+
baseEventId = nextIdPair.id
|
81
|
+
return new MutationEvent.EncodedWithMeta(
|
82
|
+
Schema.encodeUnknownSync(mutationEventSchema)({
|
83
|
+
...mutationEvent,
|
84
|
+
...nextIdPair,
|
85
|
+
clientId: clientSession.clientId,
|
86
|
+
sessionId: clientSession.sessionId,
|
87
|
+
}),
|
88
|
+
)
|
89
|
+
})
|
90
|
+
|
91
|
+
const updateResult = SyncState.updateSyncState({
|
92
|
+
syncState: syncStateRef.current,
|
93
|
+
payload: { _tag: 'local-push', newEvents: encodedMutationEvents },
|
94
|
+
isLocalEvent,
|
95
|
+
isEqualEvent: MutationEvent.isEqualEncoded,
|
96
|
+
})
|
97
|
+
|
98
|
+
if (updateResult._tag === 'unexpected-error') {
|
99
|
+
return shouldNeverHappen('Unexpected error in client-session-sync-processor', updateResult.cause)
|
100
|
+
}
|
101
|
+
|
102
|
+
span.addEvent('local-push', {
|
103
|
+
batchSize: encodedMutationEvents.length,
|
104
|
+
updateResult: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
105
|
+
})
|
106
|
+
|
107
|
+
if (updateResult._tag !== 'advance') {
|
108
|
+
return shouldNeverHappen(`Expected advance, got ${updateResult._tag}`)
|
109
|
+
}
|
110
|
+
|
111
|
+
syncStateRef.current = updateResult.newSyncState
|
112
|
+
syncStateUpdateQueue.offer(updateResult.newSyncState).pipe(Effect.runSync)
|
113
|
+
|
114
|
+
const writeTables = new Set<string>()
|
115
|
+
for (const mutationEvent of updateResult.newEvents) {
|
116
|
+
// TODO avoid encoding and decoding here again
|
117
|
+
const decodedMutationEvent = Schema.decodeSync(mutationEventSchema)(mutationEvent)
|
118
|
+
const res = applyMutation(decodedMutationEvent, { otelContext, withChangeset: true })
|
119
|
+
for (const table of res.writeTables) {
|
120
|
+
writeTables.add(table)
|
121
|
+
}
|
122
|
+
mutationEvent.meta.sessionChangeset = res.sessionChangeset
|
123
|
+
}
|
124
|
+
|
125
|
+
// console.debug('pushToLeader', encodedMutationEvents.length, ...encodedMutationEvents.map((_) => _.toJSON()))
|
126
|
+
BucketQueue.offerAll(leaderPushQueue, encodedMutationEvents).pipe(Effect.runSync)
|
127
|
+
|
128
|
+
return { writeTables }
|
129
|
+
}
|
130
|
+
|
131
|
+
const debugInfo = {
|
132
|
+
rebaseCount: 0,
|
133
|
+
advanceCount: 0,
|
134
|
+
rejectCount: 0,
|
135
|
+
}
|
136
|
+
|
137
|
+
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
138
|
+
|
139
|
+
const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
|
140
|
+
// eslint-disable-next-line unicorn/prefer-global-this
|
141
|
+
if (confirmUnsavedChanges && typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
142
|
+
const onBeforeUnload = (event: BeforeUnloadEvent) => {
|
143
|
+
if (syncStateRef.current.pending.length > 0) {
|
144
|
+
// Trigger the default browser dialog
|
145
|
+
event.preventDefault()
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
yield* Effect.acquireRelease(
|
150
|
+
Effect.sync(() => window.addEventListener('beforeunload', onBeforeUnload)),
|
151
|
+
() => Effect.sync(() => window.removeEventListener('beforeunload', onBeforeUnload)),
|
152
|
+
)
|
153
|
+
}
|
154
|
+
|
155
|
+
const leaderPushingFiberHandle = yield* FiberHandle.make()
|
156
|
+
|
157
|
+
const backgroundLeaderPushing = Effect.gen(function* () {
|
158
|
+
const batch = yield* BucketQueue.takeBetween(leaderPushQueue, 1, params.leaderPushBatchSize)
|
159
|
+
yield* clientSession.leaderThread.mutations.push(batch).pipe(
|
160
|
+
Effect.catchTag('LeaderAheadError', () => {
|
161
|
+
debugInfo.rejectCount++
|
162
|
+
return BucketQueue.clear(leaderPushQueue)
|
163
|
+
}),
|
164
|
+
)
|
165
|
+
}).pipe(Effect.forever, Effect.interruptible, Effect.tapCauseLogPretty)
|
166
|
+
|
167
|
+
yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
|
168
|
+
|
169
|
+
yield* clientSession.leaderThread.mutations.pull.pipe(
|
170
|
+
Stream.tap(({ payload, remaining }) =>
|
171
|
+
Effect.gen(function* () {
|
172
|
+
// console.log('pulled payload from leader', { payload, remaining })
|
173
|
+
if (clientSession.devtools.enabled) {
|
174
|
+
yield* clientSession.devtools.pullLatch.await
|
175
|
+
}
|
176
|
+
|
177
|
+
const updateResult = SyncState.updateSyncState({
|
178
|
+
syncState: syncStateRef.current,
|
179
|
+
payload,
|
180
|
+
isLocalEvent,
|
181
|
+
isEqualEvent: MutationEvent.isEqualEncoded,
|
182
|
+
})
|
183
|
+
|
184
|
+
if (updateResult._tag === 'unexpected-error') {
|
185
|
+
return yield* Effect.fail(updateResult.cause)
|
186
|
+
} else if (updateResult._tag === 'reject') {
|
187
|
+
return shouldNeverHappen('Unexpected reject in client-session-sync-processor', updateResult)
|
188
|
+
}
|
189
|
+
|
190
|
+
syncStateRef.current = updateResult.newSyncState
|
191
|
+
syncStateUpdateQueue.offer(updateResult.newSyncState).pipe(Effect.runSync)
|
192
|
+
|
193
|
+
if (updateResult._tag === 'rebase') {
|
194
|
+
span.addEvent('pull:rebase', {
|
195
|
+
payloadTag: payload._tag,
|
196
|
+
payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
|
197
|
+
newEventsCount: updateResult.newEvents.length,
|
198
|
+
rollbackCount: updateResult.eventsToRollback.length,
|
199
|
+
res: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
200
|
+
remaining,
|
201
|
+
})
|
202
|
+
|
203
|
+
debugInfo.rebaseCount++
|
204
|
+
|
205
|
+
yield* FiberHandle.clear(leaderPushingFiberHandle)
|
206
|
+
|
207
|
+
// Reset the leader push queue since we're rebasing and will push again
|
208
|
+
yield* BucketQueue.clear(leaderPushQueue)
|
209
|
+
|
210
|
+
yield* FiberHandle.run(leaderPushingFiberHandle, backgroundLeaderPushing)
|
211
|
+
|
212
|
+
if (LS_DEV) {
|
213
|
+
Effect.logDebug(
|
214
|
+
'pull:rebase: rollback',
|
215
|
+
updateResult.eventsToRollback.length,
|
216
|
+
...updateResult.eventsToRollback.slice(0, 10).map((_) => _.toJSON()),
|
217
|
+
).pipe(Effect.provide(runtime), Effect.runSync)
|
218
|
+
}
|
219
|
+
|
220
|
+
for (let i = updateResult.eventsToRollback.length - 1; i >= 0; i--) {
|
221
|
+
const event = updateResult.eventsToRollback[i]!
|
222
|
+
if (event.meta.sessionChangeset) {
|
223
|
+
rollback(event.meta.sessionChangeset)
|
224
|
+
event.meta.sessionChangeset = undefined
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
yield* BucketQueue.offerAll(leaderPushQueue, updateResult.newSyncState.pending)
|
229
|
+
} else {
|
230
|
+
span.addEvent('pull:advance', {
|
231
|
+
payloadTag: payload._tag,
|
232
|
+
payload: TRACE_VERBOSE ? JSON.stringify(payload) : undefined,
|
233
|
+
newEventsCount: updateResult.newEvents.length,
|
234
|
+
res: TRACE_VERBOSE ? JSON.stringify(updateResult) : undefined,
|
235
|
+
remaining,
|
236
|
+
})
|
237
|
+
|
238
|
+
debugInfo.advanceCount++
|
239
|
+
}
|
240
|
+
|
241
|
+
if (updateResult.newEvents.length === 0) return
|
242
|
+
|
243
|
+
const writeTables = new Set<string>()
|
244
|
+
for (const mutationEvent of updateResult.newEvents) {
|
245
|
+
const decodedMutationEvent = Schema.decodeSync(mutationEventSchema)(mutationEvent)
|
246
|
+
const res = applyMutation(decodedMutationEvent, { otelContext, withChangeset: true })
|
247
|
+
for (const table of res.writeTables) {
|
248
|
+
writeTables.add(table)
|
249
|
+
}
|
250
|
+
|
251
|
+
mutationEvent.meta.sessionChangeset = res.sessionChangeset
|
252
|
+
}
|
253
|
+
|
254
|
+
refreshTables(writeTables)
|
255
|
+
}).pipe(
|
256
|
+
Effect.tapCauseLogPretty,
|
257
|
+
Effect.catchAllCause((cause) => Effect.sync(() => clientSession.shutdown(cause))),
|
258
|
+
),
|
259
|
+
),
|
260
|
+
Stream.runDrain,
|
261
|
+
Effect.forever, // NOTE Whenever the leader changes, we need to re-start the stream
|
262
|
+
Effect.withSpan('client-session-sync-processor:pull'),
|
263
|
+
Effect.tapCauseLogPretty,
|
264
|
+
Effect.forkScoped,
|
265
|
+
)
|
266
|
+
})
|
267
|
+
|
268
|
+
return {
|
269
|
+
push,
|
270
|
+
boot,
|
271
|
+
syncState: Subscribable.make({
|
272
|
+
get: Effect.gen(function* () {
|
273
|
+
const syncState = syncStateRef.current
|
274
|
+
if (syncStateRef === undefined) return shouldNeverHappen('Not initialized')
|
275
|
+
return syncState
|
276
|
+
}),
|
277
|
+
changes: Stream.fromQueue(syncStateUpdateQueue),
|
278
|
+
}),
|
279
|
+
debug: {
|
280
|
+
print: () =>
|
281
|
+
Effect.gen(function* () {
|
282
|
+
console.log('debugInfo', debugInfo)
|
283
|
+
console.log('syncState', syncStateRef.current)
|
284
|
+
const pushQueueSize = yield* BucketQueue.size(leaderPushQueue)
|
285
|
+
console.log('pushQueueSize', pushQueueSize)
|
286
|
+
const pushQueueItems = yield* BucketQueue.peekAll(leaderPushQueue)
|
287
|
+
console.log(
|
288
|
+
'pushQueueItems',
|
289
|
+
pushQueueItems.map((_) => _.toJSON()),
|
290
|
+
)
|
291
|
+
}).pipe(Effect.provide(runtime), Effect.runSync),
|
292
|
+
debugInfo: () => debugInfo,
|
293
|
+
},
|
294
|
+
} satisfies ClientSessionSyncProcessor
|
295
|
+
}
|
296
|
+
|
297
|
+
export interface ClientSessionSyncProcessor {
|
298
|
+
push: (
|
299
|
+
batch: ReadonlyArray<MutationEvent.PartialAnyDecoded>,
|
300
|
+
options: { otelContext: otel.Context },
|
301
|
+
) => {
|
302
|
+
writeTables: Set<string>
|
303
|
+
}
|
304
|
+
boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
|
305
|
+
syncState: Subscribable.Subscribable<SyncState.SyncState>
|
306
|
+
debug: {
|
307
|
+
print: () => void
|
308
|
+
debugInfo: () => {
|
309
|
+
rebaseCount: number
|
310
|
+
advanceCount: number
|
311
|
+
}
|
312
|
+
}
|
313
|
+
}
|
package/src/sync/index.ts
CHANGED
package/src/sync/next/facts.ts
CHANGED
@@ -20,7 +20,7 @@ export const emptyHistoryDag = (): HistoryDag =>
|
|
20
20
|
})
|
21
21
|
|
22
22
|
// TODO consider making `ROOT_ID` parent to itself
|
23
|
-
export const rootParentId = { global: EventId.ROOT.global - 1,
|
23
|
+
export const rootParentId = EventId.make({ global: EventId.ROOT.global - 1, client: EventId.clientDefault })
|
24
24
|
|
25
25
|
export type HistoryDagNode = {
|
26
26
|
id: EventId.EventId
|
@@ -30,6 +30,8 @@ export type HistoryDagNode = {
|
|
30
30
|
/** Facts are being used for conflict detection and history compaction */
|
31
31
|
factsGroup: MutationEventFactsGroup
|
32
32
|
meta?: any
|
33
|
+
clientId: string
|
34
|
+
sessionId: string | undefined
|
33
35
|
}
|
34
36
|
|
35
37
|
export const rootEventNode: HistoryDagNode = {
|
@@ -39,6 +41,8 @@ export const rootEventNode: HistoryDagNode = {
|
|
39
41
|
mutation: '__Root__',
|
40
42
|
args: {},
|
41
43
|
factsGroup: { modifySet: new Map(), modifyUnset: new Map(), depRequire: new Map(), depRead: new Map() },
|
44
|
+
clientId: 'root',
|
45
|
+
sessionId: undefined,
|
42
46
|
}
|
43
47
|
|
44
48
|
export const EMPTY_FACT_VALUE = Symbol('EMPTY_FACT_VALUE')
|
@@ -3,7 +3,7 @@ import { factsToString, validateFacts } from './facts.js'
|
|
3
3
|
import { emptyHistoryDag, type HistoryDagNode, rootParentId } from './history-dag-common.js'
|
4
4
|
|
5
5
|
export const eventIdToString = (eventId: EventId.EventId) =>
|
6
|
-
eventId.
|
6
|
+
eventId.client === 0 ? eventId.global.toString() : `${eventId.global}.${eventId.client}`
|
7
7
|
|
8
8
|
export const historyDagFromNodes = (dagNodes: HistoryDagNode[], options?: { skipFactsCheck: boolean }) => {
|
9
9
|
if (options?.skipFactsCheck !== true) {
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import
|
1
|
+
import * as EventId from '../../schema/EventId.js'
|
2
2
|
import type * as MutationEvent from '../../schema/MutationEvent.js'
|
3
3
|
import type { MutationDef, MutationEventFactsSnapshot } from '../../schema/mutations.js'
|
4
4
|
import {
|
@@ -19,13 +19,13 @@ export type RebaseInput = {
|
|
19
19
|
newRemoteEvents: RebaseEventWithConflict[]
|
20
20
|
pendingLocalEvents: RebaseEventWithConflict[]
|
21
21
|
validate: (args: {
|
22
|
-
rebasedLocalEvents: MutationEvent.
|
22
|
+
rebasedLocalEvents: MutationEvent.PartialAnyDecoded[]
|
23
23
|
mutationDefs: Record<string, MutationDef.Any>
|
24
24
|
}) => FactValidationResult
|
25
25
|
}
|
26
26
|
|
27
27
|
export type RebaseOutput = {
|
28
|
-
rebasedLocalEvents: MutationEvent.
|
28
|
+
rebasedLocalEvents: MutationEvent.PartialAnyDecoded[]
|
29
29
|
}
|
30
30
|
|
31
31
|
export type RebaseFn = (input: RebaseInput) => RebaseOutput
|
@@ -43,12 +43,16 @@ export const rebaseEvents = ({
|
|
43
43
|
pendingLocalEvents,
|
44
44
|
newRemoteEvents,
|
45
45
|
currentFactsSnapshot,
|
46
|
+
clientId,
|
47
|
+
sessionId,
|
46
48
|
}: {
|
47
49
|
pendingLocalEvents: HistoryDagNode[]
|
48
50
|
newRemoteEvents: HistoryDagNode[]
|
49
51
|
rebaseFn: RebaseFn
|
50
52
|
currentFactsSnapshot: MutationEventFactsSnapshot
|
51
|
-
|
53
|
+
clientId: string
|
54
|
+
sessionId: string | undefined
|
55
|
+
}): ReadonlyArray<MutationEvent.AnyDecoded> => {
|
52
56
|
const initialSnapshot = new Map(currentFactsSnapshot)
|
53
57
|
applyFactGroups(
|
54
58
|
newRemoteEvents.map((event) => event.factsGroup),
|
@@ -89,10 +93,12 @@ export const rebaseEvents = ({
|
|
89
93
|
return rebasedLocalEvents.map(
|
90
94
|
(event, index) =>
|
91
95
|
({
|
92
|
-
id: { global: headGlobalId + index + 1,
|
93
|
-
parentId: { global: headGlobalId + index,
|
96
|
+
id: EventId.make({ global: headGlobalId + index + 1, client: EventId.clientDefault }),
|
97
|
+
parentId: EventId.make({ global: headGlobalId + index, client: EventId.clientDefault }),
|
94
98
|
mutation: event.mutation,
|
95
99
|
args: event.args,
|
96
|
-
|
100
|
+
clientId,
|
101
|
+
sessionId,
|
102
|
+
}) satisfies MutationEvent.AnyDecoded,
|
97
103
|
)
|
98
104
|
}
|
@@ -10,7 +10,7 @@ import { toEventNodes } from './mutation-fixtures.js'
|
|
10
10
|
expect.addSnapshotSerializer(customSerializer)
|
11
11
|
|
12
12
|
const compact = (events: any[]) => {
|
13
|
-
const dag = historyDagFromNodes(toEventNodes(events, mutations))
|
13
|
+
const dag = historyDagFromNodes(toEventNodes(events, mutations, 'client-id', 'session-id'))
|
14
14
|
const compacted = compactEvents(dag)
|
15
15
|
|
16
16
|
return Array.from(compacted.dag.nodeEntries())
|
@@ -50,8 +50,8 @@ describe('compactEvents calculator', () => {
|
|
50
50
|
|
51
51
|
expect(expected).toMatchInlineSnapshot(`
|
52
52
|
[
|
53
|
-
{ id: 0, parentId: -1, mutation: "add", args: { value: 1 }, facts: "" }
|
54
|
-
{ id: 1, parentId: 0, mutation: "add", args: { value: 1 }, facts: "" }
|
53
|
+
{ id: 0, parentId: -1, mutation: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
54
|
+
{ id: 1, parentId: 0, mutation: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
55
55
|
]
|
56
56
|
`)
|
57
57
|
})
|
@@ -64,8 +64,8 @@ describe('compactEvents calculator', () => {
|
|
64
64
|
|
65
65
|
expect(expected).toMatchInlineSnapshot(`
|
66
66
|
[
|
67
|
-
{ id: 0, parentId: -1, mutation: "multiply", args: { value: 2 }, facts: "?multiplyByZero -multiplyByZero" }
|
68
|
-
{ id: 1, parentId: 0, mutation: "multiply", args: { value: 2 }, facts: "?multiplyByZero -multiplyByZero" }
|
67
|
+
{ id: 0, parentId: -1, mutation: "multiply", args: { value: 2 }, clientId: "client-id", sessionId: "session-id", facts: "?multiplyByZero -multiplyByZero" }
|
68
|
+
{ id: 1, parentId: 0, mutation: "multiply", args: { value: 2 }, clientId: "client-id", sessionId: "session-id", facts: "?multiplyByZero -multiplyByZero" }
|
69
69
|
]
|
70
70
|
`)
|
71
71
|
})
|
@@ -79,7 +79,7 @@ describe('compactEvents calculator', () => {
|
|
79
79
|
|
80
80
|
expect(expected).toMatchInlineSnapshot(`
|
81
81
|
[
|
82
|
-
{ id: 2, parentId: -1, mutation: "multiply", args: { value: 0 }, facts: "+multiplyByZero" }
|
82
|
+
{ id: 2, parentId: -1, mutation: "multiply", args: { value: 0 }, clientId: "client-id", sessionId: "session-id", facts: "+multiplyByZero" }
|
83
83
|
]
|
84
84
|
`)
|
85
85
|
})
|
@@ -94,8 +94,8 @@ describe('compactEvents calculator', () => {
|
|
94
94
|
|
95
95
|
expect(expected).toMatchInlineSnapshot(`
|
96
96
|
[
|
97
|
-
{ id: 2, parentId: -1, mutation: "multiply", args: { value: 0 }, facts: "+multiplyByZero" }
|
98
|
-
{ id: 3, parentId: 2, mutation: "add", args: { value: 1 }, facts: "" }
|
97
|
+
{ id: 2, parentId: -1, mutation: "multiply", args: { value: 0 }, clientId: "client-id", sessionId: "session-id", facts: "+multiplyByZero" }
|
98
|
+
{ id: 3, parentId: 2, mutation: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
99
99
|
]
|
100
100
|
`)
|
101
101
|
})
|
@@ -111,10 +111,10 @@ describe('compactEvents calculator', () => {
|
|
111
111
|
|
112
112
|
expect(expected).toMatchInlineSnapshot(`
|
113
113
|
[
|
114
|
-
{ id: 0, parentId: -1, mutation: "add", args: { value: 1 }, facts: "" }
|
115
|
-
{ id: 2, parentId: 0, mutation: "multiply", args: { value: 0 }, facts: "+multiplyByZero" }
|
116
|
-
{ id: 3, parentId: 2, mutation: "multiply", args: { value: 2 }, facts: "?multiplyByZero +multiplyByZero -multiplyByZero" }
|
117
|
-
{ id: 4, parentId: 3, mutation: "add", args: { value: 1 }, facts: "" }
|
114
|
+
{ id: 0, parentId: -1, mutation: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
115
|
+
{ id: 2, parentId: 0, mutation: "multiply", args: { value: 0 }, clientId: "client-id", sessionId: "session-id", facts: "+multiplyByZero" }
|
116
|
+
{ id: 3, parentId: 2, mutation: "multiply", args: { value: 2 }, clientId: "client-id", sessionId: "session-id", facts: "?multiplyByZero +multiplyByZero -multiplyByZero" }
|
117
|
+
{ id: 4, parentId: 3, mutation: "add", args: { value: 1 }, clientId: "client-id", sessionId: "session-id", facts: "" }
|
118
118
|
]
|
119
119
|
`)
|
120
120
|
})
|