@livestore/common 0.3.0-dev.3 → 0.3.0-dev.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/fixture.d.ts +83 -221
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +33 -11
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/adapter-types.d.ts +128 -68
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +36 -7
- package/dist/adapter-types.js.map +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/debug-info.js +1 -0
- package/dist/debug-info.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 +68 -0
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-common.js +60 -0
- package/dist/devtools/devtools-messages-common.js.map +1 -0
- package/dist/devtools/devtools-messages-leader.d.ts +394 -0
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -0
- package/dist/devtools/devtools-messages-leader.js +147 -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 +4 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +62 -0
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -0
- package/dist/leader-thread/LeaderSyncProcessor.js +589 -0
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -0
- package/dist/leader-thread/apply-event.d.ts +16 -0
- package/dist/leader-thread/apply-event.d.ts.map +1 -0
- package/dist/leader-thread/apply-event.js +103 -0
- package/dist/leader-thread/apply-event.js.map +1 -0
- package/dist/leader-thread/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/eventlog.d.ts +27 -0
- package/dist/leader-thread/eventlog.d.ts.map +1 -0
- package/dist/leader-thread/eventlog.js +123 -0
- package/dist/leader-thread/eventlog.js.map +1 -0
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +154 -132
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +26 -12
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +82 -47
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -1
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -1
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +4 -2
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +35 -25
- 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 +86 -39
- 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/materializer-helper.d.ts +23 -0
- package/dist/materializer-helper.d.ts.map +1 -0
- package/dist/materializer-helper.js +70 -0
- package/dist/materializer-helper.js.map +1 -0
- package/dist/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 +158 -55
- package/dist/query-builder/api.d.ts.map +1 -1
- package/dist/query-builder/api.js +3 -5
- package/dist/query-builder/api.js.map +1 -1
- package/dist/query-builder/astToSql.d.ts +7 -0
- package/dist/query-builder/astToSql.d.ts.map +1 -0
- package/dist/query-builder/astToSql.js +190 -0
- package/dist/query-builder/astToSql.js.map +1 -0
- package/dist/query-builder/impl.d.ts +3 -8
- package/dist/query-builder/impl.d.ts.map +1 -1
- package/dist/query-builder/impl.js +166 -124
- package/dist/query-builder/impl.js.map +1 -1
- package/dist/query-builder/impl.test.d.ts +86 -1
- package/dist/query-builder/impl.test.d.ts.map +1 -1
- package/dist/query-builder/impl.test.js +411 -69
- package/dist/query-builder/impl.test.js.map +1 -1
- package/dist/query-builder/mod.d.ts +7 -0
- package/dist/query-builder/mod.d.ts.map +1 -1
- package/dist/query-builder/mod.js +7 -0
- package/dist/query-builder/mod.js.map +1 -1
- package/dist/rehydrate-from-eventlog.d.ts +14 -0
- package/dist/rehydrate-from-eventlog.d.ts.map +1 -0
- package/dist/rehydrate-from-eventlog.js +65 -0
- package/dist/rehydrate-from-eventlog.js.map +1 -0
- package/dist/schema/EventDef.d.ts +136 -0
- package/dist/schema/EventDef.d.ts.map +1 -0
- package/dist/schema/EventDef.js +58 -0
- package/dist/schema/EventDef.js.map +1 -0
- package/dist/schema/EventId.d.ts +35 -15
- package/dist/schema/EventId.d.ts.map +1 -1
- package/dist/schema/EventId.js +57 -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/LiveStoreEvent.d.ts +255 -0
- package/dist/schema/LiveStoreEvent.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent.js +118 -0
- package/dist/schema/LiveStoreEvent.js.map +1 -0
- package/dist/schema/client-document-def.d.ts +223 -0
- package/dist/schema/client-document-def.d.ts.map +1 -0
- package/dist/schema/client-document-def.js +170 -0
- package/dist/schema/client-document-def.js.map +1 -0
- package/dist/schema/client-document-def.test.d.ts +2 -0
- package/dist/schema/client-document-def.test.d.ts.map +1 -0
- package/dist/schema/client-document-def.test.js +201 -0
- package/dist/schema/client-document-def.test.js.map +1 -0
- package/dist/schema/db-schema/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 +90 -0
- package/dist/schema/db-schema/dsl/mod.d.ts.map +1 -0
- package/dist/schema/db-schema/dsl/mod.js +41 -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/events.d.ts +2 -0
- package/dist/schema/events.d.ts.map +1 -0
- package/dist/schema/events.js +2 -0
- package/dist/schema/events.js.map +1 -0
- package/dist/schema/mod.d.ts +5 -3
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +5 -3
- package/dist/schema/mod.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 +30 -23
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +48 -35
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/sqlite-state.d.ts +12 -0
- package/dist/schema/sqlite-state.d.ts.map +1 -0
- package/dist/schema/sqlite-state.js +36 -0
- package/dist/schema/sqlite-state.js.map +1 -0
- package/dist/schema/system-tables.d.ts +179 -125
- package/dist/schema/system-tables.d.ts.map +1 -1
- package/dist/schema/system-tables.js +76 -41
- package/dist/schema/system-tables.js.map +1 -1
- package/dist/schema/table-def.d.ts +37 -109
- package/dist/schema/table-def.d.ts.map +1 -1
- package/dist/schema/table-def.js +23 -66
- package/dist/schema/table-def.js.map +1 -1
- package/dist/schema/view.d.ts +3 -0
- package/dist/schema/view.d.ts.map +1 -0
- package/dist/schema/view.js +3 -0
- package/dist/schema/view.js.map +1 -0
- package/dist/schema-management/common.d.ts +7 -7
- 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 +19 -14
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-mutation-defs.d.ts +3 -3
- package/dist/schema-management/validate-mutation-defs.d.ts.map +1 -1
- package/dist/schema-management/validate-mutation-defs.js +17 -17
- package/dist/schema-management/validate-mutation-defs.js.map +1 -1
- package/dist/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/ClientSessionSyncProcessor.d.ts +66 -0
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -0
- package/dist/sync/ClientSessionSyncProcessor.js +209 -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 +19 -19
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +3 -3
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +6 -7
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +4 -2
- 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 +2 -2
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +10 -8
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +11 -8
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/compact-events.calculator.test.js +38 -33
- package/dist/sync/next/test/compact-events.calculator.test.js.map +1 -1
- package/dist/sync/next/test/compact-events.test.js +76 -76
- package/dist/sync/next/test/compact-events.test.js.map +1 -1
- package/dist/sync/next/test/{mutation-fixtures.d.ts → event-fixtures.d.ts} +29 -29
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -0
- package/dist/sync/next/test/{mutation-fixtures.js → event-fixtures.js} +67 -36
- package/dist/sync/next/test/event-fixtures.js.map +1 -0
- package/dist/sync/next/test/mod.d.ts +1 -1
- package/dist/sync/next/test/mod.d.ts.map +1 -1
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/next/test/mod.js.map +1 -1
- package/dist/sync/sync.d.ts +55 -20
- 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 +213 -82
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +319 -120
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +295 -275
- 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/__tests__/fixture.ts +36 -15
- package/src/adapter-types.ts +111 -74
- package/src/debug-info.ts +1 -0
- package/src/devtools/devtools-messages-client-session.ts +141 -0
- package/src/devtools/devtools-messages-common.ts +115 -0
- package/src/devtools/devtools-messages-leader.ts +191 -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 +4 -13
- package/src/leader-thread/LeaderSyncProcessor.ts +935 -0
- package/src/leader-thread/apply-event.ts +173 -0
- package/src/leader-thread/connection.ts +54 -9
- package/src/leader-thread/eventlog.ts +199 -0
- package/src/leader-thread/leader-worker-devtools.ts +212 -189
- package/src/leader-thread/make-leader-thread-layer.ts +143 -77
- package/src/leader-thread/mod.ts +1 -1
- package/src/leader-thread/recreate-db.ts +41 -30
- package/src/leader-thread/shutdown-channel.ts +2 -4
- package/src/leader-thread/types.ts +95 -51
- package/src/materializer-helper.ts +110 -0
- package/src/otel.ts +8 -0
- package/src/query-builder/api.ts +236 -85
- package/src/query-builder/astToSql.ts +232 -0
- package/src/query-builder/impl.test.ts +447 -78
- package/src/query-builder/impl.ts +209 -144
- package/src/query-builder/mod.ts +7 -0
- package/src/rehydrate-from-eventlog.ts +114 -0
- package/src/schema/EventDef.ts +216 -0
- package/src/schema/EventId.test.ts +12 -0
- package/src/schema/EventId.ts +75 -15
- package/src/schema/LiveStoreEvent.ts +239 -0
- package/src/schema/client-document-def.test.ts +239 -0
- package/src/schema/client-document-def.ts +444 -0
- 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 +222 -0
- package/src/schema/db-schema/hash.ts +14 -0
- package/src/schema/db-schema/mod.ts +2 -0
- package/src/schema/events.ts +1 -0
- package/src/schema/mod.ts +5 -3
- package/src/schema/schema-helpers.ts +1 -1
- package/src/schema/schema.ts +84 -62
- package/src/schema/sqlite-state.ts +62 -0
- package/src/schema/system-tables.ts +68 -50
- package/src/schema/table-def.ts +68 -214
- package/src/schema/view.ts +2 -0
- package/src/schema-management/common.ts +7 -7
- package/src/schema-management/migrations.ts +27 -24
- package/src/schema-management/validate-mutation-defs.ts +22 -24
- 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 +332 -0
- package/src/sync/index.ts +1 -1
- package/src/sync/next/facts.ts +32 -33
- package/src/sync/next/history-dag-common.ts +9 -5
- package/src/sync/next/history-dag.ts +2 -2
- package/src/sync/next/rebase-events.ts +22 -16
- package/src/sync/next/test/compact-events.calculator.test.ts +45 -45
- package/src/sync/next/test/compact-events.test.ts +78 -78
- package/src/sync/next/test/event-fixtures.ts +219 -0
- package/src/sync/next/test/mod.ts +1 -1
- package/src/sync/sync.ts +51 -19
- package/src/sync/syncstate.test.ts +335 -308
- package/src/sync/syncstate.ts +394 -212
- package/src/sync/validate-push-payload.ts +7 -4
- package/src/version.ts +1 -1
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +2 -1
- package/dist/derived-mutations.d.ts +0 -109
- package/dist/derived-mutations.d.ts.map +0 -1
- package/dist/derived-mutations.js +0 -54
- package/dist/derived-mutations.js.map +0 -1
- package/dist/derived-mutations.test.d.ts +0 -2
- package/dist/derived-mutations.test.d.ts.map +0 -1
- package/dist/derived-mutations.test.js +0 -93
- package/dist/derived-mutations.test.js.map +0 -1
- package/dist/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/init-singleton-tables.d.ts +0 -4
- package/dist/init-singleton-tables.d.ts.map +0 -1
- package/dist/init-singleton-tables.js +0 -16
- package/dist/init-singleton-tables.js.map +0 -1
- package/dist/leader-thread/apply-mutation.d.ts +0 -8
- package/dist/leader-thread/apply-mutation.d.ts.map +0 -1
- package/dist/leader-thread/apply-mutation.js +0 -95
- package/dist/leader-thread/apply-mutation.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/leader-thread/mutationlog.d.ts +0 -23
- package/dist/leader-thread/mutationlog.d.ts.map +0 -1
- package/dist/leader-thread/mutationlog.js +0 -27
- package/dist/leader-thread/mutationlog.js.map +0 -1
- package/dist/leader-thread/pull-queue-set.d.ts +0 -7
- package/dist/leader-thread/pull-queue-set.d.ts.map +0 -1
- package/dist/leader-thread/pull-queue-set.js +0 -39
- package/dist/leader-thread/pull-queue-set.js.map +0 -1
- package/dist/mutation.d.ts +0 -13
- package/dist/mutation.d.ts.map +0 -1
- package/dist/mutation.js +0 -57
- package/dist/mutation.js.map +0 -1
- package/dist/query-info.d.ts +0 -38
- package/dist/query-info.d.ts.map +0 -1
- package/dist/query-info.js +0 -7
- package/dist/query-info.js.map +0 -1
- package/dist/rehydrate-from-mutationlog.d.ts +0 -14
- package/dist/rehydrate-from-mutationlog.d.ts.map +0 -1
- package/dist/rehydrate-from-mutationlog.js +0 -72
- package/dist/rehydrate-from-mutationlog.js.map +0 -1
- package/dist/schema/MutationEvent.d.ts +0 -191
- package/dist/schema/MutationEvent.d.ts.map +0 -1
- package/dist/schema/MutationEvent.js +0 -56
- package/dist/schema/MutationEvent.js.map +0 -1
- package/dist/schema/mutations.d.ts +0 -107
- package/dist/schema/mutations.d.ts.map +0 -1
- package/dist/schema/mutations.js +0 -42
- package/dist/schema/mutations.js.map +0 -1
- package/dist/sync/client-session-sync-processor.d.ts +0 -45
- 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/dist/sync/next/test/mutation-fixtures.d.ts.map +0 -1
- package/dist/sync/next/test/mutation-fixtures.js.map +0 -1
- package/src/derived-mutations.test.ts +0 -101
- package/src/derived-mutations.ts +0 -166
- package/src/devtools/devtools-bridge.ts +0 -13
- package/src/devtools/index.ts +0 -48
- package/src/init-singleton-tables.ts +0 -24
- package/src/leader-thread/apply-mutation.ts +0 -143
- package/src/leader-thread/leader-sync-processor.ts +0 -666
- package/src/leader-thread/mutationlog.ts +0 -42
- package/src/leader-thread/pull-queue-set.ts +0 -58
- package/src/mutation.ts +0 -81
- package/src/query-info.ts +0 -78
- package/src/rehydrate-from-mutationlog.ts +0 -127
- package/src/schema/MutationEvent.ts +0 -161
- package/src/schema/mutations.ts +0 -192
- package/src/sync/client-session-sync-processor.ts +0 -207
- package/src/sync/next/test/mutation-fixtures.ts +0 -231
@@ -1,27 +1,29 @@
|
|
1
|
-
import {
|
1
|
+
import { casesHandled, shouldNeverHappen } from '@livestore/utils'
|
2
|
+
import { Match, Option, Predicate, Schema } from '@livestore/utils/effect'
|
2
3
|
|
3
|
-
import type {
|
4
|
-
import type { DbSchema } from '../schema/mod.js'
|
4
|
+
import type { State } from '../schema/mod.js'
|
5
5
|
import type { QueryBuilder, QueryBuilderAst } from './api.js'
|
6
|
-
import { QueryBuilderAstSymbol,
|
6
|
+
import { QueryBuilderAstSymbol, QueryBuilderTypeId } from './api.js'
|
7
|
+
import { astToSql } from './astToSql.js'
|
7
8
|
|
8
|
-
export const makeQueryBuilder = <TResult, TTableDef extends
|
9
|
+
export const makeQueryBuilder = <TResult, TTableDef extends State.SQLite.TableDefBase>(
|
9
10
|
tableDef: TTableDef,
|
10
11
|
ast: QueryBuilderAst = emptyAst(tableDef),
|
11
|
-
): QueryBuilder<TResult, TTableDef, never
|
12
|
+
): QueryBuilder<TResult, TTableDef, never> => {
|
12
13
|
const api = {
|
13
14
|
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
14
15
|
select() {
|
15
|
-
|
16
|
+
assertSelectQueryBuilderAst(ast)
|
16
17
|
|
17
18
|
// eslint-disable-next-line prefer-rest-params
|
18
19
|
const params = [...arguments]
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
// Pluck if there's only one column selected
|
22
|
+
if (params.length === 1) {
|
23
|
+
const [col] = params as any as [string]
|
22
24
|
return makeQueryBuilder(tableDef, {
|
23
25
|
...ast,
|
24
|
-
resultSchemaSingle:
|
26
|
+
resultSchemaSingle: ast.resultSchemaSingle.pipe(Schema.pluck(col)),
|
25
27
|
select: { columns: [col] },
|
26
28
|
})
|
27
29
|
}
|
@@ -36,8 +38,9 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
|
|
36
38
|
}) as any
|
37
39
|
},
|
38
40
|
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
39
|
-
where() {
|
40
|
-
if (
|
41
|
+
where: function () {
|
42
|
+
if (ast._tag === 'InsertQuery') return invalidQueryBuilder('Cannot use where with insert')
|
43
|
+
if (ast._tag === 'RowQuery') return invalidQueryBuilder('Cannot use where with row')
|
41
44
|
|
42
45
|
if (arguments.length === 1) {
|
43
46
|
// eslint-disable-next-line prefer-rest-params
|
@@ -50,24 +53,45 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
|
|
50
53
|
: { col, op: '=', value },
|
51
54
|
)
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
switch (ast._tag) {
|
57
|
+
case 'CountQuery':
|
58
|
+
case 'SelectQuery':
|
59
|
+
case 'UpdateQuery':
|
60
|
+
case 'DeleteQuery': {
|
61
|
+
return makeQueryBuilder(tableDef, {
|
62
|
+
...ast,
|
63
|
+
where: [...ast.where, ...newOps],
|
64
|
+
}) as any
|
65
|
+
}
|
66
|
+
default: {
|
67
|
+
return casesHandled(ast)
|
68
|
+
}
|
69
|
+
}
|
57
70
|
}
|
58
71
|
|
59
72
|
// eslint-disable-next-line prefer-rest-params
|
60
73
|
const [col, opOrValue, valueOrUndefined] = arguments
|
61
74
|
const op = valueOrUndefined === undefined ? '=' : opOrValue
|
62
75
|
const value = valueOrUndefined === undefined ? opOrValue : valueOrUndefined
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
76
|
+
|
77
|
+
switch (ast._tag) {
|
78
|
+
case 'CountQuery':
|
79
|
+
case 'SelectQuery':
|
80
|
+
case 'UpdateQuery':
|
81
|
+
case 'DeleteQuery': {
|
82
|
+
return makeQueryBuilder(tableDef, {
|
83
|
+
...ast,
|
84
|
+
where: [...ast.where, { col, op, value }],
|
85
|
+
}) as any
|
86
|
+
}
|
87
|
+
default: {
|
88
|
+
return casesHandled(ast)
|
89
|
+
}
|
90
|
+
}
|
67
91
|
},
|
68
92
|
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
69
93
|
orderBy() {
|
70
|
-
|
94
|
+
assertSelectQueryBuilderAst(ast)
|
71
95
|
|
72
96
|
if (arguments.length === 0 || arguments.length > 2) return invalidQueryBuilder()
|
73
97
|
|
@@ -89,12 +113,12 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
|
|
89
113
|
}) as any
|
90
114
|
},
|
91
115
|
limit: (limit) => {
|
92
|
-
|
116
|
+
assertSelectQueryBuilderAst(ast)
|
93
117
|
|
94
118
|
return makeQueryBuilder(tableDef, { ...ast, limit: Option.some(limit) })
|
95
119
|
},
|
96
120
|
offset: (offset) => {
|
97
|
-
|
121
|
+
assertSelectQueryBuilderAst(ast)
|
98
122
|
|
99
123
|
return makeQueryBuilder(tableDef, { ...ast, offset: Option.some(offset) })
|
100
124
|
},
|
@@ -102,58 +126,129 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
|
|
102
126
|
if (isRowQuery(ast)) return invalidQueryBuilder()
|
103
127
|
|
104
128
|
return makeQueryBuilder(tableDef, {
|
105
|
-
|
129
|
+
_tag: 'CountQuery',
|
130
|
+
tableDef,
|
131
|
+
where: [],
|
106
132
|
resultSchema: Schema.Struct({ count: Schema.Number }).pipe(
|
107
133
|
Schema.pluck('count'),
|
108
134
|
Schema.Array,
|
109
135
|
Schema.headOrElse(),
|
110
136
|
),
|
111
|
-
_tag: 'CountQuery',
|
112
137
|
})
|
113
138
|
},
|
114
139
|
first: (options) => {
|
115
|
-
|
140
|
+
assertSelectQueryBuilderAst(ast)
|
116
141
|
|
117
142
|
if (ast.limit._tag === 'Some') return invalidQueryBuilder(`.first() can't be called after .limit()`)
|
118
143
|
|
119
144
|
return makeQueryBuilder(tableDef, {
|
120
145
|
...ast,
|
121
146
|
limit: Option.some(1),
|
122
|
-
|
123
|
-
pickFirst: options?.fallback ? { fallback: options.fallback } : { fallback: () => undefined },
|
147
|
+
pickFirst: options?.fallback ? { fallback: options.fallback } : 'no-fallback',
|
124
148
|
})
|
125
149
|
},
|
126
|
-
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
127
|
-
|
128
|
-
|
129
|
-
|
150
|
+
// // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
151
|
+
// getOrCreate() {
|
152
|
+
// if (tableDef.options.isClientDocumentTable === false) {
|
153
|
+
// return invalidQueryBuilder(`getOrCreate() is not allowed when table is not a client document table`)
|
154
|
+
// }
|
155
|
+
|
156
|
+
// // eslint-disable-next-line prefer-rest-params
|
157
|
+
// const params = [...arguments]
|
158
|
+
|
159
|
+
// let id: string | number
|
160
|
+
|
161
|
+
// // TODO refactor to handle default id
|
162
|
+
// id = params[0] as string | number
|
163
|
+
// if (id === undefined) {
|
164
|
+
// invalidQueryBuilder(`Id missing for row query on non-singleton table ${tableDef.sqliteDef.name}`)
|
165
|
+
// }
|
166
|
+
|
167
|
+
// // TODO validate all required columns are present and values are matching the schema
|
168
|
+
// const insertValues: Record<string, unknown> = params[1]?.insertValues ?? {}
|
169
|
+
|
170
|
+
// return makeQueryBuilder(tableDef, {
|
171
|
+
// _tag: 'RowQuery',
|
172
|
+
// id,
|
173
|
+
// tableDef,
|
174
|
+
// insertValues,
|
175
|
+
// }) as any
|
176
|
+
// },
|
177
|
+
insert: (values) => {
|
178
|
+
const filteredValues = Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined))
|
130
179
|
|
131
|
-
|
180
|
+
return makeQueryBuilder(tableDef, {
|
181
|
+
_tag: 'InsertQuery',
|
182
|
+
tableDef,
|
183
|
+
values: filteredValues,
|
184
|
+
onConflict: undefined,
|
185
|
+
returning: undefined,
|
186
|
+
resultSchema: Schema.Void,
|
187
|
+
}) as any
|
188
|
+
},
|
189
|
+
onConflict: (
|
190
|
+
targetOrTargets: string | string[],
|
191
|
+
action: 'ignore' | 'replace' | 'update',
|
192
|
+
updateValues?: Record<string, unknown>,
|
193
|
+
) => {
|
194
|
+
const targets = Array.isArray(targetOrTargets) ? targetOrTargets : [targetOrTargets]
|
195
|
+
|
196
|
+
assertInsertQueryBuilderAst(ast)
|
197
|
+
|
198
|
+
const onConflict = Match.value(action).pipe(
|
199
|
+
Match.when('ignore', () => ({ targets, action: { _tag: 'ignore' } }) satisfies QueryBuilderAst.OnConflict),
|
200
|
+
Match.when('replace', () => ({ targets, action: { _tag: 'replace' } }) satisfies QueryBuilderAst.OnConflict),
|
201
|
+
Match.when(
|
202
|
+
'update',
|
203
|
+
() => ({ targets, action: { _tag: 'update', update: updateValues! } }) satisfies QueryBuilderAst.OnConflict,
|
204
|
+
),
|
205
|
+
Match.exhaustive,
|
206
|
+
)
|
132
207
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
208
|
+
return makeQueryBuilder(tableDef, {
|
209
|
+
...ast,
|
210
|
+
onConflict,
|
211
|
+
}) as any
|
212
|
+
},
|
213
|
+
|
214
|
+
returning: (...columns) => {
|
215
|
+
assertWriteQueryBuilderAst(ast)
|
216
|
+
|
217
|
+
return makeQueryBuilder(tableDef, {
|
218
|
+
...ast,
|
219
|
+
returning: columns,
|
220
|
+
resultSchema: tableDef.rowSchema.pipe(Schema.pick(...columns), Schema.Array),
|
221
|
+
}) as any
|
222
|
+
},
|
141
223
|
|
142
|
-
|
143
|
-
const
|
224
|
+
update: (values) => {
|
225
|
+
const filteredValues = Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined))
|
144
226
|
|
145
227
|
return makeQueryBuilder(tableDef, {
|
146
|
-
_tag: '
|
147
|
-
id,
|
228
|
+
_tag: 'UpdateQuery',
|
148
229
|
tableDef,
|
149
|
-
|
230
|
+
values: filteredValues,
|
231
|
+
where: [],
|
232
|
+
returning: undefined,
|
233
|
+
resultSchema: Schema.Void,
|
150
234
|
}) as any
|
151
235
|
},
|
152
|
-
|
236
|
+
|
237
|
+
delete: () => {
|
238
|
+
return makeQueryBuilder(tableDef, {
|
239
|
+
_tag: 'DeleteQuery',
|
240
|
+
tableDef,
|
241
|
+
where: [],
|
242
|
+
returning: undefined,
|
243
|
+
resultSchema: Schema.Void,
|
244
|
+
}) as any
|
245
|
+
},
|
246
|
+
} satisfies QueryBuilder.ApiFull<TResult, TTableDef, never>
|
153
247
|
|
154
248
|
return {
|
155
|
-
[
|
249
|
+
[QueryBuilderTypeId]: QueryBuilderTypeId,
|
156
250
|
[QueryBuilderAstSymbol]: ast,
|
251
|
+
['ResultType']: 'only-for-type-inference' as TResult,
|
157
252
|
asSql: () => astToSql(ast),
|
158
253
|
toString: () => {
|
159
254
|
try {
|
@@ -167,119 +262,89 @@ export const makeQueryBuilder = <TResult, TTableDef extends DbSchema.TableDefBas
|
|
167
262
|
} satisfies QueryBuilder<TResult, TTableDef>
|
168
263
|
}
|
169
264
|
|
170
|
-
const emptyAst = (tableDef:
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
return
|
265
|
+
const emptyAst = (tableDef: State.SQLite.TableDefBase): QueryBuilderAst.SelectQuery => ({
|
266
|
+
_tag: 'SelectQuery',
|
267
|
+
columns: [],
|
268
|
+
pickFirst: false,
|
269
|
+
select: { columns: [] },
|
270
|
+
orderBy: [],
|
271
|
+
offset: Option.none(),
|
272
|
+
limit: Option.none(),
|
273
|
+
tableDef,
|
274
|
+
where: [],
|
275
|
+
resultSchemaSingle: tableDef.rowSchema,
|
276
|
+
})
|
277
|
+
|
278
|
+
// Helper functions
|
279
|
+
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
280
|
+
function assertSelectQueryBuilderAst(ast: QueryBuilderAst): asserts ast is QueryBuilderAst.SelectQuery {
|
281
|
+
if (ast._tag !== 'SelectQuery') {
|
282
|
+
return shouldNeverHappen('Expected SelectQuery but got ' + ast._tag)
|
188
283
|
}
|
284
|
+
}
|
189
285
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
ast.where.length > 0
|
195
|
-
? `WHERE ${ast.where
|
196
|
-
.map(({ col, op, value }) => {
|
197
|
-
if (value === null) {
|
198
|
-
if (op !== '=' && op !== '!=') {
|
199
|
-
throw new Error(`Unsupported operator for NULL value: ${op}`)
|
200
|
-
}
|
201
|
-
const opStmt = op === '=' ? 'IS' : 'IS NOT'
|
202
|
-
return `${col} ${opStmt} NULL`
|
203
|
-
} else {
|
204
|
-
const colDef = ast.tableDef.sqliteDef.columns[col]
|
205
|
-
if (colDef === undefined) {
|
206
|
-
throw new Error(`Column ${col} not found`)
|
207
|
-
}
|
208
|
-
const isArray = op === 'IN' || op === 'NOT IN'
|
209
|
-
const colSchema = isArray ? Schema.Array(colDef.schema) : colDef.schema
|
210
|
-
const encodedValue = Schema.encodeSync(colSchema)(value)
|
211
|
-
|
212
|
-
if (isArray) {
|
213
|
-
bindValues.push(...encodedValue)
|
214
|
-
const placeholders = Array.from({ length: encodedValue.length }, () => '?').join(', ')
|
215
|
-
return `${col} ${op} (${placeholders})`
|
216
|
-
} else {
|
217
|
-
bindValues.push(encodedValue)
|
218
|
-
return `${col} ${op} ?`
|
219
|
-
}
|
220
|
-
}
|
221
|
-
})
|
222
|
-
.join(' AND ')}`
|
223
|
-
: ''
|
224
|
-
|
225
|
-
if (ast._tag === 'CountQuery') {
|
226
|
-
const selectFromStmt = `SELECT COUNT(*) as count FROM '${ast.tableDef.sqliteDef.name}'`
|
227
|
-
const query = [selectFromStmt, whereStmt].filter((_) => _.length > 0).join(' ')
|
228
|
-
return { query, bindValues }
|
286
|
+
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
287
|
+
function assertInsertQueryBuilderAst(ast: QueryBuilderAst): asserts ast is QueryBuilderAst.InsertQuery {
|
288
|
+
if (ast._tag !== 'InsertQuery') {
|
289
|
+
return shouldNeverHappen('Expected InsertQuery but got ' + ast._tag)
|
229
290
|
}
|
230
|
-
const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.join(', ')
|
231
|
-
const selectStmt = `SELECT ${columnsStmt}`
|
232
|
-
const fromStmt = `FROM '${ast.tableDef.sqliteDef.name}'`
|
233
|
-
|
234
|
-
const orderByStmt =
|
235
|
-
ast.orderBy.length > 0
|
236
|
-
? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${col} ${direction}`).join(', ')}`
|
237
|
-
: ''
|
238
|
-
|
239
|
-
const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''
|
240
|
-
if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
|
241
|
-
|
242
|
-
const offsetStmt = ast.offset._tag === 'Some' ? `OFFSET ?` : ''
|
243
|
-
if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
|
244
|
-
|
245
|
-
const query = [selectStmt, fromStmt, whereStmt, orderByStmt, offsetStmt, limitStmt]
|
246
|
-
.map((_) => _.trim())
|
247
|
-
.filter((_) => _.length > 0)
|
248
|
-
.join(' ')
|
249
|
-
|
250
|
-
// TODO bind values
|
251
|
-
return { query, bindValues }
|
252
291
|
}
|
253
292
|
|
254
293
|
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
255
|
-
function
|
256
|
-
if (ast._tag !== '
|
257
|
-
|
294
|
+
function assertWriteQueryBuilderAst(ast: QueryBuilderAst): asserts ast is QueryBuilderAst.WriteQuery {
|
295
|
+
if (ast._tag !== 'InsertQuery' && ast._tag !== 'UpdateQuery' && ast._tag !== 'DeleteQuery') {
|
296
|
+
return shouldNeverHappen('Expected WriteQuery but got ' + ast._tag)
|
258
297
|
}
|
259
298
|
}
|
260
299
|
|
261
300
|
const isRowQuery = (ast: QueryBuilderAst): ast is QueryBuilderAst.RowQuery => ast._tag === 'RowQuery'
|
262
301
|
|
263
302
|
export const invalidQueryBuilder = (msg?: string) => {
|
264
|
-
|
303
|
+
return shouldNeverHappen('Invalid query builder' + (msg ? `: ${msg}` : ''))
|
265
304
|
}
|
266
305
|
|
267
|
-
export const getResultSchema = (qb: QueryBuilder<any, any, any>) => {
|
306
|
+
export const getResultSchema = (qb: QueryBuilder<any, any, any>): Schema.Schema<any> => {
|
268
307
|
const queryAst = qb[QueryBuilderAstSymbol]
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
308
|
+
switch (queryAst._tag) {
|
309
|
+
case 'SelectQuery': {
|
310
|
+
const arraySchema = Schema.Array(queryAst.resultSchemaSingle)
|
311
|
+
if (queryAst.pickFirst === false) {
|
312
|
+
return arraySchema
|
313
|
+
} else if (queryAst.pickFirst === 'no-fallback') {
|
314
|
+
// Will throw if the array is empty
|
315
|
+
return arraySchema.pipe(Schema.headOrElse())
|
316
|
+
} else {
|
317
|
+
const fallbackValue = queryAst.pickFirst.fallback()
|
318
|
+
return Schema.Union(arraySchema, Schema.Tuple(Schema.Literal(fallbackValue))).pipe(
|
319
|
+
Schema.headOrElse(() => fallbackValue),
|
320
|
+
)
|
321
|
+
}
|
322
|
+
}
|
323
|
+
case 'CountQuery': {
|
324
|
+
return Schema.Struct({ count: Schema.Number }).pipe(Schema.pluck('count'), Schema.Array, Schema.headOrElse())
|
273
325
|
}
|
326
|
+
case 'InsertQuery':
|
327
|
+
case 'UpdateQuery':
|
328
|
+
case 'DeleteQuery': {
|
329
|
+
// For write operations with RETURNING clause, we need to return the appropriate schema
|
330
|
+
if (queryAst.returning && queryAst.returning.length > 0) {
|
331
|
+
// Create a schema for the returned columns
|
332
|
+
return queryAst.tableDef.rowSchema.pipe(Schema.pick(...queryAst.returning), Schema.Array)
|
333
|
+
}
|
274
334
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
335
|
+
// For write operations without RETURNING, the result is the number of affected rows
|
336
|
+
return Schema.Number
|
337
|
+
}
|
338
|
+
case 'RowQuery': {
|
339
|
+
return queryAst.tableDef.rowSchema.pipe(
|
340
|
+
Schema.pluck('value'),
|
341
|
+
Schema.annotations({ title: `${queryAst.tableDef.sqliteDef.name}.value` }),
|
342
|
+
Schema.Array,
|
343
|
+
Schema.headOrElse(),
|
344
|
+
)
|
345
|
+
}
|
346
|
+
default: {
|
347
|
+
casesHandled(queryAst)
|
283
348
|
}
|
284
349
|
}
|
285
350
|
}
|
package/src/query-builder/mod.ts
CHANGED
@@ -7,4 +7,11 @@ export * from './impl.js'
|
|
7
7
|
* - Close abstraction to SQLite to provide a simple & convenient API with predictable behaviour
|
8
8
|
* - Use table schema definitions to parse, map & validate query results
|
9
9
|
* - Implementation detail: Separate type-level & AST-based runtime implementation
|
10
|
+
*
|
11
|
+
* Currently not supported (not exhaustive list):
|
12
|
+
* - Assumes a `id` column as primary key
|
13
|
+
* - Composite primary keys
|
14
|
+
*
|
15
|
+
* Other known limitations
|
16
|
+
* - Doesn't exclude all invalid query patterns on type level `e.g. `db.todos.returning('id')`
|
10
17
|
*/
|
@@ -0,0 +1,114 @@
|
|
1
|
+
import { memoizeByRef } from '@livestore/utils'
|
2
|
+
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
3
|
+
|
4
|
+
import { type SqliteDb, UnexpectedError } from './adapter-types.js'
|
5
|
+
import type { ApplyEvent } from './leader-thread/mod.js'
|
6
|
+
import type { EventDef, EventlogMetaRow, LiveStoreSchema } from './schema/mod.js'
|
7
|
+
import { EventId, EVENTLOG_META_TABLE, getEventDef, LiveStoreEvent } from './schema/mod.js'
|
8
|
+
import type { PreparedBindValues } from './util.js'
|
9
|
+
import { sql } from './util.js'
|
10
|
+
|
11
|
+
export const rehydrateFromEventlog = ({
|
12
|
+
dbEventlog,
|
13
|
+
// TODO re-use this db when bringing back the boot in-memory db implementation
|
14
|
+
// db,
|
15
|
+
schema,
|
16
|
+
onProgress,
|
17
|
+
applyEvent,
|
18
|
+
}: {
|
19
|
+
dbEventlog: SqliteDb
|
20
|
+
// db: SqliteDb
|
21
|
+
schema: LiveStoreSchema
|
22
|
+
onProgress: (_: { done: number; total: number }) => Effect.Effect<void>
|
23
|
+
applyEvent: ApplyEvent
|
24
|
+
}) =>
|
25
|
+
Effect.gen(function* () {
|
26
|
+
const eventsCount = dbEventlog.select<{ count: number }>(`SELECT COUNT(*) AS count FROM ${EVENTLOG_META_TABLE}`)[0]!
|
27
|
+
.count
|
28
|
+
|
29
|
+
const hashEvent = memoizeByRef((event: EventDef.AnyWithoutFn) => Schema.hash(event.schema))
|
30
|
+
|
31
|
+
const processEvent = (row: EventlogMetaRow) =>
|
32
|
+
Effect.gen(function* () {
|
33
|
+
const eventDef = getEventDef(schema, row.name)
|
34
|
+
|
35
|
+
if (hashEvent(eventDef.eventDef) !== row.schemaHash) {
|
36
|
+
yield* Effect.logWarning(`Schema hash mismatch for mutation ${row.name}. Trying to apply mutation anyway.`)
|
37
|
+
}
|
38
|
+
|
39
|
+
const args = JSON.parse(row.argsJson)
|
40
|
+
|
41
|
+
// Checking whether the schema has changed in an incompatible way
|
42
|
+
yield* Schema.decodeUnknown(eventDef.eventDef.schema)(args).pipe(
|
43
|
+
Effect.mapError((cause) =>
|
44
|
+
UnexpectedError.make({
|
45
|
+
cause,
|
46
|
+
note: `\
|
47
|
+
There was an error during rehydrating from the eventlog while decoding
|
48
|
+
the persisted mutation event args for mutation "${row.name}".
|
49
|
+
This likely means the schema has changed in an incompatible way.
|
50
|
+
`,
|
51
|
+
}),
|
52
|
+
),
|
53
|
+
)
|
54
|
+
|
55
|
+
const eventEncoded = LiveStoreEvent.EncodedWithMeta.make({
|
56
|
+
id: { global: row.idGlobal, client: row.idClient },
|
57
|
+
parentId: { global: row.parentIdGlobal, client: row.parentIdClient },
|
58
|
+
name: row.name,
|
59
|
+
args,
|
60
|
+
clientId: row.clientId,
|
61
|
+
sessionId: row.sessionId,
|
62
|
+
})
|
63
|
+
|
64
|
+
yield* applyEvent(eventEncoded, { skipEventlog: true })
|
65
|
+
}).pipe(Effect.withSpan(`@livestore/common:rehydrateFromEventlog:processEvent`))
|
66
|
+
|
67
|
+
const CHUNK_SIZE = 100
|
68
|
+
|
69
|
+
const stmt = dbEventlog.prepare(sql`\
|
70
|
+
SELECT * FROM ${EVENTLOG_META_TABLE}
|
71
|
+
WHERE idGlobal > $idGlobal OR (idGlobal = $idGlobal AND idClient > $idClient)
|
72
|
+
ORDER BY idGlobal ASC, idClient ASC
|
73
|
+
LIMIT ${CHUNK_SIZE}
|
74
|
+
`)
|
75
|
+
|
76
|
+
let processedEvents = 0
|
77
|
+
|
78
|
+
yield* Stream.unfoldChunk<Chunk.Chunk<EventlogMetaRow> | { _tag: 'Initial ' }, EventlogMetaRow>(
|
79
|
+
{ _tag: 'Initial ' },
|
80
|
+
(item) => {
|
81
|
+
// End stream if no more rows
|
82
|
+
if (Chunk.isChunk(item) && item.length === 0) return Option.none()
|
83
|
+
|
84
|
+
const lastId = Chunk.isChunk(item)
|
85
|
+
? Chunk.last(item).pipe(
|
86
|
+
Option.map((_) => ({ global: _.idGlobal, client: _.idClient })),
|
87
|
+
Option.getOrElse(() => EventId.ROOT),
|
88
|
+
)
|
89
|
+
: EventId.ROOT
|
90
|
+
const nextItem = Chunk.fromIterable(
|
91
|
+
stmt.select<EventlogMetaRow>({
|
92
|
+
$idGlobal: lastId?.global,
|
93
|
+
$idClient: lastId?.client,
|
94
|
+
} as any as PreparedBindValues),
|
95
|
+
)
|
96
|
+
const prevItem = Chunk.isChunk(item) ? item : Chunk.empty()
|
97
|
+
return Option.some([prevItem, nextItem])
|
98
|
+
},
|
99
|
+
).pipe(
|
100
|
+
Stream.bufferChunks({ capacity: 2 }),
|
101
|
+
Stream.tap((row) =>
|
102
|
+
Effect.gen(function* () {
|
103
|
+
yield* processEvent(row)
|
104
|
+
|
105
|
+
processedEvents++
|
106
|
+
yield* onProgress({ done: processedEvents, total: eventsCount })
|
107
|
+
}),
|
108
|
+
),
|
109
|
+
Stream.runDrain,
|
110
|
+
)
|
111
|
+
}).pipe(
|
112
|
+
Effect.withPerformanceMeasure('@livestore/common:rehydrateFromEventlog'),
|
113
|
+
Effect.withSpan('@livestore/common:rehydrateFromEventlog'),
|
114
|
+
)
|