@livestore/common 0.3.0-dev.10 → 0.3.0-dev.12
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/adapter-types.d.ts +62 -30
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +12 -0
- package/dist/adapter-types.js.map +1 -1
- package/dist/devtools/devtool-message-leader.d.ts +2 -0
- package/dist/devtools/devtool-message-leader.d.ts.map +1 -0
- package/dist/devtools/devtool-message-leader.js +2 -0
- package/dist/devtools/devtool-message-leader.js.map +1 -0
- package/dist/devtools/devtools-bridge.d.ts +10 -7
- package/dist/devtools/devtools-bridge.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +370 -0
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-client-session.js +77 -0
- package/dist/devtools/devtools-messages-client-session.js.map +1 -0
- package/dist/devtools/devtools-messages-common.d.ts +57 -0
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-common.js +44 -0
- package/dist/devtools/devtools-messages-common.js.map +1 -0
- package/dist/devtools/devtools-messages-leader.d.ts +437 -0
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-leader.js +132 -0
- package/dist/devtools/devtools-messages-leader.js.map +1 -0
- package/dist/devtools/devtools-messages.d.ts +3 -580
- package/dist/devtools/devtools-messages.d.ts.map +1 -1
- package/dist/devtools/devtools-messages.js +3 -174
- package/dist/devtools/devtools-messages.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 +4 -4
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +64 -36
- 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 +4 -4
- 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.js +67 -36
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -6
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +38 -13
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mutationlog.d.ts +4 -4
- package/dist/leader-thread/mutationlog.d.ts.map +1 -1
- package/dist/leader-thread/mutationlog.js +6 -6
- 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/recreate-db.d.ts +4 -2
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +27 -22
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/types.d.ts +32 -17
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +0 -2
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/query-builder/api.d.ts +2 -2
- package/dist/query-builder/api.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 +3 -3
- package/dist/rehydrate-from-mutationlog.d.ts.map +1 -1
- package/dist/rehydrate-from-mutationlog.js.map +1 -1
- package/dist/schema/EventId.d.ts +1 -0
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +3 -0
- package/dist/schema/EventId.js.map +1 -1
- package/dist/schema/mutations.d.ts +1 -1
- package/dist/schema/system-tables.d.ts +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 +5 -5
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +6 -1
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +8 -12
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +31 -13
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/next/test/mutation-fixtures.d.ts +7 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/src/adapter-types.ts +52 -33
- package/src/devtools/devtools-bridge.ts +10 -7
- package/src/devtools/devtools-messages-client-session.ts +125 -0
- package/src/devtools/devtools-messages-common.ts +81 -0
- package/src/devtools/devtools-messages-leader.ts +176 -0
- package/src/devtools/devtools-messages.ts +3 -246
- package/src/init-singleton-tables.ts +2 -2
- package/src/leader-thread/LeaderSyncProcessor.ts +94 -46
- package/src/leader-thread/apply-mutation.ts +5 -5
- package/src/leader-thread/connection.ts +54 -9
- package/src/leader-thread/leader-worker-devtools.ts +105 -41
- package/src/leader-thread/make-leader-thread-layer.ts +55 -22
- package/src/leader-thread/mutationlog.ts +9 -9
- package/src/leader-thread/recreate-db.ts +33 -24
- package/src/leader-thread/types.ts +38 -21
- package/src/query-builder/api.ts +3 -3
- 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 +3 -3
- package/src/schema/EventId.ts +4 -0
- package/src/schema-management/common.ts +3 -3
- package/src/schema-management/migrations.ts +12 -8
- package/src/sync/ClientSessionSyncProcessor.ts +38 -22
- package/src/version.ts +1 -1
@@ -1,7 +1,6 @@
|
|
1
1
|
import type {
|
2
2
|
Deferred,
|
3
3
|
Effect,
|
4
|
-
Fiber,
|
5
4
|
HttpClient,
|
6
5
|
Option,
|
7
6
|
Queue,
|
@@ -16,10 +15,11 @@ import type {
|
|
16
15
|
BootStatus,
|
17
16
|
Devtools,
|
18
17
|
InvalidPushError,
|
19
|
-
|
18
|
+
MakeSqliteDb,
|
19
|
+
MigrationsReport,
|
20
20
|
PersistenceInfo,
|
21
|
+
SqliteDb,
|
21
22
|
SyncBackend,
|
22
|
-
SynchronousDatabase,
|
23
23
|
UnexpectedError,
|
24
24
|
} from '../index.js'
|
25
25
|
import type { EventId, LiveStoreSchema, MutationEvent } from '../schema/mod.js'
|
@@ -28,13 +28,6 @@ import type { ShutdownChannel } from './shutdown-channel.js'
|
|
28
28
|
|
29
29
|
export type ShutdownState = 'running' | 'shutting-down'
|
30
30
|
|
31
|
-
export class OuterWorkerCtx extends Context.Tag('OuterWorkerCtx')<
|
32
|
-
OuterWorkerCtx,
|
33
|
-
{
|
34
|
-
innerFiber: Fiber.RuntimeFiber<any, any>
|
35
|
-
}
|
36
|
-
>() {}
|
37
|
-
|
38
31
|
export const InitialSyncOptionsSkip = Schema.TaggedStruct('Skip', {})
|
39
32
|
export type InitialSyncOptionsSkip = typeof InitialSyncOptionsSkip.Type
|
40
33
|
|
@@ -56,8 +49,8 @@ export type InitialSyncInfo = Option.Option<{
|
|
56
49
|
// | { _tag: 'Recreate'; snapshotRef: Ref.Ref<Uint8Array | undefined>; syncInfo: InitialSyncInfo }
|
57
50
|
// | { _tag: 'Reuse'; syncInfo: InitialSyncInfo }
|
58
51
|
|
59
|
-
export type
|
60
|
-
export type PersistenceInfoPair = {
|
52
|
+
export type LeaderSqliteDb = SqliteDb<{ dbPointer: number; persistenceInfo: PersistenceInfo }>
|
53
|
+
export type PersistenceInfoPair = { readModel: PersistenceInfo; mutationLog: PersistenceInfo }
|
61
54
|
|
62
55
|
export type DevtoolsOptions =
|
63
56
|
| {
|
@@ -65,9 +58,9 @@ export type DevtoolsOptions =
|
|
65
58
|
}
|
66
59
|
| {
|
67
60
|
enabled: true
|
68
|
-
|
61
|
+
makeBootContext: Effect.Effect<
|
69
62
|
{
|
70
|
-
devtoolsWebChannel: WebChannel.WebChannel<Devtools.
|
63
|
+
devtoolsWebChannel: WebChannel.WebChannel<Devtools.Leader.MessageToApp, Devtools.Leader.MessageFromApp>
|
71
64
|
persistenceInfo: PersistenceInfoPair
|
72
65
|
},
|
73
66
|
UnexpectedError,
|
@@ -75,26 +68,46 @@ export type DevtoolsOptions =
|
|
75
68
|
>
|
76
69
|
}
|
77
70
|
|
71
|
+
export type DevtoolsContext =
|
72
|
+
| {
|
73
|
+
enabled: true
|
74
|
+
// syncBackendPullLatch: Effect.Latch
|
75
|
+
// syncBackendPushLatch: Effect.Latch
|
76
|
+
syncBackendLatch: Effect.Latch
|
77
|
+
syncBackendLatchState: SubscriptionRef.SubscriptionRef<{ latchClosed: boolean }>
|
78
|
+
}
|
79
|
+
| {
|
80
|
+
enabled: false
|
81
|
+
}
|
82
|
+
|
78
83
|
export class LeaderThreadCtx extends Context.Tag('LeaderThreadCtx')<
|
79
84
|
LeaderThreadCtx,
|
80
85
|
{
|
81
86
|
schema: LiveStoreSchema
|
82
87
|
storeId: string
|
83
88
|
clientId: string
|
84
|
-
|
85
|
-
|
86
|
-
|
89
|
+
makeSqliteDb: MakeSqliteDb
|
90
|
+
dbReadModel: LeaderSqliteDb
|
91
|
+
dbMutationLog: LeaderSqliteDb
|
87
92
|
bootStatusQueue: Queue.Queue<BootStatus>
|
88
93
|
// TODO we should find a more elegant way to handle cases which need this ref for their implementation
|
89
94
|
shutdownStateSubRef: SubscriptionRef.SubscriptionRef<ShutdownState>
|
90
95
|
shutdownChannel: ShutdownChannel
|
91
96
|
mutationEventSchema: MutationEvent.ForMutationDefRecord<any>
|
92
|
-
|
97
|
+
devtools: DevtoolsContext
|
93
98
|
syncBackend: SyncBackend | undefined
|
94
99
|
syncProcessor: LeaderSyncProcessor
|
95
100
|
connectedClientSessionPullQueues: PullQueueSet
|
96
|
-
|
97
|
-
|
101
|
+
initialState: {
|
102
|
+
leaderHead: EventId.EventId
|
103
|
+
migrationsReport: MigrationsReport
|
104
|
+
}
|
105
|
+
/**
|
106
|
+
* e.g. used for `store._dev` APIs
|
107
|
+
*
|
108
|
+
* This is currently separated from `.devtools` as it also needs to work when devtools are disabled
|
109
|
+
*/
|
110
|
+
extraIncomingMessagesQueue: Queue.Queue<Devtools.Leader.MessageToApp>
|
98
111
|
}
|
99
112
|
>() {}
|
100
113
|
|
@@ -124,7 +137,11 @@ export interface LeaderSyncProcessor {
|
|
124
137
|
pushPartial: (mutationEvent: MutationEvent.PartialAnyEncoded) => Effect.Effect<void, UnexpectedError, LeaderThreadCtx>
|
125
138
|
boot: (args: {
|
126
139
|
dbReady: Deferred.Deferred<void>
|
127
|
-
}) => Effect.Effect<
|
140
|
+
}) => Effect.Effect<
|
141
|
+
{ initialLeaderHead: EventId.EventId },
|
142
|
+
UnexpectedError,
|
143
|
+
LeaderThreadCtx | Scope.Scope | HttpClient.HttpClient
|
144
|
+
>
|
128
145
|
syncState: Subscribable.Subscribable<SyncState.SyncState>
|
129
146
|
}
|
130
147
|
|
package/src/query-builder/api.ts
CHANGED
@@ -35,7 +35,7 @@ export namespace QueryBuilderAst {
|
|
35
35
|
export type RowQuery = {
|
36
36
|
readonly _tag: 'RowQuery'
|
37
37
|
readonly tableDef: DbSchema.TableDefBase
|
38
|
-
readonly id: string | SessionIdSymbol
|
38
|
+
readonly id: string | SessionIdSymbol | number
|
39
39
|
readonly insertValues: Record<string, unknown>
|
40
40
|
}
|
41
41
|
|
@@ -252,10 +252,10 @@ export namespace QueryBuilder {
|
|
252
252
|
? (_: 'Error: Need to enable deriveMutations to use row()') => any
|
253
253
|
: TTableDef['options']['requiredInsertColumnNames'] extends never
|
254
254
|
? (
|
255
|
-
id: string | SessionIdSymbol,
|
255
|
+
id: string | SessionIdSymbol | number,
|
256
256
|
) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
|
257
257
|
: <TOptions extends RowQuery.RequiredColumnsOptions<TTableDef>>(
|
258
|
-
id: string | SessionIdSymbol,
|
258
|
+
id: string | SessionIdSymbol | number,
|
259
259
|
opts: TOptions,
|
260
260
|
) => QueryBuilder<RowQuery.Result<TTableDef>, TTableDef, QueryBuilder.ApiFeature, QueryInfo.Row>
|
261
261
|
}
|
@@ -18,13 +18,23 @@ const todos = DbSchema.table(
|
|
18
18
|
{ deriveMutations: true },
|
19
19
|
)
|
20
20
|
|
21
|
+
const todosWithIntId = DbSchema.table(
|
22
|
+
'todos_with_int_id',
|
23
|
+
{
|
24
|
+
id: DbSchema.integer({ primaryKey: true }),
|
25
|
+
text: DbSchema.text({ default: '', nullable: false }),
|
26
|
+
status: DbSchema.text({ schema: Schema.Literal('active', 'completed') }),
|
27
|
+
},
|
28
|
+
{ deriveMutations: true },
|
29
|
+
)
|
30
|
+
|
21
31
|
const comments = DbSchema.table('comments', {
|
22
32
|
id: DbSchema.text({ primaryKey: true }),
|
23
33
|
text: DbSchema.text({ default: '', nullable: false }),
|
24
34
|
todoId: DbSchema.text({}),
|
25
35
|
})
|
26
36
|
|
27
|
-
const db = { todos: todos.query, comments: comments.query }
|
37
|
+
const db = { todos: todos.query, todosWithIntId: todosWithIntId.query, comments: comments.query }
|
28
38
|
|
29
39
|
describe('query builder', () => {
|
30
40
|
describe('result schema', () => {
|
@@ -204,6 +214,17 @@ describe('query builder', () => {
|
|
204
214
|
}
|
205
215
|
`)
|
206
216
|
})
|
217
|
+
|
218
|
+
it('should handle row queries with numbers', () => {
|
219
|
+
expect(db.todosWithIntId.row(123, { insertValues: { status: 'active' } }).asSql()).toMatchInlineSnapshot(`
|
220
|
+
{
|
221
|
+
"bindValues": [
|
222
|
+
123,
|
223
|
+
],
|
224
|
+
"query": "SELECT * FROM 'todos_with_int_id' WHERE id = ?",
|
225
|
+
}
|
226
|
+
`)
|
227
|
+
})
|
207
228
|
})
|
208
229
|
})
|
209
230
|
|
@@ -128,12 +128,12 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
|
|
128
128
|
// eslint-disable-next-line prefer-rest-params
|
129
129
|
const params = [...arguments]
|
130
130
|
|
131
|
-
let id: string
|
131
|
+
let id: string | number
|
132
132
|
|
133
133
|
if (tableDef.options.isSingleton) {
|
134
134
|
id = tableDef.sqliteDef.columns.id!.default.pipe(Option.getOrThrow)
|
135
135
|
} else {
|
136
|
-
id = params[0] as string
|
136
|
+
id = params[0] as string | number
|
137
137
|
if (id === undefined) {
|
138
138
|
invalidQueryBuilder(`Id missing for row query on non-singleton table ${tableDef.sqliteDef.name}`)
|
139
139
|
}
|
package/src/query-info.ts
CHANGED
@@ -24,20 +24,20 @@ export namespace QueryInfo {
|
|
24
24
|
export type Row = {
|
25
25
|
_tag: 'Row'
|
26
26
|
table: DbSchema.TableDefBase
|
27
|
-
id: string | SessionIdSymbol
|
27
|
+
id: string | SessionIdSymbol | number
|
28
28
|
}
|
29
29
|
|
30
30
|
export type Col = {
|
31
31
|
_tag: 'Col'
|
32
32
|
table: DbSchema.TableDefBase
|
33
|
-
id: string | SessionIdSymbol
|
33
|
+
id: string | SessionIdSymbol | number
|
34
34
|
column: string
|
35
35
|
}
|
36
36
|
|
37
37
|
export type ColJsonValue = {
|
38
38
|
_tag: 'ColJsonValue'
|
39
39
|
table: DbSchema.TableDefBase
|
40
|
-
id: string | SessionIdSymbol
|
40
|
+
id: string | SessionIdSymbol | number
|
41
41
|
column: string
|
42
42
|
/**
|
43
43
|
* example: `$.tabs[3].items[2]` (`$` referring to the column value)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { memoizeByRef, shouldNeverHappen } from '@livestore/utils'
|
2
2
|
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
3
3
|
|
4
|
-
import { type MigrationOptionsFromMutationLog, type
|
4
|
+
import { type MigrationOptionsFromMutationLog, type SqliteDb, UnexpectedError } from './adapter-types.js'
|
5
5
|
import { makeApplyMutation } from './leader-thread/apply-mutation.js'
|
6
6
|
import type { LiveStoreSchema, MutationDef, MutationEvent, MutationLogMetaRow } from './schema/mod.js'
|
7
7
|
import { EventId, MUTATION_LOG_META_TABLE } from './schema/mod.js'
|
@@ -16,8 +16,8 @@ export const rehydrateFromMutationLog = ({
|
|
16
16
|
migrationOptions,
|
17
17
|
onProgress,
|
18
18
|
}: {
|
19
|
-
logDb:
|
20
|
-
db:
|
19
|
+
logDb: SqliteDb
|
20
|
+
db: SqliteDb
|
21
21
|
schema: LiveStoreSchema
|
22
22
|
migrationOptions: MigrationOptionsFromMutationLog
|
23
23
|
onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
|
package/src/schema/EventId.ts
CHANGED
@@ -43,6 +43,10 @@ export const isGreaterThan = (a: EventId, b: EventId) => {
|
|
43
43
|
return a.global > b.global || (a.global === b.global && a.local > b.local)
|
44
44
|
}
|
45
45
|
|
46
|
+
export const isGreaterThanOrEqual = (a: EventId, b: EventId) => {
|
47
|
+
return a.global > b.global || (a.global === b.global && a.local >= b.local)
|
48
|
+
}
|
49
|
+
|
46
50
|
export const make = (id: EventId | typeof EventId.Encoded): EventId => {
|
47
51
|
return Schema.is(EventId)(id) ? id : Schema.decodeSync(EventId)(id)
|
48
52
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import type {
|
1
|
+
import type { SqliteDb } from '../adapter-types.js'
|
2
2
|
import type { ParamsObject } from '../util.js'
|
3
3
|
import { prepareBindValues } from '../util.js'
|
4
4
|
|
@@ -6,7 +6,7 @@ import { prepareBindValues } from '../util.js'
|
|
6
6
|
// will require proper scope-aware cleanup etc (for testing and apps with multiple LiveStore instances)
|
7
7
|
// const cachedStmts = new Map<string, PreparedStatement>()
|
8
8
|
|
9
|
-
export const dbExecute = (db:
|
9
|
+
export const dbExecute = (db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
|
10
10
|
// let stmt = cachedStmts.get(queryStr)
|
11
11
|
// if (!stmt) {
|
12
12
|
const stmt = db.prepare(queryStr)
|
@@ -20,7 +20,7 @@ export const dbExecute = (db: SynchronousDatabase, queryStr: string, bindValues?
|
|
20
20
|
stmt.finalize()
|
21
21
|
}
|
22
22
|
|
23
|
-
export const dbSelect = <T>(db:
|
23
|
+
export const dbSelect = <T>(db: SqliteDb, queryStr: string, bindValues?: ParamsObject) => {
|
24
24
|
// let stmt = cachedStmts.get(queryStr)
|
25
25
|
// if (!stmt) {
|
26
26
|
const stmt = db.prepare(queryStr)
|
@@ -2,7 +2,7 @@ import { SqliteAst, SqliteDsl } from '@livestore/db-schema'
|
|
2
2
|
import { memoizeByStringifyArgs } from '@livestore/utils'
|
3
3
|
import { Effect, Schema as EffectSchema } from '@livestore/utils/effect'
|
4
4
|
|
5
|
-
import type {
|
5
|
+
import type { MigrationsReport, MigrationsReportEntry, SqliteDb, UnexpectedError } from '../adapter-types.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'
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import { LS_DEV, shouldNeverHappen, TRACE_VERBOSE } from '@livestore/utils'
|
2
|
-
import type { Scope } from '@livestore/utils/effect'
|
3
|
-
import { Effect, Schema, Stream } from '@livestore/utils/effect'
|
2
|
+
import type { Runtime, Scope } from '@livestore/utils/effect'
|
3
|
+
import { Effect, Queue, Schema, Stream, Subscribable } from '@livestore/utils/effect'
|
4
4
|
import * as otel from '@opentelemetry/api'
|
5
5
|
|
6
|
-
import type {
|
6
|
+
import type { ClientSession, UnexpectedError } from '../adapter-types.js'
|
7
7
|
import * as EventId from '../schema/EventId.js'
|
8
8
|
import { type LiveStoreSchema } from '../schema/mod.js'
|
9
9
|
import * as MutationEvent from '../schema/MutationEvent.js'
|
10
|
-
import
|
10
|
+
import * as SyncState from './syncstate.js'
|
11
11
|
|
12
12
|
/**
|
13
13
|
* Rebase behaviour:
|
@@ -20,18 +20,16 @@ import { SyncState, updateSyncState } from './syncstate.js'
|
|
20
20
|
*/
|
21
21
|
export const makeClientSessionSyncProcessor = ({
|
22
22
|
schema,
|
23
|
-
|
24
|
-
|
25
|
-
pullFromLeader,
|
23
|
+
clientSession,
|
24
|
+
runtime,
|
26
25
|
applyMutation,
|
27
26
|
rollback,
|
28
27
|
refreshTables,
|
29
28
|
span,
|
30
29
|
}: {
|
31
30
|
schema: LiveStoreSchema
|
32
|
-
|
33
|
-
|
34
|
-
pullFromLeader: ClientSessionLeaderThreadProxy['mutations']['pull']
|
31
|
+
clientSession: ClientSession
|
32
|
+
runtime: Runtime.Runtime<Scope.Scope>
|
35
33
|
applyMutation: (
|
36
34
|
mutationEventDecoded: MutationEvent.PartialAnyDecoded,
|
37
35
|
options: { otelContext: otel.Context; withChangeset: boolean },
|
@@ -46,15 +44,17 @@ export const makeClientSessionSyncProcessor = ({
|
|
46
44
|
const mutationEventSchema = MutationEvent.makeMutationEventSchemaMemo(schema)
|
47
45
|
|
48
46
|
const syncStateRef = {
|
49
|
-
current: new SyncState({
|
50
|
-
localHead:
|
51
|
-
upstreamHead:
|
47
|
+
current: new SyncState.SyncState({
|
48
|
+
localHead: clientSession.leaderThread.initialState.leaderHead,
|
49
|
+
upstreamHead: clientSession.leaderThread.initialState.leaderHead,
|
52
50
|
pending: [],
|
53
51
|
// TODO init rollbackTail from leader to be ready for backend rebasing
|
54
52
|
rollbackTail: [],
|
55
53
|
}),
|
56
54
|
}
|
57
55
|
|
56
|
+
const syncStateUpdateQueue = Queue.unbounded<SyncState.SyncState>().pipe(Effect.runSync)
|
57
|
+
|
58
58
|
const isLocalEvent = (mutationEventEncoded: MutationEvent.EncodedWithMeta) => {
|
59
59
|
const mutationDef = schema.mutations.get(mutationEventEncoded.mutation)!
|
60
60
|
return mutationDef.options.localOnly
|
@@ -73,7 +73,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
73
73
|
)
|
74
74
|
})
|
75
75
|
|
76
|
-
const updateResult = updateSyncState({
|
76
|
+
const updateResult = SyncState.updateSyncState({
|
77
77
|
syncState: syncStateRef.current,
|
78
78
|
payload: { _tag: 'local-push', newEvents: encodedMutationEvents },
|
79
79
|
isLocalEvent,
|
@@ -90,6 +90,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
90
90
|
}
|
91
91
|
|
92
92
|
syncStateRef.current = updateResult.newSyncState
|
93
|
+
syncStateUpdateQueue.offer(updateResult.newSyncState).pipe(Effect.runSync)
|
93
94
|
|
94
95
|
const writeTables = new Set<string>()
|
95
96
|
for (const mutationEvent of updateResult.newEvents) {
|
@@ -103,7 +104,9 @@ export const makeClientSessionSyncProcessor = ({
|
|
103
104
|
}
|
104
105
|
|
105
106
|
// console.debug('pushToLeader', encodedMutationEvents.length, ...encodedMutationEvents.map((_) => _.toJSON()))
|
106
|
-
|
107
|
+
clientSession.leaderThread.mutations
|
108
|
+
.push(encodedMutationEvents)
|
109
|
+
.pipe(Effect.tapCauseLogPretty, Effect.provide(runtime), Effect.runFork)
|
107
110
|
|
108
111
|
return { writeTables }
|
109
112
|
}
|
@@ -111,12 +114,15 @@ export const makeClientSessionSyncProcessor = ({
|
|
111
114
|
const otelContext = otel.trace.setSpan(otel.context.active(), span)
|
112
115
|
|
113
116
|
const boot: ClientSessionSyncProcessor['boot'] = Effect.gen(function* () {
|
114
|
-
yield*
|
117
|
+
yield* clientSession.leaderThread.mutations.pull.pipe(
|
115
118
|
Stream.tap(({ payload, remaining }) =>
|
116
119
|
Effect.gen(function* () {
|
117
120
|
// console.log('pulled payload from leader', { payload, remaining })
|
121
|
+
if (clientSession.devtools.enabled) {
|
122
|
+
yield* clientSession.devtools.pullLatch.await
|
123
|
+
}
|
118
124
|
|
119
|
-
const updateResult = updateSyncState({
|
125
|
+
const updateResult = SyncState.updateSyncState({
|
120
126
|
syncState: syncStateRef.current,
|
121
127
|
payload,
|
122
128
|
isLocalEvent,
|
@@ -129,6 +135,7 @@ export const makeClientSessionSyncProcessor = ({
|
|
129
135
|
}
|
130
136
|
|
131
137
|
syncStateRef.current = updateResult.newSyncState
|
138
|
+
syncStateUpdateQueue.offer(updateResult.newSyncState).pipe(Effect.runSync)
|
132
139
|
|
133
140
|
if (updateResult._tag === 'rebase') {
|
134
141
|
span.addEvent('pull:rebase', {
|
@@ -140,11 +147,11 @@ export const makeClientSessionSyncProcessor = ({
|
|
140
147
|
remaining,
|
141
148
|
})
|
142
149
|
if (LS_DEV) {
|
143
|
-
|
150
|
+
Effect.logDebug(
|
144
151
|
'pull:rebase: rollback',
|
145
152
|
updateResult.eventsToRollback.length,
|
146
153
|
...updateResult.eventsToRollback.map((_) => _.toJSON()),
|
147
|
-
)
|
154
|
+
).pipe(Effect.provide(runtime), Effect.runSync)
|
148
155
|
}
|
149
156
|
|
150
157
|
for (let i = updateResult.eventsToRollback.length - 1; i >= 0; i--) {
|
@@ -155,7 +162,9 @@ export const makeClientSessionSyncProcessor = ({
|
|
155
162
|
}
|
156
163
|
}
|
157
164
|
|
158
|
-
|
165
|
+
clientSession.leaderThread.mutations
|
166
|
+
.push(updateResult.newSyncState.pending)
|
167
|
+
.pipe(Effect.tapCauseLogPretty, Effect.provide(runtime), Effect.runFork)
|
159
168
|
} else {
|
160
169
|
span.addEvent('pull:advance', {
|
161
170
|
payloadTag: payload._tag,
|
@@ -192,7 +201,14 @@ export const makeClientSessionSyncProcessor = ({
|
|
192
201
|
return {
|
193
202
|
push,
|
194
203
|
boot,
|
195
|
-
|
204
|
+
syncState: Subscribable.make({
|
205
|
+
get: Effect.gen(function* () {
|
206
|
+
const syncState = syncStateRef.current
|
207
|
+
if (syncStateRef === undefined) return shouldNeverHappen('Not initialized')
|
208
|
+
return syncState
|
209
|
+
}),
|
210
|
+
changes: Stream.fromQueue(syncStateUpdateQueue),
|
211
|
+
}),
|
196
212
|
} satisfies ClientSessionSyncProcessor
|
197
213
|
}
|
198
214
|
|
@@ -205,5 +221,5 @@ export interface ClientSessionSyncProcessor {
|
|
205
221
|
}
|
206
222
|
boot: Effect.Effect<void, UnexpectedError, Scope.Scope>
|
207
223
|
|
208
|
-
|
224
|
+
syncState: Subscribable.Subscribable<SyncState.SyncState>
|
209
225
|
}
|
package/src/version.ts
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
// import packageJson from '../package.json' with { type: 'json' }
|
3
3
|
// export const liveStoreVersion = packageJson.version
|
4
4
|
|
5
|
-
export const liveStoreVersion = '0.3.0-dev.
|
5
|
+
export const liveStoreVersion = '0.3.0-dev.12' as const
|
6
6
|
|
7
7
|
/**
|
8
8
|
* This version number is incremented whenever the internal storage format changes in a breaking way.
|