@livestore/common 0.4.0 → 0.5.0-dev.1
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/ClientSessionLeaderThreadProxy.d.ts +1 -1
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/MaterializationJournal.d.ts +44 -0
- package/dist/MaterializationJournal.d.ts.map +1 -0
- package/dist/MaterializationJournal.js +112 -0
- package/dist/MaterializationJournal.js.map +1 -0
- package/dist/StateHead.d.ts +26 -0
- package/dist/StateHead.d.ts.map +1 -0
- package/dist/StateHead.js +50 -0
- package/dist/StateHead.js.map +1 -0
- package/dist/WorkerTransportError.d.ts +3 -3
- package/dist/WorkerTransportError.d.ts.map +1 -1
- package/dist/WorkerTransportError.js +3 -3
- package/dist/WorkerTransportError.js.map +1 -1
- package/dist/__tests__/fixture.d.ts +8 -8
- package/dist/__tests__/fixture.d.ts.map +1 -1
- package/dist/__tests__/fixture.js +4 -4
- package/dist/__tests__/fixture.js.map +1 -1
- package/dist/adapter-types.d.ts +33 -57
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js +24 -41
- package/dist/adapter-types.js.map +1 -1
- package/dist/bounded-collections.d.ts.map +1 -1
- package/dist/bounded-collections.js.map +1 -1
- package/dist/debug-info.d.ts +56 -56
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +32 -44
- package/dist/debug-info.js.map +1 -1
- package/dist/defs.d.ts +9 -9
- package/dist/defs.js +2 -2
- package/dist/devtools/devtools-compatibility.test.js +2 -1
- package/dist/devtools/devtools-compatibility.test.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +522 -334
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-client-session.js +80 -78
- package/dist/devtools/devtools-messages-client-session.js.map +1 -1
- package/dist/devtools/devtools-messages-common.d.ts +27 -27
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +6 -6
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +410 -348
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +105 -93
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/devtools/devtools-messages.js +3 -3
- package/dist/devtools/devtools-sessioninfo.d.ts +18 -19
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
- package/dist/devtools/devtools-sessioninfo.js +8 -5
- package/dist/devtools/devtools-sessioninfo.js.map +1 -1
- package/dist/devtools/mod.d.ts +4 -5
- package/dist/devtools/mod.d.ts.map +1 -1
- package/dist/devtools/mod.js +12 -8
- package/dist/devtools/mod.js.map +1 -1
- package/dist/errors.d.ts +45 -69
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +19 -17
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -19
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +87 -18
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +548 -480
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/RejectedPushError.d.ts +72 -41
- package/dist/leader-thread/RejectedPushError.d.ts.map +1 -1
- package/dist/leader-thread/RejectedPushError.js +25 -6
- package/dist/leader-thread/RejectedPushError.js.map +1 -1
- package/dist/leader-thread/connection.d.ts +1 -0
- package/dist/leader-thread/connection.d.ts.map +1 -1
- package/dist/leader-thread/connection.js +11 -10
- package/dist/leader-thread/connection.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +15 -5
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +19 -19
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +36 -20
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +15 -5
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +62 -58
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.js +9 -9
- package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -1
- package/dist/leader-thread/materialize-event.d.ts +2 -1
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +12 -8
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/mod.js +9 -9
- package/dist/leader-thread/recreate-db.d.ts +5 -1
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +34 -59
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -6
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -3
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/stream-events.d.ts +4 -7
- package/dist/leader-thread/stream-events.d.ts.map +1 -1
- package/dist/leader-thread/stream-events.js +16 -21
- package/dist/leader-thread/stream-events.js.map +1 -1
- package/dist/leader-thread/types.d.ts +38 -73
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +10 -6
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/logging.d.ts +5 -30
- package/dist/logging.d.ts.map +1 -1
- package/dist/logging.js +1 -32
- package/dist/logging.js.map +1 -1
- package/dist/make-client-session.d.ts +2 -3
- package/dist/make-client-session.d.ts.map +1 -1
- package/dist/make-client-session.js +5 -5
- package/dist/make-client-session.js.map +1 -1
- package/dist/materializer-helper.d.ts +0 -1
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js +9 -37
- package/dist/materializer-helper.js.map +1 -1
- package/dist/otel.d.ts +2 -3
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +2 -7
- package/dist/otel.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +3 -1
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +42 -33
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef/define.d.ts +6 -6
- package/dist/schema/EventDef/define.d.ts.map +1 -1
- package/dist/schema/EventDef/define.js +5 -5
- package/dist/schema/EventDef/define.js.map +1 -1
- package/dist/schema/EventDef/define.test.d.ts +2 -0
- package/dist/schema/EventDef/define.test.d.ts.map +1 -0
- package/dist/schema/EventDef/define.test.js +23 -0
- package/dist/schema/EventDef/define.test.js.map +1 -0
- package/dist/schema/EventDef/deprecated.d.ts +8 -13
- package/dist/schema/EventDef/deprecated.d.ts.map +1 -1
- package/dist/schema/EventDef/deprecated.js +12 -13
- package/dist/schema/EventDef/deprecated.js.map +1 -1
- package/dist/schema/EventDef/deprecated.test.js +3 -3
- package/dist/schema/EventDef/deprecated.test.js.map +1 -1
- package/dist/schema/EventDef/event-def.d.ts +1 -1
- package/dist/schema/EventDef/event-def.d.ts.map +1 -1
- package/dist/schema/EventDef/facts.d.ts.map +1 -1
- package/dist/schema/EventDef/materializer.d.ts +2 -2
- package/dist/schema/EventDef/materializer.d.ts.map +1 -1
- package/dist/schema/EventDef/mod.js +5 -5
- package/dist/schema/EventSequenceNumber/client.d.ts +12 -17
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -1
- package/dist/schema/EventSequenceNumber/client.js +20 -24
- package/dist/schema/EventSequenceNumber/client.js.map +1 -1
- package/dist/schema/EventSequenceNumber/global.d.ts +2 -2
- package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -1
- package/dist/schema/EventSequenceNumber/global.js +1 -1
- package/dist/schema/EventSequenceNumber/global.js.map +1 -1
- package/dist/schema/EventSequenceNumber/mod.js +2 -2
- package/dist/schema/EventSequenceNumber.test.js +6 -6
- package/dist/schema/EventSequenceNumber.test.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.d.ts +58 -187
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/client.js +33 -30
- package/dist/schema/LiveStoreEvent/client.js.map +1 -1
- package/dist/schema/LiveStoreEvent/client.test.js +13 -4
- package/dist/schema/LiveStoreEvent/client.test.js.map +1 -1
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts +7 -7
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/global.d.ts +6 -6
- package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/global.js +2 -2
- package/dist/schema/LiveStoreEvent/global.js.map +1 -1
- package/dist/schema/LiveStoreEvent/input.d.ts +6 -6
- package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -1
- package/dist/schema/LiveStoreEvent/input.js +3 -3
- package/dist/schema/LiveStoreEvent/input.js.map +1 -1
- package/dist/schema/LiveStoreEvent/mod.js +4 -4
- package/dist/schema/events.js +1 -1
- package/dist/schema/mod.d.ts +1 -0
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +11 -10
- package/dist/schema/mod.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 +6 -5
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/mod.js +2 -2
- package/dist/schema/state/sqlite/client-document-def.d.ts +13 -18
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +30 -27
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +53 -18
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.d.ts +13 -13
- package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.js +13 -15
- package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js +19 -43
- package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.d.ts +1 -1
- package/dist/schema/state/sqlite/column-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +73 -33
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +176 -75
- package/dist/schema/state/sqlite/column-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-spec.js +1 -1
- package/dist/schema/state/sqlite/column-spec.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js +4 -4
- package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.d.ts +3 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.js +5 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint-digest.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.d.ts +5 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.js +183 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.d.ts +2 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.js +142 -0
- package/dist/schema/state/sqlite/db-schema/ast/fingerprint.test.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +3 -8
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +1 -73
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/validate.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +9 -9
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js +9 -13
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js +28 -17
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts +13 -11
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +6 -4
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.d.ts +3 -0
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.d.ts.map +1 -0
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.js +6 -0
- package/dist/schema/state/sqlite/db-schema/has-json-string-encoding.js.map +1 -0
- package/dist/schema/state/sqlite/db-schema/mod.js +2 -2
- package/dist/schema/state/sqlite/mod.d.ts +1 -3
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +11 -10
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/persistence.d.ts +11 -0
- package/dist/schema/state/sqlite/persistence.d.ts.map +1 -0
- package/dist/schema/state/sqlite/persistence.js +10 -0
- package/dist/schema/state/sqlite/persistence.js.map +1 -0
- package/dist/schema/state/sqlite/query-builder/api.d.ts +7 -7
- package/dist/schema/state/sqlite/query-builder/api.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/astToSql.js +22 -23
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +18 -16
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +364 -598
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/mod.js +2 -2
- package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js +2 -2
- package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.test.js +2 -2
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts +102 -134
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts.map +1 -1
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +5 -5
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -1
- package/dist/schema/state/sqlite/system-tables/mod.js +2 -2
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +380 -115
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -1
- package/dist/schema/state/sqlite/system-tables/state-tables.js +47 -6
- package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.d.ts +17 -20
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +72 -6
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +207 -37
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts.map +1 -1
- package/dist/schema/unknown-events.js +3 -2
- package/dist/schema/unknown-events.js.map +1 -1
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +28 -6
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -1
- package/dist/schema-management/common.d.ts.map +1 -1
- package/dist/schema-management/common.js +2 -2
- package/dist/schema-management/migrations.d.ts +4 -4
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +9 -9
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-schema.d.ts.map +1 -1
- package/dist/schema-management/validate-schema.js +1 -1
- package/dist/session-id-symbol.d.ts +29 -0
- package/dist/session-id-symbol.d.ts.map +1 -0
- package/dist/session-id-symbol.js +44 -0
- package/dist/session-id-symbol.js.map +1 -0
- package/dist/sql-queries/index.js +3 -3
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js +11 -13
- package/dist/sql-queries/sql-queries.js.map +1 -1
- package/dist/sql-queries/sql-query-builder.d.ts.map +1 -1
- package/dist/sql-queries/sql-query-builder.js +1 -1
- package/dist/sql-queries/types.d.ts +6 -7
- package/dist/sql-queries/types.d.ts.map +1 -1
- package/dist/sql-queries/types.js.map +1 -1
- package/dist/sqlite-db-helper.d.ts +23 -3
- package/dist/sqlite-db-helper.d.ts.map +1 -1
- package/dist/sqlite-db-helper.js +39 -4
- package/dist/sqlite-db-helper.js.map +1 -1
- package/dist/sqlite-types.d.ts +3 -6
- package/dist/sqlite-types.d.ts.map +1 -1
- package/dist/sqlite-types.js +3 -3
- package/dist/sqlite-types.js.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +41 -19
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +200 -70
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +12 -18
- package/dist/sync/errors.d.ts.map +1 -1
- package/dist/sync/errors.js +3 -3
- package/dist/sync/errors.js.map +1 -1
- package/dist/sync/index.js +6 -6
- package/dist/sync/mock-sync-backend.d.ts +2 -3
- package/dist/sync/mock-sync-backend.d.ts.map +1 -1
- package/dist/sync/mock-sync-backend.js +58 -37
- package/dist/sync/mock-sync-backend.js.map +1 -1
- package/dist/sync/mock-sync-backend.test.d.ts +2 -0
- package/dist/sync/mock-sync-backend.test.d.ts.map +1 -0
- package/dist/sync/mock-sync-backend.test.js +49 -0
- package/dist/sync/mock-sync-backend.test.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/compact-events.js +3 -3
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +1 -1
- package/dist/sync/next/history-dag-common.d.ts +5 -1
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +53 -32
- 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 +5 -4
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/mod.js +5 -5
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +2 -2
- package/dist/sync/next/test/compact-events.calculator.test.js +6 -6
- package/dist/sync/next/test/compact-events.test.js +4 -4
- package/dist/sync/next/test/event-fixtures.d.ts +8 -8
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +6 -6
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/sync/next/test/history-dag-common.test.d.ts +2 -0
- package/dist/sync/next/test/history-dag-common.test.d.ts.map +1 -0
- package/dist/sync/next/test/history-dag-common.test.js +73 -0
- package/dist/sync/next/test/history-dag-common.test.js.map +1 -0
- package/dist/sync/next/test/mod.js +1 -1
- package/dist/sync/sync-backend-kv.d.ts.map +1 -1
- package/dist/sync/sync-backend-kv.js +5 -3
- package/dist/sync/sync-backend-kv.js.map +1 -1
- package/dist/sync/sync-backend.d.ts +15 -15
- package/dist/sync/sync-backend.d.ts.map +1 -1
- package/dist/sync/sync-backend.js +10 -6
- package/dist/sync/sync-backend.js.map +1 -1
- package/dist/sync/sync.d.ts +1 -1
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js +2 -2
- package/dist/sync/syncstate.d.ts +100 -176
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +36 -39
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +103 -64
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/transport-chunking.d.ts +15 -16
- package/dist/sync/transport-chunking.d.ts.map +1 -1
- package/dist/sync/transport-chunking.js +23 -32
- package/dist/sync/transport-chunking.js.map +1 -1
- package/dist/sync/validate-push-payload.d.ts.map +1 -1
- package/dist/sync/validate-push-payload.js +2 -2
- package/dist/testing/event-factory.d.ts.map +1 -1
- package/dist/testing/event-factory.js +2 -2
- package/dist/testing/event-factory.js.map +1 -1
- package/dist/testing/mod.js +1 -1
- package/dist/util.d.ts +11 -4
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +20 -2
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +40 -57
- package/src/ClientSessionLeaderThreadProxy.ts +1 -1
- package/src/MaterializationJournal.ts +184 -0
- package/src/StateHead.ts +80 -0
- package/src/WorkerTransportError.ts +4 -4
- package/src/__tests__/fixture.ts +3 -3
- package/src/adapter-types.ts +28 -61
- package/src/debug-info.ts +53 -70
- package/src/defs.ts +2 -2
- package/src/devtools/devtools-compatibility.test.ts +1 -0
- package/src/devtools/devtools-messages-client-session.ts +56 -65
- package/src/devtools/devtools-messages-common.ts +12 -11
- package/src/devtools/devtools-messages-leader.ts +71 -69
- package/src/devtools/devtools-sessioninfo.ts +13 -11
- package/src/devtools/mod.ts +4 -5
- package/src/errors.ts +46 -34
- package/src/index.ts +8 -1
- package/src/leader-thread/LeaderSyncProcessor.ts +777 -650
- package/src/leader-thread/RejectedPushError.ts +40 -27
- package/src/leader-thread/connection.ts +12 -8
- package/src/leader-thread/eventlog.ts +20 -12
- package/src/leader-thread/leader-worker-devtools.ts +38 -20
- package/src/leader-thread/make-leader-thread-layer.test.ts +7 -7
- package/src/leader-thread/make-leader-thread-layer.ts +100 -71
- package/src/leader-thread/materialize-event.ts +13 -8
- package/src/leader-thread/recreate-db.ts +41 -75
- package/src/leader-thread/shutdown-channel.ts +3 -14
- package/src/leader-thread/stream-events.ts +102 -101
- package/src/leader-thread/types.ts +29 -62
- package/src/logging.ts +5 -52
- package/src/make-client-session.ts +6 -6
- package/src/materializer-helper.ts +7 -36
- package/src/otel.ts +5 -14
- package/src/rematerialize-from-eventlog.ts +116 -98
- package/src/schema/EventDef/define.test.ts +28 -0
- package/src/schema/EventDef/define.ts +20 -19
- package/src/schema/EventDef/deprecated.test.ts +1 -8
- package/src/schema/EventDef/deprecated.ts +17 -20
- package/src/schema/EventDef/event-def.ts +2 -4
- package/src/schema/EventSequenceNumber/client.ts +20 -24
- package/src/schema/EventSequenceNumber/global.ts +1 -1
- package/src/schema/EventSequenceNumber.test.ts +5 -5
- package/src/schema/LiveStoreEvent/client.test.ts +17 -4
- package/src/schema/LiveStoreEvent/client.ts +36 -35
- package/src/schema/LiveStoreEvent/for-event-def.ts +7 -7
- package/src/schema/LiveStoreEvent/global.ts +1 -1
- package/src/schema/LiveStoreEvent/input.ts +6 -6
- package/src/schema/mod.ts +1 -0
- package/src/schema/schema.ts +4 -3
- package/src/schema/state/sqlite/client-document-def.test.ts +55 -20
- package/src/schema/state/sqlite/client-document-def.ts +95 -80
- package/src/schema/state/sqlite/column-annotations.test.ts +26 -45
- package/src/schema/state/sqlite/column-annotations.ts +26 -30
- package/src/schema/state/sqlite/column-def.test.ts +213 -77
- package/src/schema/state/sqlite/column-def.ts +87 -37
- package/src/schema/state/sqlite/column-spec.test.ts +2 -2
- package/src/schema/state/sqlite/column-spec.ts +3 -2
- package/src/schema/state/sqlite/db-schema/ast/fingerprint-digest.ts +6 -0
- package/src/schema/state/sqlite/db-schema/ast/fingerprint.test.ts +209 -0
- package/src/schema/state/sqlite/db-schema/ast/fingerprint.ts +225 -0
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +2 -81
- package/src/schema/state/sqlite/db-schema/dsl/__snapshots__/field-defs.test.ts.snap +123 -63
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.test.ts +35 -16
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +26 -31
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +35 -21
- package/src/schema/state/sqlite/db-schema/has-json-string-encoding.ts +9 -0
- package/src/schema/state/sqlite/mod.ts +4 -5
- package/src/schema/state/sqlite/persistence.ts +11 -0
- package/src/schema/state/sqlite/query-builder/api.ts +9 -9
- package/src/schema/state/sqlite/query-builder/astToSql.ts +24 -26
- package/src/schema/state/sqlite/query-builder/impl.test.ts +433 -669
- package/src/schema/state/sqlite/query-builder/impl.ts +19 -15
- package/src/schema/state/sqlite/schema-helpers.ts +1 -1
- package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +2 -2
- package/src/schema/state/sqlite/system-tables/state-tables.ts +54 -3
- package/src/schema/state/sqlite/table-def.test.ts +270 -66
- package/src/schema/state/sqlite/table-def.ts +112 -45
- package/src/schema/unknown-events.ts +3 -2
- package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +35 -4
- package/src/schema-management/migrations.ts +7 -6
- package/src/session-id-symbol.ts +59 -0
- package/src/sql-queries/sql-queries.ts +9 -13
- package/src/sql-queries/types.ts +6 -7
- package/src/sqlite-db-helper.ts +64 -2
- package/src/sqlite-types.ts +5 -8
- package/src/sync/ClientSessionSyncProcessor.ts +303 -119
- package/src/sync/errors.ts +14 -12
- package/src/sync/mock-sync-backend.test.ts +78 -0
- package/src/sync/mock-sync-backend.ts +93 -47
- package/src/sync/next/history-dag-common.ts +60 -34
- package/src/sync/next/history-dag.ts +4 -1
- package/src/sync/next/test/compact-events.calculator.test.ts +2 -2
- package/src/sync/next/test/event-fixtures.ts +1 -1
- package/src/sync/next/test/history-dag-common.test.ts +87 -0
- package/src/sync/sync-backend-kv.ts +4 -2
- package/src/sync/sync-backend.ts +15 -15
- package/src/sync/sync.ts +1 -1
- package/src/sync/syncstate.test.ts +191 -140
- package/src/sync/syncstate.ts +63 -53
- package/src/sync/transport-chunking.ts +34 -39
- package/src/util.ts +19 -9
- package/src/version.ts +1 -2
- package/dist/schema/state/sqlite/db-schema/hash.d.ts +0 -2
- package/dist/schema/state/sqlite/db-schema/hash.d.ts.map +0 -1
- package/dist/schema/state/sqlite/db-schema/hash.js +0 -15
- package/dist/schema/state/sqlite/db-schema/hash.js.map +0 -1
- package/dist/sql-queries/misc.d.ts +0 -2
- package/dist/sql-queries/misc.d.ts.map +0 -1
- package/dist/sql-queries/misc.js +0 -2
- package/dist/sql-queries/misc.js.map +0 -1
- package/src/schema/state/sqlite/db-schema/hash.ts +0 -13
- package/src/sql-queries/misc.ts +0 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Nullable, shouldNeverHappen } from '@livestore/utils'
|
|
2
|
-
import {
|
|
2
|
+
import type { Schema } from '@livestore/utils/effect'
|
|
3
|
+
import { SchemaAST, type Types } from '@livestore/utils/effect'
|
|
3
4
|
|
|
4
5
|
import { getColumnDefForSchema, schemaFieldsToColumns } from './column-def.ts'
|
|
5
6
|
import { SqliteDsl } from './db-schema/mod.ts'
|
|
@@ -38,29 +39,17 @@ export type TableDef<
|
|
|
38
39
|
// https://github.com/livestorejs/livestore/issues/382
|
|
39
40
|
TSqliteDef extends DefaultSqliteTableDef = DefaultSqliteTableDefConstrained,
|
|
40
41
|
TOptions extends TableOptions = TableOptions,
|
|
41
|
-
|
|
42
|
-
// as we don't want the alias type for users to show up, so we're redefining it here
|
|
43
|
-
// TODO adjust this to `TSchema = Schema.TypeLiteral<` but requires some advance type-level work
|
|
44
|
-
TSchema = Schema.Schema<
|
|
45
|
-
SqliteDsl.AnyIfConstained<
|
|
46
|
-
TSqliteDef['columns'],
|
|
47
|
-
{ readonly [K in keyof TSqliteDef['columns']]: TSqliteDef['columns'][K]['schema']['Type'] }
|
|
48
|
-
>,
|
|
49
|
-
SqliteDsl.AnyIfConstained<
|
|
50
|
-
TSqliteDef['columns'],
|
|
51
|
-
{ readonly [K in keyof TSqliteDef['columns']]: TSqliteDef['columns'][K]['schema']['Encoded'] }
|
|
52
|
-
>
|
|
53
|
-
>,
|
|
42
|
+
TSchema extends Schema.Top = Schema.Struct<SqliteDsl.StructFieldsForColumns<TSqliteDef['columns']>>,
|
|
54
43
|
> = {
|
|
55
44
|
sqliteDef: TSqliteDef
|
|
56
45
|
options: TOptions
|
|
57
46
|
// Derived from `sqliteDef`, so only exposed for convenience
|
|
58
47
|
rowSchema: TSchema
|
|
59
48
|
insertSchema: SqliteDsl.InsertStructSchemaForColumns<TSqliteDef['columns']>
|
|
60
|
-
// query: QueryBuilder<ReadonlyArray<
|
|
61
|
-
readonly Type:
|
|
62
|
-
readonly Encoded:
|
|
63
|
-
} & QueryBuilder<ReadonlyArray<
|
|
49
|
+
// query: QueryBuilder<ReadonlyArray<TSchema['Type']>>, TableDefBase<TSqliteDef & {}, TOptions>>
|
|
50
|
+
readonly Type: TSchema['Type']
|
|
51
|
+
readonly Encoded: TSchema['Encoded']
|
|
52
|
+
} & QueryBuilder<ReadonlyArray<TSchema['Type']>, TableDefBase<TSqliteDef & {}, TOptions>>
|
|
64
53
|
|
|
65
54
|
export type TableOptionsInput = Partial<{
|
|
66
55
|
indexes: SqliteDsl.Index[]
|
|
@@ -114,7 +103,7 @@ export type TableOptions = {
|
|
|
114
103
|
* })
|
|
115
104
|
*
|
|
116
105
|
* // Option 2: With name from schema annotation (title or identifier)
|
|
117
|
-
* const AnnotatedUserSchema = UserSchema.
|
|
106
|
+
* const AnnotatedUserSchema = UserSchema.annotate({ title: 'users' })
|
|
118
107
|
* const usersTable2 = State.SQLite.table({
|
|
119
108
|
* schema: AnnotatedUserSchema,
|
|
120
109
|
* })
|
|
@@ -127,7 +116,7 @@ export type TableOptions = {
|
|
|
127
116
|
* title: Schema.String,
|
|
128
117
|
* authorId: Schema.String,
|
|
129
118
|
* createdAt: Schema.Date,
|
|
130
|
-
* }).
|
|
119
|
+
* }).annotate({ identifier: 'posts' })
|
|
131
120
|
*
|
|
132
121
|
* const postsTable = State.SQLite.table({
|
|
133
122
|
* schema: PostSchema,
|
|
@@ -161,24 +150,21 @@ export function table<
|
|
|
161
150
|
// Overload 2: With schema and explicit name
|
|
162
151
|
export function table<
|
|
163
152
|
TName extends string,
|
|
164
|
-
TSchema extends Schema.
|
|
153
|
+
TSchema extends Schema.Top,
|
|
165
154
|
const TOptionsInput extends TableOptionsInput = TableOptionsInput,
|
|
166
155
|
>(
|
|
167
156
|
args: {
|
|
168
157
|
name: TName
|
|
169
158
|
schema: TSchema
|
|
170
159
|
} & Partial<TOptionsInput>,
|
|
171
|
-
): TableDef<SqliteTableDefForSchemaInput<TName,
|
|
160
|
+
): TableDef<SqliteTableDefForSchemaInput<TName, TSchema['Type'], TSchema['Encoded'], TSchema>>
|
|
172
161
|
|
|
173
162
|
// Overload 3: With schema and no name (uses schema annotations)
|
|
174
|
-
export function table<
|
|
175
|
-
TSchema extends Schema.Schema.AnyNoContext,
|
|
176
|
-
const TOptionsInput extends TableOptionsInput = TableOptionsInput,
|
|
177
|
-
>(
|
|
163
|
+
export function table<TSchema extends Schema.Top, const TOptionsInput extends TableOptionsInput = TableOptionsInput>(
|
|
178
164
|
args: {
|
|
179
165
|
schema: TSchema
|
|
180
166
|
} & Partial<TOptionsInput>,
|
|
181
|
-
): TableDef<SqliteTableDefForSchemaInput<string,
|
|
167
|
+
): TableDef<SqliteTableDefForSchemaInput<string, TSchema['Type'], TSchema['Encoded'], TSchema>>
|
|
182
168
|
|
|
183
169
|
// Implementation
|
|
184
170
|
export function table<
|
|
@@ -193,10 +179,10 @@ export function table<
|
|
|
193
179
|
}
|
|
194
180
|
| {
|
|
195
181
|
name: TName
|
|
196
|
-
schema: Schema.
|
|
182
|
+
schema: Schema.Top
|
|
197
183
|
}
|
|
198
184
|
| {
|
|
199
|
-
schema: Schema.
|
|
185
|
+
schema: Schema.Top
|
|
200
186
|
}
|
|
201
187
|
) &
|
|
202
188
|
Partial<TOptionsInput>,
|
|
@@ -213,7 +199,7 @@ export function table<
|
|
|
213
199
|
columns = SqliteDsl.isColumnDefinition(columnOrColumns) === true ? { value: columnOrColumns } : columnOrColumns
|
|
214
200
|
additionalIndexes = []
|
|
215
201
|
} else if ('schema' in args) {
|
|
216
|
-
const result =
|
|
202
|
+
const result = args.schema.pipe(getSqlitePropertySignatures, schemaFieldsToColumns)
|
|
217
203
|
columns = result.columns
|
|
218
204
|
|
|
219
205
|
// We'll set tableName first, then use it for index names
|
|
@@ -224,14 +210,12 @@ export function table<
|
|
|
224
210
|
tempTableName = args.name
|
|
225
211
|
} else {
|
|
226
212
|
// Use title or identifier, with preference for title
|
|
227
|
-
tempTableName =
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
),
|
|
234
|
-
)
|
|
213
|
+
tempTableName =
|
|
214
|
+
SchemaAST.resolveTitle(args.schema.ast) ??
|
|
215
|
+
SchemaAST.resolveIdentifier(args.schema.ast) ??
|
|
216
|
+
shouldNeverHappen(
|
|
217
|
+
'When using schema without explicit name, the schema must have a title or identifier annotation',
|
|
218
|
+
)
|
|
235
219
|
}
|
|
236
220
|
|
|
237
221
|
tableName = tempTableName
|
|
@@ -281,6 +265,90 @@ export function table<
|
|
|
281
265
|
return tableDef as any
|
|
282
266
|
}
|
|
283
267
|
|
|
268
|
+
/**
|
|
269
|
+
* The encoded side of the schema decides which columns exist (a transformation may flatten a nested
|
|
270
|
+
* type into columns). Where the schema itself declares a property of the same name, that property's
|
|
271
|
+
* own AST becomes the column schema: it still carries the field's encoding, so a codec such as
|
|
272
|
+
* `Schema.DateFromString` or `Schema.DateFromMillis` stores its encoded form and decodes back to
|
|
273
|
+
* its type. Substituting the type-side AST instead would strip that encoding and leave a `Date`
|
|
274
|
+
* with nothing SQLite can store natively, which is how date columns ended up JSON-encoded and
|
|
275
|
+
* unreadable.
|
|
276
|
+
*/
|
|
277
|
+
const getSqlitePropertySignatures = (schema: Schema.Top): ReadonlyArray<SchemaAST.PropertySignature> => {
|
|
278
|
+
const encodedPropertySignatures = getPropertySignatures(SchemaAST.toEncoded(schema.ast))
|
|
279
|
+
const ownPropertySignatures = getPropertySignatures(schema.ast)
|
|
280
|
+
|
|
281
|
+
return encodedPropertySignatures.map((encodedPropertySignature) => {
|
|
282
|
+
const ownPropertySignature = ownPropertySignatures.find(
|
|
283
|
+
(propertySignature) => propertySignature.name === encodedPropertySignature.name,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
if (ownPropertySignature === undefined || hasLiveStoreSqliteAnnotation(encodedPropertySignature.type) === true) {
|
|
287
|
+
return encodedPropertySignature
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return ownPropertySignature
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const getPropertySignatures = (ast: SchemaAST.AST): ReadonlyArray<SchemaAST.PropertySignature> => {
|
|
295
|
+
if (SchemaAST.isObjects(ast) === true) return ast.propertySignatures
|
|
296
|
+
|
|
297
|
+
// Class declarations encode through their fields object. Inspect that first
|
|
298
|
+
// link before toEncoded strips the individual field codecs.
|
|
299
|
+
if (SchemaAST.isDeclaration(ast) === true) {
|
|
300
|
+
const fieldsAst = ast.encoding?.[0]?.to
|
|
301
|
+
if (fieldsAst !== undefined) return getPropertySignatures(fieldsAst)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (SchemaAST.isUnion(ast) === true) {
|
|
305
|
+
const members = ast.types.map(getPropertySignatures)
|
|
306
|
+
const [head, ...tail] = members
|
|
307
|
+
if (head === undefined) return []
|
|
308
|
+
|
|
309
|
+
return head.flatMap((propertySignature) => {
|
|
310
|
+
const matchingPropertySignatures: Array<SchemaAST.PropertySignature> = []
|
|
311
|
+
for (const propertySignatures of tail) {
|
|
312
|
+
const matchingPropertySignature = propertySignatures.find(
|
|
313
|
+
(memberPropertySignature) => memberPropertySignature.name === propertySignature.name,
|
|
314
|
+
)
|
|
315
|
+
if (matchingPropertySignature === undefined) {
|
|
316
|
+
return []
|
|
317
|
+
}
|
|
318
|
+
matchingPropertySignatures.push(matchingPropertySignature)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const propertySignatures = [propertySignature, ...matchingPropertySignatures]
|
|
322
|
+
/**
|
|
323
|
+
* `SchemaAST.optionalKey` became internal in Effect rc.109, so the optional-key marker is
|
|
324
|
+
* applied by constructing the union with an optional `Context`. Equivalent here because the
|
|
325
|
+
* union is freshly built and therefore carries no encoding chain to propagate the marker to.
|
|
326
|
+
*/
|
|
327
|
+
const hasOptionalMember =
|
|
328
|
+
propertySignatures.some((memberPropertySignature) => SchemaAST.isOptional(memberPropertySignature.type)) ===
|
|
329
|
+
true
|
|
330
|
+
const keyContext = hasOptionalMember === true ? new SchemaAST.Context(true, false) : undefined
|
|
331
|
+
const union = new SchemaAST.Union(
|
|
332
|
+
propertySignatures.map((memberPropertySignature) => memberPropertySignature.type),
|
|
333
|
+
ast.options,
|
|
334
|
+
undefined,
|
|
335
|
+
undefined,
|
|
336
|
+
undefined,
|
|
337
|
+
keyContext,
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
return [new SchemaAST.PropertySignature(propertySignature.name, union)]
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return []
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const hasLiveStoreSqliteAnnotation = (ast: SchemaAST.AST): boolean => {
|
|
348
|
+
const annotationKeys = [...Object.keys(ast.annotations ?? {}), ...Object.keys(ast.context?.annotations ?? {})]
|
|
349
|
+
return annotationKeys.some((key) => key.startsWith('livestore/state/sqlite/annotations/'))
|
|
350
|
+
}
|
|
351
|
+
|
|
284
352
|
export namespace FromTable {
|
|
285
353
|
// TODO this sometimes doesn't preserve the order of columns
|
|
286
354
|
export type RowDecoded<TTableDef extends TableDefBase> = Types.Simplify<
|
|
@@ -297,9 +365,7 @@ export namespace FromTable {
|
|
|
297
365
|
}
|
|
298
366
|
|
|
299
367
|
export type RowEncodeNonNullable<TTableDef extends TableDefBase> = {
|
|
300
|
-
[K in keyof TTableDef['sqliteDef']['columns']]:
|
|
301
|
-
TTableDef['sqliteDef']['columns'][K]['schema']
|
|
302
|
-
>
|
|
368
|
+
[K in keyof TTableDef['sqliteDef']['columns']]: TTableDef['sqliteDef']['columns'][K]['schema']['Encoded']
|
|
303
369
|
}
|
|
304
370
|
|
|
305
371
|
export type RowEncoded<TTableDef extends TableDefBase> = Types.Simplify<
|
|
@@ -308,7 +374,7 @@ export namespace FromTable {
|
|
|
308
374
|
>
|
|
309
375
|
|
|
310
376
|
export type RowDecodedAll<TTableDef extends TableDefBase> = {
|
|
311
|
-
[K in keyof TTableDef['sqliteDef']['columns']]:
|
|
377
|
+
[K in keyof TTableDef['sqliteDef']['columns']]: TTableDef['sqliteDef']['columns'][K]['schema']['Type']
|
|
312
378
|
}
|
|
313
379
|
}
|
|
314
380
|
|
|
@@ -320,7 +386,7 @@ export namespace FromColumns {
|
|
|
320
386
|
>
|
|
321
387
|
|
|
322
388
|
export type RowDecodedAll<TColumns extends SqliteDsl.Columns> = {
|
|
323
|
-
[K in keyof TColumns]:
|
|
389
|
+
[K in keyof TColumns]: TColumns[K]['schema']['Type']
|
|
324
390
|
}
|
|
325
391
|
|
|
326
392
|
export type RowEncoded<TColumns extends SqliteDsl.Columns> = Types.Simplify<
|
|
@@ -329,7 +395,7 @@ export namespace FromColumns {
|
|
|
329
395
|
>
|
|
330
396
|
|
|
331
397
|
export type RowEncodeNonNullable<TColumns extends SqliteDsl.Columns> = {
|
|
332
|
-
[K in keyof TColumns]:
|
|
398
|
+
[K in keyof TColumns]: TColumns[K]['schema']['Encoded']
|
|
333
399
|
}
|
|
334
400
|
|
|
335
401
|
export type NullableColumnNames<TColumns extends SqliteDsl.Columns> = keyof {
|
|
@@ -378,7 +444,8 @@ export declare namespace SchemaToColumns {
|
|
|
378
444
|
export type FromTypes<TType, TEncoded> =
|
|
379
445
|
TEncoded extends Record<string, any>
|
|
380
446
|
? {
|
|
381
|
-
[K in keyof TEncoded]-?: ColumnDefForType<
|
|
447
|
+
[K in keyof TEncoded]-?: ColumnDefForType<
|
|
448
|
+
TEncoded[K],
|
|
382
449
|
TType extends Record<string, any> ? (K extends keyof TType ? TType[K] : TEncoded[K]) : TEncoded[K]
|
|
383
450
|
>
|
|
384
451
|
}
|
|
@@ -72,8 +72,9 @@ const handleUnknownEvent = ({
|
|
|
72
72
|
case 'callback': {
|
|
73
73
|
const callback = config.onUnknownEvent
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// @effect-diagnostics-next-line anyUnknownInErrorContext:off -- user callback errors are immediately handled and logged below
|
|
76
|
+
yield* Effect.trySyncOrPromiseOrEffect(() => callback(context, error)).pipe(
|
|
77
|
+
Effect.catch((cause) =>
|
|
77
78
|
Effect.logWarning('@livestore/common:schema:unknown-event:callback-error', {
|
|
78
79
|
event: context.event,
|
|
79
80
|
reason: context.reason,
|
|
@@ -2,13 +2,16 @@ import { describe, expect, it } from 'vitest'
|
|
|
2
2
|
|
|
3
3
|
import { Effect, Option, Schema } from '@livestore/utils/effect'
|
|
4
4
|
|
|
5
|
+
import { fingerprint } from '../../schema/state/sqlite/db-schema/ast/fingerprint.ts'
|
|
5
6
|
import { SqliteAst } from '../../schema/state/sqlite/db-schema/mod.ts'
|
|
7
|
+
import { schemaMetaTable } from '../../schema/state/sqlite/system-tables/state-tables.ts'
|
|
6
8
|
import type { PreparedStatement, SqliteDb } from '../../sqlite-types.ts'
|
|
7
9
|
import type { PreparedBindValues } from '../../util.ts'
|
|
8
10
|
import { migrateTable } from '../migrations.ts'
|
|
9
11
|
|
|
10
12
|
const makeStubDb = () => {
|
|
11
13
|
const executed: string[] = []
|
|
14
|
+
const bindings: Array<PreparedBindValues | undefined> = []
|
|
12
15
|
|
|
13
16
|
const db: SqliteDb = {
|
|
14
17
|
_tag: 'SqliteDb',
|
|
@@ -16,8 +19,9 @@ const makeStubDb = () => {
|
|
|
16
19
|
debug: { head: 0 as any },
|
|
17
20
|
prepare: (queryStr: string): PreparedStatement => ({
|
|
18
21
|
sql: queryStr,
|
|
19
|
-
execute: (
|
|
22
|
+
execute: (bind: PreparedBindValues | undefined) => {
|
|
20
23
|
executed.push(queryStr)
|
|
24
|
+
bindings.push(bind)
|
|
21
25
|
},
|
|
22
26
|
select: <T>(_bind: PreparedBindValues | undefined) => [] as unknown as ReadonlyArray<T>,
|
|
23
27
|
finalize: () => {},
|
|
@@ -32,7 +36,7 @@ const makeStubDb = () => {
|
|
|
32
36
|
makeChangeset: () => ({ invert: () => ({ invert: () => ({}) as any, apply: () => {} }) as any, apply: () => {} }),
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
return { db, executed }
|
|
39
|
+
return { db, executed, bindings }
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
describe('migrateTable - quoting and autoincrement', () => {
|
|
@@ -49,7 +53,7 @@ describe('migrateTable - quoting and autoincrement', () => {
|
|
|
49
53
|
primaryKey: true,
|
|
50
54
|
autoIncrement: true,
|
|
51
55
|
default: Option.none(),
|
|
52
|
-
schema: Schema.
|
|
56
|
+
schema: Schema.Finite,
|
|
53
57
|
}),
|
|
54
58
|
SqliteAst.column({
|
|
55
59
|
name: 'text',
|
|
@@ -67,7 +71,7 @@ describe('migrateTable - quoting and autoincrement', () => {
|
|
|
67
71
|
primaryKey: false,
|
|
68
72
|
autoIncrement: false,
|
|
69
73
|
default: Option.some(0),
|
|
70
|
-
schema: Schema.
|
|
74
|
+
schema: Schema.Finite,
|
|
71
75
|
}),
|
|
72
76
|
],
|
|
73
77
|
[],
|
|
@@ -85,4 +89,31 @@ describe('migrateTable - quoting and autoincrement', () => {
|
|
|
85
89
|
expect(createStmt!).not.toContain("PRIMARY KEY ('id')")
|
|
86
90
|
expect(createStmt!).not.toMatch(/'todos'|'id'|'text'/)
|
|
87
91
|
})
|
|
92
|
+
|
|
93
|
+
it('persists full textual table fingerprints', () => {
|
|
94
|
+
const { db, bindings } = makeStubDb()
|
|
95
|
+
const table = SqliteAst.table(
|
|
96
|
+
'todos',
|
|
97
|
+
[
|
|
98
|
+
SqliteAst.column({
|
|
99
|
+
name: 'id',
|
|
100
|
+
type: { _tag: 'text' },
|
|
101
|
+
nullable: false,
|
|
102
|
+
primaryKey: true,
|
|
103
|
+
autoIncrement: false,
|
|
104
|
+
default: Option.none(),
|
|
105
|
+
schema: Schema.String,
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
108
|
+
[],
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
migrateTable({ db, tableAst: table, behaviour: 'create-if-not-exists' }).pipe(Effect.runSync)
|
|
112
|
+
|
|
113
|
+
const schemaMetaBinding = bindings.find(
|
|
114
|
+
(binding) => binding !== undefined && Array.isArray(binding) === false && '$schemaHash' in binding,
|
|
115
|
+
)
|
|
116
|
+
expect(schemaMetaBinding).toMatchObject({ $schemaHash: fingerprint(table) })
|
|
117
|
+
expect(schemaMetaTable.sqliteDef.ast.columns.find((column) => column.name === 'schemaHash')?.type._tag).toBe('text')
|
|
118
|
+
})
|
|
88
119
|
})
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - EVENTLOG TABLES (NEVER modify): Changes cause data loss - need manual versioning!
|
|
9
9
|
*
|
|
10
10
|
* How it works:
|
|
11
|
-
* 1. Each table's schema is
|
|
11
|
+
* 1. Each table's schema is fingerprinted
|
|
12
12
|
* 2. Hashes are stored in SCHEMA_META_TABLE after successful migrations
|
|
13
13
|
* 3. On app start, current schema hashes are compared with stored hashes
|
|
14
14
|
* 4. Mismatches trigger migrations:
|
|
@@ -37,7 +37,8 @@ import type { MigrationsReport, MigrationsReportEntry } from '../defs.ts'
|
|
|
37
37
|
import type { UnknownError } from '../errors.ts'
|
|
38
38
|
import type { LiveStoreSchema } from '../schema/mod.ts'
|
|
39
39
|
import { makeColumnSpec } from '../schema/state/sqlite/column-spec.ts'
|
|
40
|
-
import {
|
|
40
|
+
import { fingerprint } from '../schema/state/sqlite/db-schema/ast/fingerprint.ts'
|
|
41
|
+
import type { SqliteAst } from '../schema/state/sqlite/db-schema/mod.ts'
|
|
41
42
|
import type { SchemaEventDefsMetaRow, SchemaMetaRow } from '../schema/state/sqlite/system-tables/state-tables.ts'
|
|
42
43
|
import {
|
|
43
44
|
isStateSystemTable,
|
|
@@ -114,14 +115,14 @@ export const migrateDb = ({
|
|
|
114
115
|
...Array.from(schema.state.sqlite.tables.values()).filter((_) => !isStateSystemTable(_.sqliteDef.name)),
|
|
115
116
|
]
|
|
116
117
|
|
|
117
|
-
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash:
|
|
118
|
+
const tablesToMigrate = new Set<{ tableAst: SqliteAst.Table; schemaHash: string }>()
|
|
118
119
|
|
|
119
120
|
const migrationsReportEntries: MigrationsReportEntry[] = []
|
|
120
121
|
for (const tableDef of tableDefs) {
|
|
121
122
|
const tableAst = tableDef.sqliteDef.ast
|
|
122
123
|
const tableName = tableAst.name
|
|
123
124
|
const dbSchemaHash = dbSchemaHashByTable[tableName]
|
|
124
|
-
const schemaHash =
|
|
125
|
+
const schemaHash = fingerprint(tableAst)
|
|
125
126
|
|
|
126
127
|
if (schemaHash !== dbSchemaHash) {
|
|
127
128
|
tablesToMigrate.add({ tableAst, schemaHash })
|
|
@@ -151,13 +152,13 @@ export const migrateDb = ({
|
|
|
151
152
|
export const migrateTable = ({
|
|
152
153
|
db,
|
|
153
154
|
tableAst,
|
|
154
|
-
schemaHash =
|
|
155
|
+
schemaHash = fingerprint(tableAst),
|
|
155
156
|
behaviour,
|
|
156
157
|
skipMetaTable = false,
|
|
157
158
|
}: {
|
|
158
159
|
db: SqliteDb
|
|
159
160
|
tableAst: SqliteAst.Table
|
|
160
|
-
schemaHash?:
|
|
161
|
+
schemaHash?: string
|
|
161
162
|
behaviour: 'drop-and-recreate' | 'create-if-not-exists'
|
|
162
163
|
skipMetaTable?: boolean
|
|
163
164
|
}) =>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionIdSymbol is a user-facing placeholder for "the current client session".
|
|
3
|
+
* User code can keep using the same event/query object across sessions, while the
|
|
4
|
+
* storage and eventlog layers require concrete string ids. Resolving the symbol at
|
|
5
|
+
* those boundaries preserves the symbolic API without mutating caller-owned values.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import { Predicate } from '@livestore/utils/effect'
|
|
10
|
+
|
|
11
|
+
import type { Bindable, SqlValue } from './util.ts'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Can be used in queries to refer to the current session id.
|
|
15
|
+
* Will be replaced with the actual session id at runtime.
|
|
16
|
+
*
|
|
17
|
+
* In client document table:
|
|
18
|
+
* ```ts
|
|
19
|
+
* const uiState = State.SQLite.clientDocument({
|
|
20
|
+
* name: 'ui_state',
|
|
21
|
+
* schema: Schema.Struct({
|
|
22
|
+
* theme: Schema.Literals(['dark', 'light', 'system']),
|
|
23
|
+
* user: Schema.String,
|
|
24
|
+
* showToolbar: Schema.Boolean,
|
|
25
|
+
* }),
|
|
26
|
+
* default: { value: defaultFrontendState, id: SessionIdSymbol },
|
|
27
|
+
* })
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* Or in a client document query:
|
|
31
|
+
* ```ts
|
|
32
|
+
* const query$ = queryDb(tables.uiState.get(SessionIdSymbol))
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const SessionIdSymbol = Symbol.for('@livestore/session-id')
|
|
36
|
+
export type SessionIdSymbol = typeof SessionIdSymbol
|
|
37
|
+
|
|
38
|
+
export type BindableWithSessionIdSymbol =
|
|
39
|
+
| ReadonlyArray<SqlValue | SessionIdSymbol>
|
|
40
|
+
| Record<string, SqlValue | SessionIdSymbol>
|
|
41
|
+
|
|
42
|
+
export const resolveSessionIdSymbolInBindValues = (
|
|
43
|
+
bindValues: BindableWithSessionIdSymbol,
|
|
44
|
+
sessionId: string,
|
|
45
|
+
): Bindable => {
|
|
46
|
+
return Array.isArray(bindValues) === true
|
|
47
|
+
? bindValues.map((value) => (value === SessionIdSymbol ? sessionId : value))
|
|
48
|
+
: (Object.fromEntries(
|
|
49
|
+
Object.entries(bindValues).map(([key, value]) => [key, value === SessionIdSymbol ? sessionId : value]),
|
|
50
|
+
) as Record<string, SqlValue>)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const resolveSessionIdSymbolInEventArgs = (args: unknown, sessionId: string): unknown => {
|
|
54
|
+
if (Predicate.hasProperty(args, 'id') === false) {
|
|
55
|
+
return args
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return args.id === SessionIdSymbol ? { ...args, id: sessionId } : args
|
|
59
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
|
-
import { pipe, ReadonlyArray, Schema,
|
|
2
|
+
import { pipe, ReadonlyArray, ReadonlyRecord, Result, Schema, SchemaIssue } from '@livestore/utils/effect'
|
|
3
3
|
|
|
4
4
|
import type { SqliteDsl } from '../schema/state/sqlite/db-schema/mod.ts'
|
|
5
5
|
import { sql } from '../util.ts'
|
|
6
|
-
import { objectEntries } from './misc.ts'
|
|
7
6
|
import * as ClientTypes from './types.ts'
|
|
8
7
|
|
|
9
8
|
export type BindValues = {
|
|
@@ -106,7 +105,6 @@ export const insertRows = <TColumns extends SqliteDsl.Columns>({
|
|
|
106
105
|
|
|
107
106
|
const bindValues = valuesArray.reduce(
|
|
108
107
|
(acc, values, itemIndex) => ({
|
|
109
|
-
// biome-ignore lint/performance/noAccumulatingSpread: TODO improve this some day
|
|
110
108
|
...acc,
|
|
111
109
|
...makeBindValues({ columns, values, variablePrefix: `item_${itemIndex}_` }),
|
|
112
110
|
}),
|
|
@@ -279,15 +277,14 @@ export const makeBindValues = <TColumns extends SqliteDsl.Columns, TKeys extends
|
|
|
279
277
|
skipNil?: boolean
|
|
280
278
|
}): Record<string, any> => {
|
|
281
279
|
const codecMap = pipe(
|
|
282
|
-
columns,
|
|
283
|
-
objectEntries,
|
|
280
|
+
ReadonlyRecord.toEntries(columns),
|
|
284
281
|
ReadonlyArray.map(([columnName, columnDef]) => [
|
|
285
282
|
columnName,
|
|
286
283
|
(value: any) => {
|
|
287
284
|
if (columnDef.nullable === true && (value === null || value === undefined)) return null
|
|
288
|
-
const res = Schema.
|
|
289
|
-
if (res
|
|
290
|
-
const parseErrorStr =
|
|
285
|
+
const res = Schema.encodeResult(columnDef.schema)(value)
|
|
286
|
+
if (Result.isFailure(res) === true) {
|
|
287
|
+
const parseErrorStr = SchemaIssue.makeFormatterDefault()(res.failure.issue)
|
|
291
288
|
const expectedSchemaStr = String(columnDef.schema.ast)
|
|
292
289
|
|
|
293
290
|
console.error(
|
|
@@ -301,11 +298,11 @@ Error: ${parseErrorStr}
|
|
|
301
298
|
Value:`,
|
|
302
299
|
value,
|
|
303
300
|
)
|
|
304
|
-
// oxlint-disable-next-line
|
|
301
|
+
// oxlint-disable-next-line no-debugger -- intentional breakpoint for SQL decode errors
|
|
305
302
|
debugger
|
|
306
|
-
throw res.
|
|
303
|
+
throw res.failure
|
|
307
304
|
} else {
|
|
308
|
-
return res.
|
|
305
|
+
return res.success
|
|
309
306
|
}
|
|
310
307
|
},
|
|
311
308
|
]),
|
|
@@ -363,8 +360,7 @@ const buildWhereSql = <TColumns extends SqliteDsl.Columns>({
|
|
|
363
360
|
}
|
|
364
361
|
|
|
365
362
|
return pipe(
|
|
366
|
-
where,
|
|
367
|
-
objectEntries,
|
|
363
|
+
ReadonlyRecord.toEntries(where),
|
|
368
364
|
ReadonlyArray.map(([columnName, value]) => `${columnName} ${getWhereOp(columnName, value)}`),
|
|
369
365
|
ReadonlyArray.join(' AND '),
|
|
370
366
|
)
|
package/src/sql-queries/types.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { Schema } from '@livestore/utils/effect'
|
|
1
|
+
import type { Schema, Types } from '@livestore/utils/effect'
|
|
3
2
|
|
|
4
3
|
import type { SqliteDsl } from '../schema/state/sqlite/db-schema/mod.ts'
|
|
5
4
|
|
|
6
5
|
export type DecodedValuesForTableAll<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = {
|
|
7
|
-
[K in keyof GetColumns<TSchema, TTableName>]:
|
|
6
|
+
[K in keyof GetColumns<TSchema, TTableName>]: GetColumn<TSchema, TTableName, K>['schema']['Type']
|
|
8
7
|
}
|
|
9
8
|
|
|
10
9
|
export type DecodedValuesForTablePretty<
|
|
11
10
|
TSchema extends SqliteDsl.DbSchema,
|
|
12
11
|
TTableName extends keyof TSchema,
|
|
13
|
-
> =
|
|
12
|
+
> = Types.Simplify<DecodedValuesForTable<TSchema, TTableName>>
|
|
14
13
|
|
|
15
14
|
export type DecodedValuesForTable<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = Partial<
|
|
16
15
|
Pick<DecodedValuesForTableAll<TSchema, TTableName>, GetNullableColumnNamesForTable<TSchema, TTableName>>
|
|
@@ -40,7 +39,7 @@ export const isValidWhereOp = (op: string): op is WhereOp => {
|
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
export type EncodedValuesForTableAll<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = {
|
|
43
|
-
[K in keyof GetColumns<TSchema, TTableName>]:
|
|
42
|
+
[K in keyof GetColumns<TSchema, TTableName>]: GetColumn<TSchema, TTableName, K>['schema']['Type']
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
export type EncodedValuesForTable<TSchema extends SqliteDsl.DbSchema, TTableName extends keyof TSchema> = Partial<
|
|
@@ -69,7 +68,7 @@ export type GetColumn<
|
|
|
69
68
|
> = TSchema[TTableName]['columns'][TColumnName]
|
|
70
69
|
|
|
71
70
|
export type DecodedValuesForColumnsAll<TColumns extends SqliteDsl.Columns> = {
|
|
72
|
-
[K in keyof TColumns]:
|
|
71
|
+
[K in keyof TColumns]: TColumns[K]['schema']['Type']
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
export type DecodedValuesForColumns<TColumns extends SqliteDsl.Columns> = Partial<
|
|
@@ -78,7 +77,7 @@ export type DecodedValuesForColumns<TColumns extends SqliteDsl.Columns> = Partia
|
|
|
78
77
|
Omit<DecodedValuesForColumnsAll<TColumns>, GetNullableColumnNames<TColumns>>
|
|
79
78
|
|
|
80
79
|
export type EncodedValuesForColumnsAll<TColumns extends SqliteDsl.Columns> = {
|
|
81
|
-
[K in keyof TColumns]:
|
|
80
|
+
[K in keyof TColumns]: TColumns[K]['schema']['Encoded']
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
export type EncodedValuesForColumns<TColumns extends SqliteDsl.Columns> = Partial<
|
package/src/sqlite-db-helper.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Schema } from '@livestore/utils/effect'
|
|
1
|
+
import { Effect, Exit, Function, Schema } from '@livestore/utils/effect'
|
|
2
2
|
|
|
3
3
|
import { type SqliteDb, SqliteError } from './adapter-types.ts'
|
|
4
4
|
import { getResultSchema, isQueryBuilder } from './schema/state/sqlite/query-builder/mod.ts'
|
|
@@ -33,13 +33,75 @@ export const makeSelect = <T>(
|
|
|
33
33
|
const { query, bindValues } = queryStrOrQueryBuilder.asSql()
|
|
34
34
|
const resultSchema = getResultSchema(queryStrOrQueryBuilder)
|
|
35
35
|
const results = select(query, bindValues as unknown as PreparedBindValues)
|
|
36
|
-
return Schema.
|
|
36
|
+
return Schema.decodeUnknownSync(resultSchema)(results)
|
|
37
37
|
} else {
|
|
38
38
|
return select(queryStrOrQueryBuilder, maybeBindValues)
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Runs an Effect inside an SQLite savepoint.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
*
|
|
48
|
+
* This starts a savepoint before running `effect`, releases the savepoint on
|
|
49
|
+
* success, and rolls back to the savepoint before re-emitting the original
|
|
50
|
+
* failure on failure.
|
|
51
|
+
*
|
|
52
|
+
* Use this for atomic DB updates that need to compose with callers that may
|
|
53
|
+
* already have an open transaction.
|
|
54
|
+
*
|
|
55
|
+
* @see {@link https://sqlite.org/lang_savepoint.html | SQLite savepoint documentation}
|
|
56
|
+
* @see {@link https://sqlite.org/lang_transaction.html | SQLite transaction documentation}
|
|
57
|
+
*/
|
|
58
|
+
export const withSavepoint: {
|
|
59
|
+
(db: SqliteDb): <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E | SqliteError, R>
|
|
60
|
+
<A, E, R>(self: Effect.Effect<A, E, R>, db: SqliteDb): Effect.Effect<A, E | SqliteError, R>
|
|
61
|
+
} = Function.dual(
|
|
62
|
+
2,
|
|
63
|
+
<A, E, R>(self: Effect.Effect<A, E, R>, db: SqliteDb): Effect.Effect<A, E | SqliteError, R> =>
|
|
64
|
+
Effect.uninterruptibleMask((restore) =>
|
|
65
|
+
Effect.sync(generateSavepointName).pipe(
|
|
66
|
+
Effect.flatMap((savepointName) => {
|
|
67
|
+
const savepointSql = `SAVEPOINT ${savepointName}`
|
|
68
|
+
const releaseSql = `RELEASE SAVEPOINT ${savepointName}`
|
|
69
|
+
|
|
70
|
+
return executeSavepointSql(db, savepointSql).pipe(
|
|
71
|
+
// Cleanup is installed only after SQLite successfully creates the savepoint.
|
|
72
|
+
Effect.andThen(
|
|
73
|
+
restore(self).pipe(
|
|
74
|
+
Effect.exit,
|
|
75
|
+
Effect.flatMap((exit) => {
|
|
76
|
+
const cleanup =
|
|
77
|
+
Exit.isSuccess(exit) === true
|
|
78
|
+
? executeSavepointSql(db, releaseSql)
|
|
79
|
+
: executeSavepointSql(db, `ROLLBACK TO SAVEPOINT ${savepointName}`).pipe(
|
|
80
|
+
Effect.andThen(executeSavepointSql(db, releaseSql)),
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
// Cleanup failures supersede the wrapped exit because the connection state is uncertain.
|
|
84
|
+
return cleanup.pipe(Effect.andThen(exit))
|
|
85
|
+
}),
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
}),
|
|
90
|
+
),
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
let nextSavepointId = 0
|
|
95
|
+
|
|
96
|
+
/** Uses a reserved prefix and process-local counter to avoid caller-controlled or reused identifiers. */
|
|
97
|
+
const generateSavepointName = () => `livestore_savepoint_${nextSavepointId++}`
|
|
98
|
+
|
|
99
|
+
const executeSavepointSql = (db: SqliteDb, sql: string): Effect.Effect<void, SqliteError> =>
|
|
100
|
+
Effect.try({
|
|
101
|
+
try: () => db.execute(sql),
|
|
102
|
+
catch: (cause) => new SqliteError({ cause, query: { sql, bindValues: [] } }),
|
|
103
|
+
})
|
|
104
|
+
|
|
43
105
|
export const validateSnapshot = (snapshot: Uint8Array) => {
|
|
44
106
|
const headerBytes = new TextDecoder().decode(snapshot.slice(0, 16))
|
|
45
107
|
const hasValidHeader = headerBytes.startsWith('SQLite format 3')
|