@livestore/common 0.3.0-dev.12 → 0.3.0-dev.13
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/db-schema/ast/sqlite.d.ts +69 -0
- package/dist/db-schema/ast/sqlite.d.ts.map +1 -0
- package/dist/db-schema/ast/sqlite.js +71 -0
- package/dist/db-schema/ast/sqlite.js.map +1 -0
- package/dist/db-schema/ast/validate.d.ts +3 -0
- package/dist/db-schema/ast/validate.d.ts.map +1 -0
- package/dist/db-schema/ast/validate.js +12 -0
- package/dist/db-schema/ast/validate.js.map +1 -0
- package/dist/db-schema/dsl/field-defs.d.ts +90 -0
- package/dist/db-schema/dsl/field-defs.d.ts.map +1 -0
- package/dist/db-schema/dsl/field-defs.js +87 -0
- package/dist/db-schema/dsl/field-defs.js.map +1 -0
- package/dist/db-schema/dsl/field-defs.test.d.ts +2 -0
- package/dist/db-schema/dsl/field-defs.test.d.ts.map +1 -0
- package/dist/db-schema/dsl/field-defs.test.js +29 -0
- package/dist/db-schema/dsl/field-defs.test.js.map +1 -0
- package/dist/db-schema/dsl/index.d.ts +88 -0
- package/dist/db-schema/dsl/index.d.ts.map +1 -0
- package/dist/db-schema/dsl/index.js +35 -0
- package/dist/db-schema/dsl/index.js.map +1 -0
- package/dist/db-schema/dsl/mod.d.ts +90 -0
- package/dist/db-schema/dsl/mod.d.ts.map +1 -0
- package/dist/db-schema/dsl/mod.js +35 -0
- package/dist/db-schema/dsl/mod.js.map +1 -0
- package/dist/db-schema/dsl/sqlite/field-defs.d.ts +90 -0
- package/dist/db-schema/dsl/sqlite/field-defs.d.ts.map +1 -0
- package/dist/db-schema/dsl/sqlite/field-defs.js +86 -0
- package/dist/db-schema/dsl/sqlite/field-defs.js.map +1 -0
- package/dist/db-schema/dsl/sqlite/field-defs.test.d.ts +2 -0
- package/dist/db-schema/dsl/sqlite/field-defs.test.d.ts.map +1 -0
- package/dist/db-schema/dsl/sqlite/field-defs.test.js +29 -0
- package/dist/db-schema/dsl/sqlite/field-defs.test.js.map +1 -0
- package/dist/db-schema/dsl/sqlite/index.d.ts +88 -0
- package/dist/db-schema/dsl/sqlite/index.d.ts.map +1 -0
- package/dist/db-schema/dsl/sqlite/index.js +35 -0
- package/dist/db-schema/dsl/sqlite/index.js.map +1 -0
- package/dist/db-schema/hash.d.ts +2 -0
- package/dist/db-schema/hash.d.ts.map +1 -0
- package/dist/db-schema/hash.js +14 -0
- package/dist/db-schema/hash.js.map +1 -0
- package/dist/db-schema/index.d.ts +4 -0
- package/dist/db-schema/index.d.ts.map +1 -0
- package/dist/db-schema/index.js +6 -0
- package/dist/db-schema/index.js.map +1 -0
- package/dist/db-schema/mod.d.ts +3 -0
- package/dist/db-schema/mod.d.ts.map +1 -0
- package/dist/db-schema/mod.js +3 -0
- package/dist/db-schema/mod.js.map +1 -0
- package/dist/derived-mutations.d.ts +1 -1
- 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/devtools/devtools-messages-client-session.d.ts +23 -23
- package/dist/devtools/devtools-messages-common.d.ts +6 -6
- package/dist/devtools/devtools-messages-leader.d.ts +41 -53
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +5 -4
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +24 -22
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/apply-mutation.d.ts.map +1 -1
- package/dist/leader-thread/apply-mutation.js +8 -6
- package/dist/leader-thread/apply-mutation.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +6 -12
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +6 -1
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +1 -1
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +7 -5
- package/dist/leader-thread/mutationlog.js.map +1 -1
- package/dist/leader-thread/pull-queue-set.d.ts.map +1 -1
- package/dist/leader-thread/types.d.ts +7 -3
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +1 -1
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/query-builder/api.d.ts +1 -1
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js +8 -6
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +9 -9
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +12 -12
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/EventId.test.js +3 -3
- package/dist/schema/EventId.test.js.map +1 -1
- package/dist/schema/MutationEvent.d.ts +37 -12
- package/dist/schema/MutationEvent.d.ts.map +1 -1
- package/dist/schema/MutationEvent.js +20 -4
- 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 +5 -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.js +1 -1
- package/dist/schema/schema-helpers.js.map +1 -1
- package/dist/schema/schema.d.ts +1 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +1 -1
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/system-tables.d.ts +47 -29
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +10 -7
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +18 -14
- 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/migrations.d.ts +1 -1
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +1 -1
- package/dist/schema-management/migrations.js.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/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +18 -3
- package/dist/sync/ClientSessionSyncProcessor.js.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 +2 -0
- 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 +3 -1
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -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 +11 -11
- package/dist/sync/next/test/mutation-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.js +12 -10
- package/dist/sync/next/test/mutation-fixtures.js.map +1 -1
- package/dist/sync/sync.d.ts +2 -2
- package/dist/sync/syncstate.d.ts +9 -9
- package/dist/sync/syncstate.js +6 -6
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +18 -16
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -3
- package/src/derived-mutations.ts +4 -4
- package/src/devtools/devtools-messages-leader.ts +5 -4
- package/src/index.ts +1 -1
- package/src/leader-thread/LeaderSyncProcessor.ts +28 -22
- package/src/leader-thread/apply-mutation.ts +15 -5
- package/src/leader-thread/leader-worker-devtools.ts +6 -13
- package/src/leader-thread/make-leader-thread-layer.ts +9 -1
- package/src/leader-thread/mutationlog.ts +8 -6
- package/src/leader-thread/types.ts +6 -2
- package/src/query-builder/api.ts +1 -1
- package/src/rehydrate-from-mutationlog.ts +8 -6
- package/src/schema/EventId.test.ts +3 -3
- package/src/schema/EventId.ts +17 -17
- package/src/schema/MutationEvent.ts +31 -6
- 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 +6 -19
- package/src/schema/schema-helpers.ts +1 -1
- package/src/schema/schema.ts +2 -2
- package/src/schema/system-tables.ts +10 -7
- package/src/schema/table-def.ts +17 -16
- package/src/schema-management/migrations.ts +1 -1
- 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 +23 -4
- 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 +8 -2
- 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 -12
- package/src/sync/syncstate.test.ts +19 -17
- package/src/sync/syncstate.ts +6 -6
- package/src/version.ts +1 -1
- package/tsconfig.json +1 -1
@@ -225,7 +225,15 @@ const bootLeaderThread = ({
|
|
225
225
|
yield* Deferred.succeed(dbReady, void 0)
|
226
226
|
|
227
227
|
if (initialBlockingSyncContext.blockingDeferred !== undefined) {
|
228
|
-
|
228
|
+
// Provides a syncing status right away before the first pull response comes in
|
229
|
+
yield* Queue.offer(bootStatusQueue, {
|
230
|
+
stage: 'syncing',
|
231
|
+
progress: { done: 0, total: -1 },
|
232
|
+
})
|
233
|
+
|
234
|
+
yield* initialBlockingSyncContext.blockingDeferred.pipe(
|
235
|
+
Effect.withSpan('@livestore/common:leader-thread:initial-sync-blocking'),
|
236
|
+
)
|
229
237
|
}
|
230
238
|
|
231
239
|
yield* Queue.offer(bootStatusQueue, { stage: 'done' })
|
@@ -23,18 +23,20 @@ export const getMutationEventsSince = (
|
|
23
23
|
.map((_) => ({
|
24
24
|
mutation: _.mutation,
|
25
25
|
args: _.argsJson,
|
26
|
-
id: { global: _.idGlobal,
|
27
|
-
parentId: { global: _.parentIdGlobal,
|
26
|
+
id: { global: _.idGlobal, client: _.idClient },
|
27
|
+
parentId: { global: _.parentIdGlobal, client: _.parentIdClient },
|
28
|
+
clientId: _.clientId,
|
29
|
+
sessionId: _.sessionId ?? undefined,
|
28
30
|
}))
|
29
31
|
.filter((_) => EventId.compare(_.id, since) > 0)
|
30
32
|
})
|
31
33
|
|
32
|
-
export const
|
33
|
-
const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId;
|
34
|
-
sql`select idGlobal,
|
34
|
+
export const getClientHeadFromDb = (dbMutationLog: SqliteDb): EventId.EventId => {
|
35
|
+
const res = dbMutationLog.select<{ idGlobal: EventId.GlobalEventId; idClient: EventId.ClientEventId }>(
|
36
|
+
sql`select idGlobal, idClient from ${MUTATION_LOG_META_TABLE} order by idGlobal DESC, idClient DESC limit 1`,
|
35
37
|
)[0]
|
36
38
|
|
37
|
-
return res ? { global: res.idGlobal,
|
39
|
+
return res ? { global: res.idGlobal, client: res.idClient } : EventId.ROOT
|
38
40
|
}
|
39
41
|
|
40
42
|
export const getBackendHeadFromDb = (dbMutationLog: SqliteDb): EventId.GlobalEventId =>
|
@@ -32,7 +32,7 @@ export const InitialSyncOptionsSkip = Schema.TaggedStruct('Skip', {})
|
|
32
32
|
export type InitialSyncOptionsSkip = typeof InitialSyncOptionsSkip.Type
|
33
33
|
|
34
34
|
export const InitialSyncOptionsBlocking = Schema.TaggedStruct('Blocking', {
|
35
|
-
timeout: Schema.DurationFromMillis,
|
35
|
+
timeout: Schema.Union(Schema.DurationFromMillis, Schema.Number),
|
36
36
|
})
|
37
37
|
|
38
38
|
export type InitialSyncOptionsBlocking = typeof InitialSyncOptionsBlocking.Type
|
@@ -134,7 +134,11 @@ export interface LeaderSyncProcessor {
|
|
134
134
|
},
|
135
135
|
) => Effect.Effect<void, InvalidPushError>
|
136
136
|
|
137
|
-
pushPartial: (
|
137
|
+
pushPartial: (args: {
|
138
|
+
mutationEvent: MutationEvent.PartialAnyEncoded
|
139
|
+
clientId: string
|
140
|
+
sessionId: string | undefined
|
141
|
+
}) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
|
138
142
|
boot: (args: {
|
139
143
|
dbReady: Deferred.Deferred<void>
|
140
144
|
}) => Effect.Effect<
|
package/src/query-builder/api.ts
CHANGED
@@ -3,8 +3,8 @@ import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
|
|
3
3
|
|
4
4
|
import type { SessionIdSymbol } from '../adapter-types.js'
|
5
5
|
import type { QueryInfo } from '../query-info.js'
|
6
|
+
import type { SqliteDsl } from '../schema/db-schema/mod.js'
|
6
7
|
import type { DbSchema } from '../schema/mod.js'
|
7
|
-
import type { SqliteDsl } from '../schema/table-def.js'
|
8
8
|
import type { SqlValue } from '../util.js'
|
9
9
|
|
10
10
|
export type QueryBuilderAst = QueryBuilderAst.SelectQuery | QueryBuilderAst.CountQuery | QueryBuilderAst.RowQuery
|
@@ -60,10 +60,12 @@ This likely means the schema has changed in an incompatible way.
|
|
60
60
|
)
|
61
61
|
|
62
62
|
const mutationEventEncoded = {
|
63
|
-
id: { global: row.idGlobal,
|
64
|
-
parentId: { global: row.parentIdGlobal,
|
63
|
+
id: { global: row.idGlobal, client: row.idClient },
|
64
|
+
parentId: { global: row.parentIdGlobal, client: row.parentIdClient },
|
65
65
|
mutation: row.mutation,
|
66
66
|
args,
|
67
|
+
clientId: row.clientId,
|
68
|
+
sessionId: row.sessionId ?? undefined,
|
67
69
|
} satisfies MutationEvent.AnyEncoded
|
68
70
|
|
69
71
|
yield* applyMutation(mutationEventEncoded, { skipMutationLog: true })
|
@@ -73,8 +75,8 @@ This likely means the schema has changed in an incompatible way.
|
|
73
75
|
|
74
76
|
const stmt = logDb.prepare(sql`\
|
75
77
|
SELECT * FROM ${MUTATION_LOG_META_TABLE}
|
76
|
-
WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND
|
77
|
-
ORDER BY idGlobal ASC,
|
78
|
+
WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND idClient > $idClient)
|
79
|
+
ORDER BY idGlobal ASC, idClient ASC
|
78
80
|
LIMIT ${CHUNK_SIZE}
|
79
81
|
`)
|
80
82
|
|
@@ -88,14 +90,14 @@ LIMIT ${CHUNK_SIZE}
|
|
88
90
|
|
89
91
|
const lastId = Chunk.isChunk(item)
|
90
92
|
? Chunk.last(item).pipe(
|
91
|
-
Option.map((_) => ({ global: _.idGlobal,
|
93
|
+
Option.map((_) => ({ global: _.idGlobal, client: _.idClient })),
|
92
94
|
Option.getOrElse(() => EventId.ROOT),
|
93
95
|
)
|
94
96
|
: EventId.ROOT
|
95
97
|
const nextItem = Chunk.fromIterable(
|
96
98
|
stmt.select<MutationLogMetaRow>({
|
97
99
|
$idGlobal: lastId?.global,
|
98
|
-
$
|
100
|
+
$idClient: lastId?.client,
|
99
101
|
} as any as PreparedBindValues),
|
100
102
|
)
|
101
103
|
const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
|
@@ -5,8 +5,8 @@ import { EventId } from './mod.js'
|
|
5
5
|
|
6
6
|
Vitest.describe('EventId', () => {
|
7
7
|
Vitest.test('nextPair', () => {
|
8
|
-
const e_0_0 = EventId.make({ global: 0,
|
9
|
-
expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1,
|
10
|
-
expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0,
|
8
|
+
const e_0_0 = EventId.make({ global: 0, client: 0 })
|
9
|
+
expect(EventId.nextPair(e_0_0, false).id).toStrictEqual({ global: 1, client: 0 })
|
10
|
+
expect(EventId.nextPair(e_0_0, true).id).toStrictEqual({ global: 0, client: 1 })
|
11
11
|
})
|
12
12
|
})
|
package/src/schema/EventId.ts
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
import { Brand, Schema } from '@livestore/utils/effect'
|
2
2
|
|
3
|
-
export type
|
4
|
-
export const localEventId = Brand.nominal<
|
5
|
-
export const
|
3
|
+
export type ClientEventId = Brand.Branded<number, 'ClientEventId'>
|
4
|
+
export const localEventId = Brand.nominal<ClientEventId>()
|
5
|
+
export const ClientEventId = Schema.fromBrand(localEventId)(Schema.Int)
|
6
6
|
|
7
7
|
export type GlobalEventId = Brand.Branded<number, 'GlobalEventId'>
|
8
8
|
export const globalEventId = Brand.nominal<GlobalEventId>()
|
9
9
|
export const GlobalEventId = Schema.fromBrand(globalEventId)(Schema.Int)
|
10
10
|
|
11
|
-
export const
|
11
|
+
export const clientDefault = 0 as any as ClientEventId
|
12
12
|
|
13
13
|
/**
|
14
14
|
* LiveStore event id value consisting of a globally unique event sequence number
|
15
|
-
* and a
|
15
|
+
* and a client sequence number.
|
16
16
|
*
|
17
|
-
* The
|
17
|
+
* The client sequence number is only used for clientOnly mutations and starts from 0 for each global sequence number.
|
18
18
|
*/
|
19
|
-
export type EventId = { global: GlobalEventId;
|
19
|
+
export type EventId = { global: GlobalEventId; client: ClientEventId }
|
20
20
|
|
21
21
|
export const EventId = Schema.Struct({
|
22
22
|
global: GlobalEventId,
|
23
|
-
|
23
|
+
client: ClientEventId,
|
24
24
|
}).annotations({ title: 'LiveStore.EventId' })
|
25
25
|
|
26
26
|
/**
|
@@ -30,21 +30,21 @@ export const compare = (a: EventId, b: EventId) => {
|
|
30
30
|
if (a.global !== b.global) {
|
31
31
|
return a.global - b.global
|
32
32
|
}
|
33
|
-
return a.
|
33
|
+
return a.client - b.client
|
34
34
|
}
|
35
35
|
|
36
|
-
export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.
|
36
|
+
export const isEqual = (a: EventId, b: EventId) => a.global === b.global && a.client === b.client
|
37
37
|
|
38
38
|
export type EventIdPair = { id: EventId; parentId: EventId }
|
39
39
|
|
40
|
-
export const ROOT = { global: -1 as any as GlobalEventId,
|
40
|
+
export const ROOT = { global: -1 as any as GlobalEventId, client: clientDefault } satisfies EventId
|
41
41
|
|
42
42
|
export const isGreaterThan = (a: EventId, b: EventId) => {
|
43
|
-
return a.global > b.global || (a.global === b.global && a.
|
43
|
+
return a.global > b.global || (a.global === b.global && a.client > b.client)
|
44
44
|
}
|
45
45
|
|
46
46
|
export const isGreaterThanOrEqual = (a: EventId, b: EventId) => {
|
47
|
-
return a.global > b.global || (a.global === b.global && a.
|
47
|
+
return a.global > b.global || (a.global === b.global && a.client >= b.client)
|
48
48
|
}
|
49
49
|
|
50
50
|
export const make = (id: EventId | typeof EventId.Encoded): EventId => {
|
@@ -53,12 +53,12 @@ export const make = (id: EventId | typeof EventId.Encoded): EventId => {
|
|
53
53
|
|
54
54
|
export const nextPair = (id: EventId, isLocal: boolean): EventIdPair => {
|
55
55
|
if (isLocal) {
|
56
|
-
return { id: { global: id.global,
|
56
|
+
return { id: { global: id.global, client: (id.client + 1) as any as ClientEventId }, parentId: id }
|
57
57
|
}
|
58
58
|
|
59
59
|
return {
|
60
|
-
id: { global: (id.global + 1) as any as GlobalEventId,
|
61
|
-
// NOTE we always point to `
|
62
|
-
parentId: { global: id.global,
|
60
|
+
id: { global: (id.global + 1) as any as GlobalEventId, client: clientDefault },
|
61
|
+
// NOTE we always point to `client: 0` for non-clientOnly mutations
|
62
|
+
parentId: { global: id.global, client: clientDefault },
|
63
63
|
}
|
64
64
|
}
|
@@ -10,7 +10,7 @@ export type MutationEventPartial<TMutationsDef extends MutationDef.Any> = {
|
|
10
10
|
args: Schema.Schema.Type<TMutationsDef['schema']>
|
11
11
|
}
|
12
12
|
|
13
|
-
export type
|
13
|
+
export type PartialEncoded<TMutationsDef extends MutationDef.Any> = {
|
14
14
|
mutation: TMutationsDef['name']
|
15
15
|
args: Schema.Schema.Encoded<TMutationsDef['schema']>
|
16
16
|
}
|
@@ -20,6 +20,8 @@ export type MutationEvent<TMutationsDef extends MutationDef.Any> = {
|
|
20
20
|
args: Schema.Schema.Type<TMutationsDef['schema']>
|
21
21
|
id: EventId.EventId
|
22
22
|
parentId: EventId.EventId
|
23
|
+
clientId: string
|
24
|
+
sessionId: string | undefined
|
23
25
|
}
|
24
26
|
|
25
27
|
export type MutationEventEncoded<TMutationsDef extends MutationDef.Any> = {
|
@@ -27,6 +29,8 @@ export type MutationEventEncoded<TMutationsDef extends MutationDef.Any> = {
|
|
27
29
|
args: Schema.Schema.Encoded<TMutationsDef['schema']>
|
28
30
|
id: EventId.EventId
|
29
31
|
parentId: EventId.EventId
|
32
|
+
clientId: string
|
33
|
+
sessionId: string | undefined
|
30
34
|
}
|
31
35
|
|
32
36
|
export type AnyDecoded = MutationEvent<MutationDef.Any>
|
@@ -35,6 +39,8 @@ export const AnyDecoded = Schema.Struct({
|
|
35
39
|
args: Schema.Any,
|
36
40
|
id: EventId.EventId,
|
37
41
|
parentId: EventId.EventId,
|
42
|
+
clientId: Schema.String,
|
43
|
+
sessionId: Schema.UndefinedOr(Schema.String),
|
38
44
|
}).annotations({ title: 'MutationEvent.AnyDecoded' })
|
39
45
|
|
40
46
|
export type AnyEncoded = MutationEventEncoded<MutationDef.Any>
|
@@ -43,6 +49,8 @@ export const AnyEncoded = Schema.Struct({
|
|
43
49
|
args: Schema.Any,
|
44
50
|
id: EventId.EventId,
|
45
51
|
parentId: EventId.EventId,
|
52
|
+
clientId: Schema.String,
|
53
|
+
sessionId: Schema.UndefinedOr(Schema.String),
|
46
54
|
}).annotations({ title: 'MutationEvent.AnyEncoded' })
|
47
55
|
|
48
56
|
export const AnyEncodedGlobal = Schema.Struct({
|
@@ -50,11 +58,17 @@ export const AnyEncodedGlobal = Schema.Struct({
|
|
50
58
|
args: Schema.Any,
|
51
59
|
id: EventId.GlobalEventId,
|
52
60
|
parentId: EventId.GlobalEventId,
|
61
|
+
clientId: Schema.String,
|
53
62
|
}).annotations({ title: 'MutationEvent.AnyEncodedGlobal' })
|
54
63
|
export type AnyEncodedGlobal = typeof AnyEncodedGlobal.Type
|
55
64
|
|
56
65
|
export type PartialAnyDecoded = MutationEventPartial<MutationDef.Any>
|
57
|
-
export type PartialAnyEncoded =
|
66
|
+
export type PartialAnyEncoded = PartialEncoded<MutationDef.Any>
|
67
|
+
|
68
|
+
export const PartialAnyEncoded = Schema.Struct({
|
69
|
+
mutation: Schema.String,
|
70
|
+
args: Schema.Any,
|
71
|
+
})
|
58
72
|
|
59
73
|
export type PartialForSchema<TSchema extends LiveStoreSchema> = {
|
60
74
|
[K in keyof TSchema['_MutationDefMapType']]: MutationEventPartial<TSchema['_MutationDefMapType'][K]>
|
@@ -75,6 +89,8 @@ export type ForMutationDefRecord<TMutationsDefRecord extends MutationDefRecord>
|
|
75
89
|
args: Schema.Schema.Type<TMutationsDefRecord[K]['schema']>
|
76
90
|
id: EventId.EventId
|
77
91
|
parentId: EventId.EventId
|
92
|
+
clientId: string
|
93
|
+
sessionId: string | undefined
|
78
94
|
}
|
79
95
|
}[keyof TMutationsDefRecord],
|
80
96
|
{
|
@@ -83,6 +99,8 @@ export type ForMutationDefRecord<TMutationsDefRecord extends MutationDefRecord>
|
|
83
99
|
args: Schema.Schema.Encoded<TMutationsDefRecord[K]['schema']>
|
84
100
|
id: EventId.EventId
|
85
101
|
parentId: EventId.EventId
|
102
|
+
clientId: string
|
103
|
+
sessionId: string | undefined
|
86
104
|
}
|
87
105
|
}[keyof TMutationsDefRecord]
|
88
106
|
>
|
@@ -112,6 +130,8 @@ export const makeMutationEventSchema = <TSchema extends LiveStoreSchema>(
|
|
112
130
|
args: def.schema,
|
113
131
|
id: EventId.EventId,
|
114
132
|
parentId: EventId.EventId,
|
133
|
+
clientId: Schema.String,
|
134
|
+
sessionId: Schema.UndefinedOr(Schema.String),
|
115
135
|
}),
|
116
136
|
),
|
117
137
|
).annotations({ title: 'MutationEvent' }) as any
|
@@ -136,6 +156,8 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
|
|
136
156
|
args: Schema.Any,
|
137
157
|
id: EventId.EventId,
|
138
158
|
parentId: EventId.EventId,
|
159
|
+
clientId: Schema.String,
|
160
|
+
sessionId: Schema.UndefinedOr(Schema.String),
|
139
161
|
// TODO get rid of `meta` again by cleaning up the usage implementations
|
140
162
|
meta: Schema.optionalWith(
|
141
163
|
Schema.Any as Schema.Schema<{
|
@@ -149,7 +171,7 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
|
|
149
171
|
// - More readable way to print the id + parentId
|
150
172
|
// - not including `meta`
|
151
173
|
return {
|
152
|
-
id: `(${this.id.global},${this.id.
|
174
|
+
id: `(${this.id.global},${this.id.client}) → (${this.parentId.global},${this.parentId.client})`,
|
153
175
|
mutation: this.mutation,
|
154
176
|
args: this.args,
|
155
177
|
}
|
@@ -164,8 +186,9 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
|
|
164
186
|
static fromGlobal = (mutationEvent: AnyEncodedGlobal) =>
|
165
187
|
new EncodedWithMeta({
|
166
188
|
...mutationEvent,
|
167
|
-
id: { global: mutationEvent.id,
|
168
|
-
parentId: { global: mutationEvent.parentId,
|
189
|
+
id: { global: mutationEvent.id, client: EventId.clientDefault },
|
190
|
+
parentId: { global: mutationEvent.parentId, client: EventId.clientDefault },
|
191
|
+
sessionId: undefined,
|
169
192
|
})
|
170
193
|
|
171
194
|
toGlobal = (): AnyEncodedGlobal => ({
|
@@ -177,7 +200,9 @@ export class EncodedWithMeta extends Schema.Class<EncodedWithMeta>('MutationEven
|
|
177
200
|
|
178
201
|
export const isEqualEncoded = (a: AnyEncoded, b: AnyEncoded) =>
|
179
202
|
a.id.global === b.id.global &&
|
180
|
-
a.id.
|
203
|
+
a.id.client === b.id.client &&
|
181
204
|
a.mutation === b.mutation &&
|
205
|
+
a.clientId === b.clientId &&
|
206
|
+
// a.sessionId === b.sessionId &&
|
182
207
|
// TODO use schema equality here
|
183
208
|
JSON.stringify(a.args) === JSON.stringify(b.args)
|
@@ -0,0 +1,142 @@
|
|
1
|
+
import { type Option, Schema } from '@livestore/utils/effect'
|
2
|
+
|
3
|
+
import { hashCode } from '../hash.js'
|
4
|
+
|
5
|
+
export namespace ColumnType {
|
6
|
+
export type ColumnType = Text | Null | Real | Integer | Blob
|
7
|
+
|
8
|
+
export type Text = { _tag: 'text' }
|
9
|
+
|
10
|
+
export type Null = { _tag: 'null' }
|
11
|
+
|
12
|
+
export type Real = { _tag: 'real' }
|
13
|
+
|
14
|
+
export type Integer = { _tag: 'integer' }
|
15
|
+
|
16
|
+
export type Blob = { _tag: 'blob' }
|
17
|
+
}
|
18
|
+
|
19
|
+
export type Column = {
|
20
|
+
_tag: 'column'
|
21
|
+
name: string
|
22
|
+
type: ColumnType.ColumnType
|
23
|
+
primaryKey: boolean
|
24
|
+
nullable: boolean
|
25
|
+
default: Option.Option<any>
|
26
|
+
schema: Schema.Schema<any>
|
27
|
+
}
|
28
|
+
|
29
|
+
export const column = (props: Omit<Column, '_tag'>): Column => ({ _tag: 'column', ...props })
|
30
|
+
|
31
|
+
export type Index = {
|
32
|
+
_tag: 'index'
|
33
|
+
columns: ReadonlyArray<string>
|
34
|
+
name?: string
|
35
|
+
unique?: boolean
|
36
|
+
primaryKey?: boolean
|
37
|
+
}
|
38
|
+
|
39
|
+
export const index = (
|
40
|
+
columns: ReadonlyArray<string>,
|
41
|
+
name?: string,
|
42
|
+
unique?: boolean,
|
43
|
+
primaryKey?: boolean,
|
44
|
+
): Index => ({
|
45
|
+
_tag: 'index',
|
46
|
+
columns,
|
47
|
+
name,
|
48
|
+
unique,
|
49
|
+
primaryKey,
|
50
|
+
})
|
51
|
+
|
52
|
+
export type ForeignKey = {
|
53
|
+
_tag: 'foreignKey'
|
54
|
+
references: {
|
55
|
+
table: string
|
56
|
+
columns: ReadonlyArray<string>
|
57
|
+
}
|
58
|
+
key: {
|
59
|
+
table: string
|
60
|
+
columns: ReadonlyArray<string>
|
61
|
+
}
|
62
|
+
columns: ReadonlyArray<string>
|
63
|
+
}
|
64
|
+
|
65
|
+
export type Table = {
|
66
|
+
_tag: 'table'
|
67
|
+
name: string
|
68
|
+
columns: ReadonlyArray<Column>
|
69
|
+
indexes: ReadonlyArray<Index>
|
70
|
+
}
|
71
|
+
|
72
|
+
export const table = (name: string, columns: ReadonlyArray<Column>, indexes: ReadonlyArray<Index>): Table => ({
|
73
|
+
_tag: 'table',
|
74
|
+
name,
|
75
|
+
columns,
|
76
|
+
indexes,
|
77
|
+
})
|
78
|
+
|
79
|
+
export type DbSchema = {
|
80
|
+
_tag: 'dbSchema'
|
81
|
+
tables: Table[]
|
82
|
+
}
|
83
|
+
|
84
|
+
export const dbSchema = (tables: Table[]): DbSchema => ({ _tag: 'dbSchema', tables })
|
85
|
+
|
86
|
+
/**
|
87
|
+
* NOTE we're only including SQLite-relevant information in the hash (which excludes the schema mapping)
|
88
|
+
*/
|
89
|
+
export const hash = (obj: Table | Column | Index | ForeignKey | DbSchema): number =>
|
90
|
+
hashCode(JSON.stringify(trimInfoForHasing(obj)))
|
91
|
+
|
92
|
+
const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema): Record<string, any> => {
|
93
|
+
switch (obj._tag) {
|
94
|
+
case 'table': {
|
95
|
+
return {
|
96
|
+
_tag: 'table',
|
97
|
+
name: obj.name,
|
98
|
+
columns: obj.columns.map((column) => trimInfoForHasing(column)),
|
99
|
+
indexes: obj.indexes.map((index) => trimInfoForHasing(index)),
|
100
|
+
}
|
101
|
+
}
|
102
|
+
case 'column': {
|
103
|
+
return {
|
104
|
+
_tag: 'column',
|
105
|
+
name: obj.name,
|
106
|
+
type: obj.type._tag,
|
107
|
+
primaryKey: obj.primaryKey,
|
108
|
+
nullable: obj.nullable,
|
109
|
+
default: obj.default,
|
110
|
+
}
|
111
|
+
}
|
112
|
+
case 'index': {
|
113
|
+
return {
|
114
|
+
_tag: 'index',
|
115
|
+
columns: obj.columns,
|
116
|
+
name: obj.name,
|
117
|
+
unique: obj.unique,
|
118
|
+
primaryKey: obj.primaryKey,
|
119
|
+
}
|
120
|
+
}
|
121
|
+
case 'foreignKey': {
|
122
|
+
return {
|
123
|
+
_tag: 'foreignKey',
|
124
|
+
references: obj.references,
|
125
|
+
key: obj.key,
|
126
|
+
columns: obj.columns,
|
127
|
+
}
|
128
|
+
}
|
129
|
+
case 'dbSchema': {
|
130
|
+
return {
|
131
|
+
_tag: 'dbSchema',
|
132
|
+
tables: obj.tables.map(trimInfoForHasing),
|
133
|
+
}
|
134
|
+
}
|
135
|
+
default: {
|
136
|
+
throw new Error(`Unreachable: ${obj}`)
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
export const structSchemaForTable = (tableDef: Table) =>
|
142
|
+
Schema.Struct(Object.fromEntries(tableDef.columns.map((column) => [column.name, column.schema])))
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import type { DbSchema } from './sqlite.js'
|
2
|
+
|
3
|
+
// TODO
|
4
|
+
export const validate = (_dbSchema: DbSchema) => {
|
5
|
+
/*
|
6
|
+
TODO:
|
7
|
+
|
8
|
+
- ensure no duplicate table names
|
9
|
+
- ensure no duplicate column names within a table
|
10
|
+
- ensure no duplicate index names globally
|
11
|
+
- ...
|
12
|
+
*/
|
13
|
+
}
|