@livestore/common 0.4.0-dev.2 → 0.4.0-dev.21
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 +20 -12
- package/dist/ClientSessionLeaderThreadProxy.d.ts.map +1 -1
- package/dist/ClientSessionLeaderThreadProxy.js.map +1 -1
- package/dist/adapter-types.d.ts +14 -6
- package/dist/adapter-types.d.ts.map +1 -1
- package/dist/adapter-types.js.map +1 -1
- package/dist/debug-info.d.ts.map +1 -1
- package/dist/debug-info.js +33 -6
- package/dist/debug-info.js.map +1 -1
- package/dist/devtools/devtools-messages-client-session.d.ts +28 -23
- package/dist/devtools/devtools-messages-client-session.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-client-session.js +2 -2
- package/dist/devtools/devtools-messages-client-session.js.map +1 -1
- package/dist/devtools/devtools-messages-common.d.ts +7 -14
- package/dist/devtools/devtools-messages-common.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-common.js +1 -6
- package/dist/devtools/devtools-messages-common.js.map +1 -1
- package/dist/devtools/devtools-messages-leader.d.ts +38 -29
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +9 -8
- package/dist/devtools/devtools-messages-leader.js.map +1 -1
- package/dist/devtools/devtools-sessioninfo.d.ts +14 -2
- package/dist/devtools/devtools-sessioninfo.d.ts.map +1 -1
- package/dist/devtools/devtools-sessioninfo.js +7 -4
- package/dist/devtools/devtools-sessioninfo.js.map +1 -1
- package/dist/devtools/mod.d.ts +13 -2
- package/dist/devtools/mod.d.ts.map +1 -1
- package/dist/devtools/mod.js +10 -3
- package/dist/devtools/mod.js.map +1 -1
- package/dist/errors.d.ts +52 -10
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +25 -6
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.d.ts +41 -4
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +158 -75
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +21 -22
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +77 -20
- package/dist/leader-thread/eventlog.js.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.d.ts +2 -2
- package/dist/leader-thread/leader-worker-devtools.d.ts.map +1 -1
- package/dist/leader-thread/leader-worker-devtools.js +56 -45
- package/dist/leader-thread/leader-worker-devtools.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.d.ts +6 -6
- package/dist/leader-thread/make-leader-thread-layer.d.ts.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.js +79 -27
- package/dist/leader-thread/make-leader-thread-layer.js.map +1 -1
- package/dist/leader-thread/make-leader-thread-layer.test.d.ts +2 -0
- package/dist/leader-thread/make-leader-thread-layer.test.d.ts.map +1 -0
- package/dist/leader-thread/make-leader-thread-layer.test.js +32 -0
- package/dist/leader-thread/make-leader-thread-layer.test.js.map +1 -0
- package/dist/leader-thread/materialize-event.d.ts +3 -3
- package/dist/leader-thread/materialize-event.d.ts.map +1 -1
- package/dist/leader-thread/materialize-event.js +25 -11
- package/dist/leader-thread/materialize-event.js.map +1 -1
- package/dist/leader-thread/mod.d.ts +1 -0
- package/dist/leader-thread/mod.d.ts.map +1 -1
- package/dist/leader-thread/mod.js +1 -0
- package/dist/leader-thread/mod.js.map +1 -1
- package/dist/leader-thread/recreate-db.d.ts +2 -3
- package/dist/leader-thread/recreate-db.d.ts.map +1 -1
- package/dist/leader-thread/recreate-db.js +5 -5
- package/dist/leader-thread/recreate-db.js.map +1 -1
- package/dist/leader-thread/shutdown-channel.d.ts +2 -2
- package/dist/leader-thread/shutdown-channel.d.ts.map +1 -1
- package/dist/leader-thread/shutdown-channel.js +2 -2
- package/dist/leader-thread/shutdown-channel.js.map +1 -1
- package/dist/leader-thread/stream-events.d.ts +56 -0
- package/dist/leader-thread/stream-events.d.ts.map +1 -0
- package/dist/leader-thread/stream-events.js +166 -0
- package/dist/leader-thread/stream-events.js.map +1 -0
- package/dist/leader-thread/types.d.ts +98 -20
- package/dist/leader-thread/types.d.ts.map +1 -1
- package/dist/leader-thread/types.js +13 -0
- package/dist/leader-thread/types.js.map +1 -1
- package/dist/logging.d.ts +40 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +33 -0
- package/dist/logging.js.map +1 -0
- package/dist/make-client-session.d.ts +5 -3
- package/dist/make-client-session.d.ts.map +1 -1
- package/dist/make-client-session.js +5 -2
- package/dist/make-client-session.js.map +1 -1
- package/dist/materializer-helper.d.ts +6 -6
- package/dist/materializer-helper.d.ts.map +1 -1
- package/dist/materializer-helper.js +20 -4
- package/dist/materializer-helper.js.map +1 -1
- package/dist/otel.d.ts +2 -1
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +5 -0
- package/dist/otel.js.map +1 -1
- package/dist/rematerialize-from-eventlog.d.ts +2 -2
- package/dist/rematerialize-from-eventlog.d.ts.map +1 -1
- package/dist/rematerialize-from-eventlog.js +29 -20
- package/dist/rematerialize-from-eventlog.js.map +1 -1
- package/dist/schema/EventDef/define.d.ts +147 -0
- package/dist/schema/EventDef/define.d.ts.map +1 -0
- package/dist/schema/EventDef/define.js +139 -0
- package/dist/schema/EventDef/define.js.map +1 -0
- package/dist/schema/EventDef/event-def.d.ts +106 -0
- package/dist/schema/EventDef/event-def.d.ts.map +1 -0
- package/dist/schema/EventDef/event-def.js +2 -0
- package/dist/schema/EventDef/event-def.js.map +1 -0
- package/dist/schema/EventDef/facts.d.ts +118 -0
- package/dist/schema/EventDef/facts.d.ts.map +1 -0
- package/dist/schema/EventDef/facts.js +53 -0
- package/dist/schema/EventDef/facts.js.map +1 -0
- package/dist/schema/EventDef/materializer.d.ts +155 -0
- package/dist/schema/EventDef/materializer.d.ts.map +1 -0
- package/dist/schema/EventDef/materializer.js +83 -0
- package/dist/schema/EventDef/materializer.js.map +1 -0
- package/dist/schema/EventDef/mod.d.ts +5 -0
- package/dist/schema/EventDef/mod.d.ts.map +1 -0
- package/dist/schema/EventDef/mod.js +5 -0
- package/dist/schema/EventDef/mod.js.map +1 -0
- package/dist/schema/EventSequenceNumber/client.d.ts +136 -0
- package/dist/schema/EventSequenceNumber/client.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/client.js +193 -0
- package/dist/schema/EventSequenceNumber/client.js.map +1 -0
- package/dist/schema/EventSequenceNumber/global.d.ts +15 -0
- package/dist/schema/EventSequenceNumber/global.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/global.js +14 -0
- package/dist/schema/EventSequenceNumber/global.js.map +1 -0
- package/dist/schema/EventSequenceNumber/mod.d.ts +37 -0
- package/dist/schema/EventSequenceNumber/mod.d.ts.map +1 -0
- package/dist/schema/EventSequenceNumber/mod.js +37 -0
- package/dist/schema/EventSequenceNumber/mod.js.map +1 -0
- package/dist/schema/EventSequenceNumber.test.js +43 -43
- package/dist/schema/EventSequenceNumber.test.js.map +1 -1
- package/dist/schema/{LiveStoreEvent.d.ts → LiveStoreEvent/client.d.ts} +89 -106
- package/dist/schema/LiveStoreEvent/client.d.ts.map +1 -0
- package/dist/schema/{LiveStoreEvent.js → LiveStoreEvent/client.js} +74 -58
- package/dist/schema/LiveStoreEvent/client.js.map +1 -0
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts +52 -0
- package/dist/schema/LiveStoreEvent/for-event-def.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/for-event-def.js +2 -0
- package/dist/schema/LiveStoreEvent/for-event-def.js.map +1 -0
- package/dist/schema/LiveStoreEvent/global.d.ts +36 -0
- package/dist/schema/LiveStoreEvent/global.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/global.js +31 -0
- package/dist/schema/LiveStoreEvent/global.js.map +1 -0
- package/dist/schema/LiveStoreEvent/input.d.ts +46 -0
- package/dist/schema/LiveStoreEvent/input.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/input.js +26 -0
- package/dist/schema/LiveStoreEvent/input.js.map +1 -0
- package/dist/schema/LiveStoreEvent/mod.d.ts +5 -0
- package/dist/schema/LiveStoreEvent/mod.d.ts.map +1 -0
- package/dist/schema/LiveStoreEvent/mod.js +5 -0
- package/dist/schema/LiveStoreEvent/mod.js.map +1 -0
- package/dist/schema/events.d.ts +1 -1
- package/dist/schema/events.d.ts.map +1 -1
- package/dist/schema/events.js +1 -1
- package/dist/schema/events.js.map +1 -1
- package/dist/schema/mod.d.ts +6 -4
- package/dist/schema/mod.d.ts.map +1 -1
- package/dist/schema/mod.js +5 -4
- package/dist/schema/mod.js.map +1 -1
- package/dist/schema/schema.d.ts +16 -1
- package/dist/schema/schema.d.ts.map +1 -1
- package/dist/schema/schema.js +27 -2
- package/dist/schema/schema.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.d.ts +36 -6
- package/dist/schema/state/sqlite/client-document-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.js +97 -6
- package/dist/schema/state/sqlite/client-document-def.js.map +1 -1
- package/dist/schema/state/sqlite/client-document-def.test.js +16 -0
- package/dist/schema/state/sqlite/client-document-def.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.d.ts.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.js +14 -6
- package/dist/schema/state/sqlite/column-annotations.js.map +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js +1 -1
- package/dist/schema/state/sqlite/column-annotations.test.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.js +69 -22
- package/dist/schema/state/sqlite/column-def.js.map +1 -1
- package/dist/schema/state/sqlite/column-def.test.js +48 -10
- 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 +30 -12
- package/dist/schema/state/sqlite/column-spec.js.map +1 -1
- package/dist/schema/state/sqlite/column-spec.test.js +23 -14
- package/dist/schema/state/sqlite/column-spec.test.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts +2 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js +23 -6
- package/dist/schema/state/sqlite/db-schema/ast/sqlite.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.d.ts +14 -8
- 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 +5 -3
- package/dist/schema/state/sqlite/db-schema/dsl/field-defs.js.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js +2 -1
- package/dist/schema/state/sqlite/db-schema/dsl/mod.js.map +1 -1
- package/dist/schema/state/sqlite/mod.d.ts +3 -3
- package/dist/schema/state/sqlite/mod.d.ts.map +1 -1
- package/dist/schema/state/sqlite/mod.js +3 -3
- package/dist/schema/state/sqlite/mod.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/api.d.ts +19 -11
- 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 -15
- package/dist/schema/state/sqlite/query-builder/astToSql.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.d.ts.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.js +6 -3
- package/dist/schema/state/sqlite/query-builder/impl.js.map +1 -1
- package/dist/schema/state/sqlite/query-builder/impl.test.js +252 -88
- package/dist/schema/state/sqlite/query-builder/impl.test.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.d.ts +2 -2
- package/dist/schema/state/sqlite/schema-helpers.d.ts.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.js +22 -12
- package/dist/schema/state/sqlite/schema-helpers.js.map +1 -1
- package/dist/schema/state/sqlite/schema-helpers.test.d.ts +2 -0
- package/dist/schema/state/sqlite/schema-helpers.test.d.ts.map +1 -0
- package/dist/schema/state/sqlite/schema-helpers.test.js +36 -0
- package/dist/schema/state/sqlite/schema-helpers.test.js.map +1 -0
- package/dist/schema/state/sqlite/{system-tables.d.ts → system-tables/eventlog-tables.d.ts} +63 -456
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js +54 -0
- package/dist/schema/state/sqlite/system-tables/eventlog-tables.js.map +1 -0
- package/dist/schema/state/sqlite/system-tables/mod.d.ts +3 -0
- package/dist/schema/state/sqlite/system-tables/mod.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables/mod.js +3 -0
- package/dist/schema/state/sqlite/system-tables/mod.js.map +1 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts +456 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.d.ts.map +1 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.js +55 -0
- package/dist/schema/state/sqlite/system-tables/state-tables.js.map +1 -0
- package/dist/schema/state/sqlite/table-def.d.ts +4 -4
- package/dist/schema/state/sqlite/table-def.d.ts.map +1 -1
- package/dist/schema/state/sqlite/table-def.js +2 -2
- package/dist/schema/state/sqlite/table-def.js.map +1 -1
- package/dist/schema/state/sqlite/table-def.test.js +80 -0
- package/dist/schema/state/sqlite/table-def.test.js.map +1 -1
- package/dist/schema/unknown-events.d.ts +47 -0
- package/dist/schema/unknown-events.d.ts.map +1 -0
- package/dist/schema/unknown-events.js +69 -0
- package/dist/schema/unknown-events.js.map +1 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts +2 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.d.ts.map +1 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js +73 -0
- package/dist/schema-management/__tests__/migrations-autoincrement-quoting.test.js.map +1 -0
- package/dist/schema-management/migrations.d.ts +32 -2
- package/dist/schema-management/migrations.d.ts.map +1 -1
- package/dist/schema-management/migrations.js +37 -5
- package/dist/schema-management/migrations.js.map +1 -1
- package/dist/schema-management/validate-schema.d.ts +3 -3
- package/dist/schema-management/validate-schema.d.ts.map +1 -1
- package/dist/schema-management/validate-schema.js +2 -2
- package/dist/schema-management/validate-schema.js.map +1 -1
- package/dist/sql-queries/sql-queries.d.ts.map +1 -1
- package/dist/sql-queries/sql-queries.js +11 -1
- 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 +2 -1
- package/dist/sql-queries/sql-query-builder.js.map +1 -1
- package/dist/sqlite-types.d.ts +3 -3
- package/dist/sqlite-types.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.d.ts +11 -13
- package/dist/sync/ClientSessionSyncProcessor.d.ts.map +1 -1
- package/dist/sync/ClientSessionSyncProcessor.js +45 -42
- package/dist/sync/ClientSessionSyncProcessor.js.map +1 -1
- package/dist/sync/errors.d.ts +66 -0
- package/dist/sync/errors.d.ts.map +1 -0
- package/dist/sync/errors.js +36 -0
- package/dist/sync/errors.js.map +1 -0
- package/dist/sync/index.d.ts +3 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +3 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/mock-sync-backend.d.ts +23 -0
- package/dist/sync/mock-sync-backend.d.ts.map +1 -0
- package/dist/sync/mock-sync-backend.js +114 -0
- package/dist/sync/mock-sync-backend.js.map +1 -0
- package/dist/sync/next/compact-events.d.ts.map +1 -1
- package/dist/sync/next/compact-events.js +6 -7
- package/dist/sync/next/compact-events.js.map +1 -1
- package/dist/sync/next/facts.d.ts +5 -5
- package/dist/sync/next/facts.d.ts.map +1 -1
- package/dist/sync/next/facts.js +1 -2
- package/dist/sync/next/facts.js.map +1 -1
- package/dist/sync/next/history-dag-common.d.ts +54 -15
- package/dist/sync/next/history-dag-common.d.ts.map +1 -1
- package/dist/sync/next/history-dag-common.js +198 -9
- 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 +10 -8
- package/dist/sync/next/history-dag.js.map +1 -1
- package/dist/sync/next/rebase-events.d.ts +5 -5
- package/dist/sync/next/rebase-events.d.ts.map +1 -1
- package/dist/sync/next/rebase-events.js +5 -5
- package/dist/sync/next/rebase-events.js.map +1 -1
- package/dist/sync/next/test/event-fixtures.d.ts +2 -2
- package/dist/sync/next/test/event-fixtures.d.ts.map +1 -1
- package/dist/sync/next/test/event-fixtures.js +9 -9
- package/dist/sync/next/test/event-fixtures.js.map +1 -1
- package/dist/sync/sync-backend-kv.d.ts +7 -0
- package/dist/sync/sync-backend-kv.d.ts.map +1 -0
- package/dist/sync/sync-backend-kv.js +18 -0
- package/dist/sync/sync-backend-kv.js.map +1 -0
- package/dist/sync/sync-backend.d.ts +105 -0
- package/dist/sync/sync-backend.d.ts.map +1 -0
- package/dist/sync/sync-backend.js +61 -0
- package/dist/sync/sync-backend.js.map +1 -0
- package/dist/sync/sync.d.ts +9 -86
- package/dist/sync/sync.d.ts.map +1 -1
- package/dist/sync/sync.js +2 -27
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/syncstate.d.ts +57 -44
- package/dist/sync/syncstate.d.ts.map +1 -1
- package/dist/sync/syncstate.js +50 -45
- package/dist/sync/syncstate.js.map +1 -1
- package/dist/sync/syncstate.test.js +83 -46
- package/dist/sync/syncstate.test.js.map +1 -1
- package/dist/sync/transport-chunking.d.ts +36 -0
- package/dist/sync/transport-chunking.d.ts.map +1 -0
- package/dist/sync/transport-chunking.js +56 -0
- package/dist/sync/transport-chunking.js.map +1 -0
- 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 +6 -6
- package/dist/sync/validate-push-payload.js.map +1 -1
- package/dist/testing/event-factory.d.ts +68 -0
- package/dist/testing/event-factory.d.ts.map +1 -0
- package/dist/testing/event-factory.js +78 -0
- package/dist/testing/event-factory.js.map +1 -0
- package/dist/testing/mod.d.ts +2 -0
- package/dist/testing/mod.d.ts.map +1 -0
- package/dist/testing/mod.js +2 -0
- package/dist/testing/mod.js.map +1 -0
- package/dist/version.d.ts +16 -6
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +16 -6
- package/dist/version.js.map +1 -1
- package/package.json +7 -8
- package/src/ClientSessionLeaderThreadProxy.ts +20 -12
- package/src/adapter-types.ts +18 -6
- package/src/debug-info.ts +37 -6
- package/src/devtools/devtools-messages-client-session.ts +2 -2
- package/src/devtools/devtools-messages-common.ts +1 -8
- package/src/devtools/devtools-messages-leader.ts +9 -8
- package/src/devtools/devtools-sessioninfo.ts +8 -5
- package/src/devtools/mod.ts +11 -2
- package/src/errors.ts +38 -11
- package/src/index.ts +2 -1
- package/src/leader-thread/LeaderSyncProcessor.ts +277 -105
- package/src/leader-thread/eventlog.ts +113 -38
- package/src/leader-thread/leader-worker-devtools.ts +86 -55
- package/src/leader-thread/make-leader-thread-layer.test.ts +44 -0
- package/src/leader-thread/make-leader-thread-layer.ts +156 -37
- package/src/leader-thread/materialize-event.ts +37 -12
- package/src/leader-thread/mod.ts +1 -0
- package/src/leader-thread/recreate-db.ts +15 -7
- package/src/leader-thread/shutdown-channel.ts +16 -2
- package/src/leader-thread/stream-events.ts +201 -0
- package/src/leader-thread/types.ts +70 -20
- package/src/logging.ts +62 -0
- package/src/make-client-session.ts +9 -3
- package/src/materializer-helper.ts +27 -10
- package/src/otel.ts +10 -0
- package/src/rematerialize-from-eventlog.ts +37 -27
- package/src/schema/EventDef/define.ts +201 -0
- package/src/schema/EventDef/event-def.ts +120 -0
- package/src/schema/EventDef/facts.ts +135 -0
- package/src/schema/EventDef/materializer.ts +172 -0
- package/src/schema/EventDef/mod.ts +4 -0
- package/src/schema/EventSequenceNumber/client.ts +257 -0
- package/src/schema/EventSequenceNumber/global.ts +19 -0
- package/src/schema/EventSequenceNumber/mod.ts +37 -0
- package/src/schema/EventSequenceNumber.test.ts +70 -52
- package/src/schema/LiveStoreEvent/client.ts +221 -0
- package/src/schema/LiveStoreEvent/for-event-def.ts +60 -0
- package/src/schema/LiveStoreEvent/global.ts +45 -0
- package/src/schema/LiveStoreEvent/input.ts +63 -0
- package/src/schema/LiveStoreEvent/mod.ts +4 -0
- package/src/schema/events.ts +1 -1
- package/src/schema/mod.ts +6 -4
- package/src/schema/schema.ts +39 -3
- package/src/schema/state/sqlite/client-document-def.test.ts +19 -2
- package/src/schema/state/sqlite/client-document-def.ts +127 -25
- package/src/schema/state/sqlite/column-annotations.test.ts +1 -1
- package/src/schema/state/sqlite/column-annotations.ts +16 -6
- package/src/schema/state/sqlite/column-def.test.ts +62 -10
- package/src/schema/state/sqlite/column-def.ts +88 -21
- package/src/schema/state/sqlite/column-spec.test.ts +29 -16
- package/src/schema/state/sqlite/column-spec.ts +36 -11
- package/src/schema/state/sqlite/db-schema/ast/sqlite.ts +26 -6
- package/src/schema/state/sqlite/db-schema/dsl/field-defs.ts +29 -12
- package/src/schema/state/sqlite/db-schema/dsl/mod.ts +12 -17
- package/src/schema/state/sqlite/mod.ts +4 -3
- package/src/schema/state/sqlite/query-builder/api.ts +25 -11
- package/src/schema/state/sqlite/query-builder/astToSql.ts +23 -14
- package/src/schema/state/sqlite/query-builder/impl.test.ts +305 -92
- package/src/schema/state/sqlite/query-builder/impl.ts +8 -3
- package/src/schema/state/sqlite/schema-helpers.test.ts +44 -0
- package/src/schema/state/sqlite/schema-helpers.ts +28 -20
- package/src/schema/state/sqlite/system-tables/eventlog-tables.ts +64 -0
- package/src/schema/state/sqlite/system-tables/mod.ts +2 -0
- package/src/schema/state/sqlite/system-tables/state-tables.ts +69 -0
- package/src/schema/state/sqlite/table-def.test.ts +101 -0
- package/src/schema/state/sqlite/table-def.ts +8 -6
- package/src/schema/unknown-events.ts +131 -0
- package/src/schema-management/__tests__/migrations-autoincrement-quoting.test.ts +86 -0
- package/src/schema-management/migrations.ts +41 -8
- package/src/schema-management/validate-schema.ts +3 -3
- package/src/sql-queries/sql-queries.ts +9 -1
- package/src/sql-queries/sql-query-builder.ts +2 -1
- package/src/sqlite-types.ts +3 -3
- package/src/sync/ClientSessionSyncProcessor.ts +69 -62
- package/src/sync/errors.ts +38 -0
- package/src/sync/index.ts +3 -0
- package/src/sync/mock-sync-backend.ts +184 -0
- package/src/sync/next/compact-events.ts +6 -7
- package/src/sync/next/facts.ts +7 -9
- package/src/sync/next/history-dag-common.ts +277 -26
- package/src/sync/next/history-dag.ts +16 -10
- package/src/sync/next/rebase-events.ts +11 -11
- package/src/sync/next/test/event-fixtures.ts +11 -11
- package/src/sync/sync-backend-kv.ts +22 -0
- package/src/sync/sync-backend.ts +185 -0
- package/src/sync/sync.ts +9 -91
- package/src/sync/syncstate.test.ts +96 -52
- package/src/sync/syncstate.ts +69 -58
- package/src/sync/transport-chunking.ts +90 -0
- package/src/sync/validate-push-payload.ts +8 -9
- package/src/testing/event-factory.ts +131 -0
- package/src/testing/mod.ts +1 -0
- package/src/version.ts +16 -6
- package/dist/schema/EventDef.d.ts +0 -123
- package/dist/schema/EventDef.d.ts.map +0 -1
- package/dist/schema/EventDef.js +0 -46
- package/dist/schema/EventDef.js.map +0 -1
- package/dist/schema/EventSequenceNumber.d.ts +0 -80
- package/dist/schema/EventSequenceNumber.d.ts.map +0 -1
- package/dist/schema/EventSequenceNumber.js +0 -139
- package/dist/schema/EventSequenceNumber.js.map +0 -1
- package/dist/schema/LiveStoreEvent.d.ts.map +0 -1
- package/dist/schema/LiveStoreEvent.js.map +0 -1
- package/dist/schema/state/sqlite/system-tables.d.ts.map +0 -1
- package/dist/schema/state/sqlite/system-tables.js +0 -79
- package/dist/schema/state/sqlite/system-tables.js.map +0 -1
- package/dist/schema-management/migrations.test.d.ts +0 -2
- package/dist/schema-management/migrations.test.d.ts.map +0 -1
- package/dist/schema-management/migrations.test.js +0 -52
- package/dist/schema-management/migrations.test.js.map +0 -1
- package/dist/sync/next/graphology.d.ts +0 -8
- package/dist/sync/next/graphology.d.ts.map +0 -1
- package/dist/sync/next/graphology.js +0 -30
- package/dist/sync/next/graphology.js.map +0 -1
- package/dist/sync/next/graphology_.d.ts +0 -3
- package/dist/sync/next/graphology_.d.ts.map +0 -1
- package/dist/sync/next/graphology_.js +0 -3
- package/dist/sync/next/graphology_.js.map +0 -1
- package/src/schema/EventDef.ts +0 -219
- package/src/schema/EventSequenceNumber.ts +0 -199
- package/src/schema/LiveStoreEvent.ts +0 -287
- package/src/schema/state/sqlite/system-tables.ts +0 -104
- package/src/sync/next/ambient.d.ts +0 -3
- package/src/sync/next/graphology.ts +0 -41
- package/src/sync/next/graphology_.ts +0 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
2
|
import type { Option, Types } from '@livestore/utils/effect'
|
|
3
|
-
import { Schema
|
|
3
|
+
import { Schema } from '@livestore/utils/effect'
|
|
4
4
|
|
|
5
5
|
import { SessionIdSymbol } from '../../../adapter-types.ts'
|
|
6
6
|
import { sql } from '../../../util.ts'
|
|
7
|
-
import type { EventDef, Materializer } from '../../EventDef.ts'
|
|
8
|
-
import { defineEvent, defineMaterializer } from '../../EventDef.ts'
|
|
7
|
+
import type { EventDef, Materializer } from '../../EventDef/mod.ts'
|
|
8
|
+
import { defineEvent, defineMaterializer } from '../../EventDef/mod.ts'
|
|
9
9
|
import { SqliteDsl } from './db-schema/mod.ts'
|
|
10
10
|
import type { QueryBuilder, QueryBuilderAst } from './query-builder/mod.ts'
|
|
11
11
|
import { QueryBuilderAstSymbol, QueryBuilderTypeId } from './query-builder/mod.ts'
|
|
@@ -62,9 +62,16 @@ export const clientDocument = <
|
|
|
62
62
|
},
|
|
63
63
|
} satisfies ClientDocumentTableOptions<TType>
|
|
64
64
|
|
|
65
|
+
// Column needs optimistic schema to read historical data formats
|
|
66
|
+
const optimisticColumnSchema = createOptimisticEventSchema({
|
|
67
|
+
valueSchema,
|
|
68
|
+
defaultValue: options.default.value,
|
|
69
|
+
partialSet: false, // Column always stores full documents
|
|
70
|
+
})
|
|
71
|
+
|
|
65
72
|
const columns = {
|
|
66
73
|
id: SqliteDsl.text({ primaryKey: true }),
|
|
67
|
-
value: SqliteDsl.json({ schema:
|
|
74
|
+
value: SqliteDsl.json({ schema: optimisticColumnSchema }),
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
const tableDef = table({ name, columns })
|
|
@@ -140,6 +147,105 @@ export const mergeDefaultValues = <T>(defaultValues: T, explicitDefaultValues: T
|
|
|
140
147
|
}, {} as any)
|
|
141
148
|
}
|
|
142
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Creates an optimistic schema that accepts historical event formats
|
|
152
|
+
* and transforms them to the current schema, preserving data and intent.
|
|
153
|
+
*
|
|
154
|
+
* Decision Matrix for Schema Changes:
|
|
155
|
+
*
|
|
156
|
+
* | Change Type | Partial Set | Full Set | Strategy |
|
|
157
|
+
* |---------------------|---------------------|----------------------------------|-------------------------|
|
|
158
|
+
* | **Compatible Changes** |
|
|
159
|
+
* | Add optional field | Preserve existing | Preserve existing, new field undefined | Direct decode or merge |
|
|
160
|
+
* | Add required field | Preserve existing | Preserve existing, new field from default | Merge with defaults |
|
|
161
|
+
* | **Incompatible Changes** |
|
|
162
|
+
* | Remove field | Drop removed field | Drop removed field, preserve others | Filter & decode |
|
|
163
|
+
* | Type change | Use default for field | Use default for changed field | Selective merge |
|
|
164
|
+
* | Rename field | Use default | Use default (can't detect rename) | Fall back to default |
|
|
165
|
+
* | **Edge Cases** |
|
|
166
|
+
* | Empty event | Return {} | Return full default | Fallback handling |
|
|
167
|
+
* | Invalid structure | Return {} | Return full default | Fallback handling |
|
|
168
|
+
*/
|
|
169
|
+
export const createOptimisticEventSchema = ({
|
|
170
|
+
valueSchema,
|
|
171
|
+
defaultValue,
|
|
172
|
+
partialSet,
|
|
173
|
+
}: {
|
|
174
|
+
valueSchema: Schema.Schema<any, any>
|
|
175
|
+
defaultValue: any
|
|
176
|
+
partialSet: boolean
|
|
177
|
+
}) => {
|
|
178
|
+
const targetSchema = partialSet ? Schema.partial(valueSchema) : valueSchema
|
|
179
|
+
|
|
180
|
+
return Schema.transform(
|
|
181
|
+
Schema.Unknown, // Accept any historical event structure
|
|
182
|
+
targetSchema, // Output current schema
|
|
183
|
+
{
|
|
184
|
+
decode: (eventValue) => {
|
|
185
|
+
// Try direct decode first (for current schema events)
|
|
186
|
+
try {
|
|
187
|
+
return Schema.decodeUnknownSync(targetSchema)(eventValue)
|
|
188
|
+
} catch {
|
|
189
|
+
// Optimistic decoding for historical events
|
|
190
|
+
|
|
191
|
+
// Handle null/undefined/non-object cases
|
|
192
|
+
if (typeof eventValue !== 'object' || eventValue === null) {
|
|
193
|
+
console.warn(`Client document: Non-object event value, using ${partialSet ? 'empty partial' : 'defaults'}`)
|
|
194
|
+
return partialSet ? {} : defaultValue
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (partialSet) {
|
|
198
|
+
// For partial sets: only preserve fields that exist in new schema
|
|
199
|
+
const partialResult: Record<string, unknown> = {}
|
|
200
|
+
let hasValidFields = false
|
|
201
|
+
|
|
202
|
+
for (const [key, value] of Object.entries(eventValue as Record<string, unknown>)) {
|
|
203
|
+
if (key in defaultValue) {
|
|
204
|
+
partialResult[key] = value
|
|
205
|
+
hasValidFields = true
|
|
206
|
+
}
|
|
207
|
+
// Drop fields that don't exist in new schema
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (hasValidFields) {
|
|
211
|
+
try {
|
|
212
|
+
return Schema.decodeUnknownSync(targetSchema)(partialResult)
|
|
213
|
+
} catch {
|
|
214
|
+
// Even filtered fields don't match schema
|
|
215
|
+
console.warn('Client document: Partial fields incompatible, returning empty partial')
|
|
216
|
+
return {}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return {}
|
|
220
|
+
} else {
|
|
221
|
+
// Full set: merge old data with new defaults
|
|
222
|
+
const merged: Record<string, unknown> = { ...defaultValue }
|
|
223
|
+
|
|
224
|
+
// Override defaults with valid fields from old event
|
|
225
|
+
for (const [key, value] of Object.entries(eventValue as Record<string, unknown>)) {
|
|
226
|
+
if (key in defaultValue) {
|
|
227
|
+
merged[key] = value
|
|
228
|
+
}
|
|
229
|
+
// Drop fields that don't exist in new schema
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Try to decode the merged value
|
|
233
|
+
try {
|
|
234
|
+
return Schema.decodeUnknownSync(valueSchema)(merged)
|
|
235
|
+
} catch {
|
|
236
|
+
// Merged value still doesn't match (e.g., type changes)
|
|
237
|
+
// Fall back to pure defaults
|
|
238
|
+
console.warn('Client document: Could not preserve event data, using defaults')
|
|
239
|
+
return defaultValue
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
encode: (value) => value, // Pass-through for encoding
|
|
245
|
+
},
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
|
|
143
249
|
export const deriveEventAndMaterializer = ({
|
|
144
250
|
name,
|
|
145
251
|
valueSchema,
|
|
@@ -155,7 +261,7 @@ export const deriveEventAndMaterializer = ({
|
|
|
155
261
|
name: `${name}Set`,
|
|
156
262
|
schema: Schema.Struct({
|
|
157
263
|
id: Schema.Union(Schema.String, Schema.UniqueSymbolFromSelf(SessionIdSymbol)),
|
|
158
|
-
value:
|
|
264
|
+
value: createOptimisticEventSchema({ valueSchema, defaultValue, partialSet }),
|
|
159
265
|
}).annotations({ title: `${name}Set:Args` }),
|
|
160
266
|
clientOnly: true,
|
|
161
267
|
derived: true,
|
|
@@ -167,7 +273,7 @@ export const deriveEventAndMaterializer = ({
|
|
|
167
273
|
}
|
|
168
274
|
|
|
169
275
|
// Override the full value if it's not an object or no partial set is allowed
|
|
170
|
-
const schemaProps =
|
|
276
|
+
const schemaProps = Schema.getResolvedPropertySignatures(valueSchema)
|
|
171
277
|
if (schemaProps.length === 0 || partialSet === false) {
|
|
172
278
|
const valueColJsonSchema = Schema.parseJson(valueSchema)
|
|
173
279
|
const encodedInsertValue = Schema.encodeSyncDebug(valueColJsonSchema)(value ?? defaultValue)
|
|
@@ -281,8 +387,14 @@ export namespace ClientDocumentTableOptions {
|
|
|
281
387
|
}
|
|
282
388
|
}
|
|
283
389
|
|
|
390
|
+
type IsStructLike<T> = T extends {} ? true : false
|
|
391
|
+
|
|
284
392
|
export type WithDefaults<TInput extends Input<any>> = {
|
|
285
|
-
partialSet: TInput['partialSet'] extends false
|
|
393
|
+
partialSet: TInput['partialSet'] extends false
|
|
394
|
+
? false
|
|
395
|
+
: IsStructLike<TInput['default']['value']> extends true
|
|
396
|
+
? true
|
|
397
|
+
: false
|
|
286
398
|
default: {
|
|
287
399
|
id: TInput['default']['id'] extends string | SessionIdSymbol ? TInput['default']['id'] : undefined
|
|
288
400
|
value: TInput['default']['value']
|
|
@@ -401,27 +513,17 @@ export namespace ClientDocumentTableDef {
|
|
|
401
513
|
}
|
|
402
514
|
}
|
|
403
515
|
|
|
404
|
-
export type GetOptions<TTableDef extends TraitAny> =
|
|
405
|
-
any,
|
|
406
|
-
any,
|
|
407
|
-
any,
|
|
408
|
-
infer TOptions
|
|
409
|
-
>
|
|
410
|
-
? TOptions
|
|
411
|
-
: never
|
|
516
|
+
export type GetOptions<TTableDef extends TraitAny> =
|
|
517
|
+
TTableDef extends ClientDocumentTableDef.Trait<any, any, any, infer TOptions> ? TOptions : never
|
|
412
518
|
|
|
413
519
|
export type TraitAny = Trait<any, any, any, any>
|
|
414
520
|
|
|
415
|
-
export type DefaultIdType<TTableDef extends TraitAny> =
|
|
416
|
-
any,
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
>
|
|
421
|
-
? TOptions['default']['id'] extends SessionIdSymbol | string
|
|
422
|
-
? TOptions['default']['id']
|
|
521
|
+
export type DefaultIdType<TTableDef extends TraitAny> =
|
|
522
|
+
TTableDef extends ClientDocumentTableDef.Trait<any, any, any, infer TOptions>
|
|
523
|
+
? TOptions['default']['id'] extends SessionIdSymbol | string
|
|
524
|
+
? TOptions['default']['id']
|
|
525
|
+
: never
|
|
423
526
|
: never
|
|
424
|
-
: never
|
|
425
527
|
|
|
426
528
|
export type SetEventDefLike<
|
|
427
529
|
TName extends string,
|
|
@@ -467,5 +569,5 @@ export namespace ClientDocumentTableDef {
|
|
|
467
569
|
) => QueryBuilder<TType, ClientDocumentTableDef.TableDefBase_<TName, TType>, QueryBuilder.ApiFeature>
|
|
468
570
|
}
|
|
469
571
|
|
|
470
|
-
export const ClientDocumentTableDefSymbol = Symbol('ClientDocumentTableDef')
|
|
572
|
+
export const ClientDocumentTableDefSymbol = Symbol.for('livestore.ClientDocumentTableDef')
|
|
471
573
|
export type ClientDocumentTableDefSymbol = typeof ClientDocumentTableDefSymbol
|
|
@@ -65,7 +65,7 @@ describe.concurrent('annotations', () => {
|
|
|
65
65
|
})
|
|
66
66
|
|
|
67
67
|
test('Union of same type with compatible column type', () => {
|
|
68
|
-
const unionSchema = Schema.
|
|
68
|
+
const unionSchema = Schema.Literal('a', 'b')
|
|
69
69
|
expect(() => withColumnType(unionSchema, 'text')).not.toThrow()
|
|
70
70
|
})
|
|
71
71
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Schema } from '@livestore/utils/effect'
|
|
2
|
-
import { dual } from '@livestore/utils/effect'
|
|
2
|
+
import { dual, Option, SchemaAST } from '@livestore/utils/effect'
|
|
3
3
|
import type { SqliteDsl } from './db-schema/mod.ts'
|
|
4
4
|
|
|
5
5
|
export const PrimaryKeyId = Symbol.for('livestore/state/sqlite/annotations/primary-key')
|
|
@@ -32,7 +32,7 @@ Here are the knobs you can turn per-column when you CREATE TABLE (or ALTER TABLE
|
|
|
32
32
|
* Adds a primary key annotation to a schema.
|
|
33
33
|
*/
|
|
34
34
|
export const withPrimaryKey = <T extends Schema.Schema.All>(schema: T) =>
|
|
35
|
-
schema
|
|
35
|
+
applyAnnotations(schema, { [PrimaryKeyId]: true })
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Adds a column type annotation to a schema.
|
|
@@ -43,19 +43,19 @@ export const withColumnType: {
|
|
|
43
43
|
<T extends Schema.Schema.All>(schema: T, type: SqliteDsl.FieldColumnType): T
|
|
44
44
|
} = dual(2, <T extends Schema.Schema.All>(schema: T, type: SqliteDsl.FieldColumnType) => {
|
|
45
45
|
validateSchemaColumnTypeCompatibility(schema, type)
|
|
46
|
-
return schema
|
|
46
|
+
return applyAnnotations(schema, { [ColumnType]: type })
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Adds an auto-increment annotation to a schema.
|
|
51
51
|
*/
|
|
52
52
|
export const withAutoIncrement = <T extends Schema.Schema.All>(schema: T) =>
|
|
53
|
-
schema
|
|
53
|
+
applyAnnotations(schema, { [AutoIncrement]: true })
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Adds a unique constraint annotation to a schema.
|
|
57
57
|
*/
|
|
58
|
-
export const withUnique = <T extends Schema.Schema.All>(schema: T) => schema
|
|
58
|
+
export const withUnique = <T extends Schema.Schema.All>(schema: T) => applyAnnotations(schema, { [Unique]: true })
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Adds a default value annotation to a schema.
|
|
@@ -64,7 +64,7 @@ export const withDefault: {
|
|
|
64
64
|
// TODO make type safe
|
|
65
65
|
<T extends Schema.Schema.All>(schema: T, value: unknown): T
|
|
66
66
|
(value: unknown): <T extends Schema.Schema.All>(schema: T) => T
|
|
67
|
-
} = dual(2, <T extends Schema.Schema.All>(schema: T, value: unknown) => schema
|
|
67
|
+
} = dual(2, <T extends Schema.Schema.All>(schema: T, value: unknown) => applyAnnotations(schema, { [Default]: value }))
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Validates that a schema is compatible with the specified SQLite column type
|
|
@@ -75,3 +75,13 @@ const validateSchemaColumnTypeCompatibility = (
|
|
|
75
75
|
): void => {
|
|
76
76
|
// TODO actually implement this
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
const applyAnnotations = <T extends Schema.Schema.All>(schema: T, overrides: Record<PropertyKey, unknown>): T => {
|
|
80
|
+
const identifier = SchemaAST.getIdentifierAnnotation(schema.ast)
|
|
81
|
+
const shouldPreserveIdentifier = Option.isSome(identifier) && !(SchemaAST.IdentifierAnnotationId in overrides)
|
|
82
|
+
const annotations: Record<PropertyKey, unknown> = shouldPreserveIdentifier
|
|
83
|
+
? { ...overrides, [SchemaAST.IdentifierAnnotationId]: identifier.value }
|
|
84
|
+
: overrides
|
|
85
|
+
|
|
86
|
+
return schema.annotations(annotations) as T
|
|
87
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema } from '@livestore/utils/effect'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { assert, describe, expect, it } from 'vitest'
|
|
3
3
|
|
|
4
4
|
import * as State from '../mod.ts'
|
|
5
5
|
import { withAutoIncrement, withColumnType, withDefault, withPrimaryKey, withUnique } from './column-annotations.ts'
|
|
@@ -144,11 +144,10 @@ describe('getColumnDefForSchema', () => {
|
|
|
144
144
|
|
|
145
145
|
it('should map tagged unions to json column', () => {
|
|
146
146
|
const ResultSchema = Schema.Union(
|
|
147
|
-
Schema.
|
|
148
|
-
_tag: Schema.Literal('success'),
|
|
147
|
+
Schema.TaggedStruct('success', {
|
|
149
148
|
value: Schema.String,
|
|
150
149
|
}),
|
|
151
|
-
Schema.
|
|
150
|
+
Schema.TaggedStruct('error', { error: Schema.String }),
|
|
152
151
|
)
|
|
153
152
|
|
|
154
153
|
const columnDef = State.SQLite.getColumnDefForSchema(ResultSchema)
|
|
@@ -273,17 +272,34 @@ describe('getColumnDefForSchema', () => {
|
|
|
273
272
|
INACTIVE: 'inactive',
|
|
274
273
|
})
|
|
275
274
|
|
|
276
|
-
const StatusUnion = Schema.
|
|
275
|
+
const StatusUnion = Schema.Literal('pending', 'active', 'inactive')
|
|
277
276
|
|
|
278
277
|
expect(State.SQLite.getColumnDefForSchema(StatusEnum).columnType).toBe('text')
|
|
279
278
|
expect(State.SQLite.getColumnDefForSchema(StatusUnion).columnType).toBe('text')
|
|
280
279
|
})
|
|
280
|
+
|
|
281
|
+
it('should handle unions of numeric literals as integer column', () => {
|
|
282
|
+
const IntervalSchema = Schema.Literal(1, 5, 15, 30)
|
|
283
|
+
|
|
284
|
+
const columnDef = State.SQLite.getColumnDefForSchema(IntervalSchema)
|
|
285
|
+
|
|
286
|
+
expect(columnDef.columnType).toBe('integer')
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
it('should handle unions of non-integer numeric literals as real column', () => {
|
|
290
|
+
const PercentSchema = Schema.Literal(0.1, 0.2, 0.25)
|
|
291
|
+
|
|
292
|
+
const columnDef = State.SQLite.getColumnDefForSchema(PercentSchema)
|
|
293
|
+
|
|
294
|
+
expect(columnDef.columnType).toBe('real')
|
|
295
|
+
})
|
|
281
296
|
})
|
|
282
297
|
|
|
283
298
|
describe('binary data', () => {
|
|
284
299
|
it('should handle Uint8Array as blob column', () => {
|
|
285
300
|
const columnDef = State.SQLite.getColumnDefForSchema(Schema.Uint8Array)
|
|
286
|
-
expect(columnDef.columnType).toBe('
|
|
301
|
+
expect(columnDef.columnType).toBe('blob')
|
|
302
|
+
expect(columnDef.schema.toString()).toBe('Uint8ArrayFromSelf')
|
|
287
303
|
})
|
|
288
304
|
})
|
|
289
305
|
|
|
@@ -381,6 +397,19 @@ describe('getColumnDefForSchema', () => {
|
|
|
381
397
|
expect((table.rowSchema as any).fields.count.toString()).toBe('Int | null')
|
|
382
398
|
})
|
|
383
399
|
|
|
400
|
+
it('should treat unions of string literals as text columns without JSON parsing', () => {
|
|
401
|
+
const schema = Schema.Struct({
|
|
402
|
+
id: Schema.String,
|
|
403
|
+
status: Schema.Literal('idle', 'running', 'stopped'),
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
const table = State.SQLite.table({ name: 'timers', schema })
|
|
407
|
+
|
|
408
|
+
expect(table.sqliteDef.columns.status.columnType).toBe('text')
|
|
409
|
+
expect(table.sqliteDef.columns.status.schema.toString()).toBe('"idle" | "running" | "stopped"')
|
|
410
|
+
expect((table.rowSchema as any).fields.status.toString()).toBe('"idle" | "running" | "stopped"')
|
|
411
|
+
})
|
|
412
|
+
|
|
384
413
|
it('should handle Schema.NullOr with complex types', () => {
|
|
385
414
|
const schema = Schema.Struct({
|
|
386
415
|
data: Schema.NullOr(Schema.Struct({ value: Schema.Number })),
|
|
@@ -539,7 +568,7 @@ describe('getColumnDefForSchema', () => {
|
|
|
539
568
|
|
|
540
569
|
it('should work with column type annotation', () => {
|
|
541
570
|
const UserSchema = Schema.Struct({
|
|
542
|
-
id: Schema.Number.pipe(withColumnType('integer')
|
|
571
|
+
id: Schema.Number.pipe(withColumnType('integer'), withPrimaryKey),
|
|
543
572
|
name: Schema.String,
|
|
544
573
|
})
|
|
545
574
|
|
|
@@ -571,7 +600,7 @@ describe('getColumnDefForSchema', () => {
|
|
|
571
600
|
describe('withAutoIncrement', () => {
|
|
572
601
|
it('should add autoIncrement annotation to schema', () => {
|
|
573
602
|
const UserSchema = Schema.Struct({
|
|
574
|
-
id: Schema.Int.pipe(withPrimaryKey
|
|
603
|
+
id: Schema.Int.pipe(withPrimaryKey, withAutoIncrement),
|
|
575
604
|
name: Schema.String,
|
|
576
605
|
})
|
|
577
606
|
const userTable = State.SQLite.table({
|
|
@@ -623,6 +652,29 @@ describe('getColumnDefForSchema', () => {
|
|
|
623
652
|
table2.sqliteDef.columns.count.default._tag === 'Some' && table2.sqliteDef.columns.count.default.value,
|
|
624
653
|
).toBe(0)
|
|
625
654
|
})
|
|
655
|
+
|
|
656
|
+
it('should support thunk defaults without eager evaluation', () => {
|
|
657
|
+
let counter = 0
|
|
658
|
+
const UserSchema = Schema.Struct({
|
|
659
|
+
id: Schema.String.pipe(
|
|
660
|
+
withDefault(() => {
|
|
661
|
+
counter += 1
|
|
662
|
+
return `user-${counter}`
|
|
663
|
+
}),
|
|
664
|
+
),
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
const table = State.SQLite.table({ name: 'users_with_thunk', schema: UserSchema })
|
|
668
|
+
|
|
669
|
+
expect(counter).toBe(0)
|
|
670
|
+
expect(table.sqliteDef.columns.id.default._tag).toBe('Some')
|
|
671
|
+
if (table.sqliteDef.columns.id.default._tag === 'Some') {
|
|
672
|
+
const defaultThunk = table.sqliteDef.columns.id.default.value
|
|
673
|
+
assert(typeof defaultThunk === 'function')
|
|
674
|
+
expect(defaultThunk()).toBe('user-1')
|
|
675
|
+
expect(defaultThunk()).toBe('user-2')
|
|
676
|
+
}
|
|
677
|
+
})
|
|
626
678
|
})
|
|
627
679
|
|
|
628
680
|
describe('withUnique', () => {
|
|
@@ -668,7 +720,7 @@ describe('getColumnDefForSchema', () => {
|
|
|
668
720
|
|
|
669
721
|
describe('combined annotations', () => {
|
|
670
722
|
it('should work with multiple annotations', () => {
|
|
671
|
-
const schema = Schema.Uint8ArrayFromBase64.pipe(withColumnType('blob')
|
|
723
|
+
const schema = Schema.Uint8ArrayFromBase64.pipe(withColumnType('blob'), withPrimaryKey)
|
|
672
724
|
|
|
673
725
|
const UserSchema = Schema.Struct({
|
|
674
726
|
id: schema,
|
|
@@ -686,7 +738,7 @@ describe('getColumnDefForSchema', () => {
|
|
|
686
738
|
|
|
687
739
|
it('should combine all annotations', () => {
|
|
688
740
|
const UserSchema = Schema.Struct({
|
|
689
|
-
id: Schema.Int.pipe(withPrimaryKey
|
|
741
|
+
id: Schema.Int.pipe(withPrimaryKey, withAutoIncrement),
|
|
690
742
|
email: Schema.String.pipe(withUnique),
|
|
691
743
|
status: Schema.String.pipe(withDefault('active')),
|
|
692
744
|
metadata: Schema.Unknown.pipe(withColumnType('text')),
|
|
@@ -179,26 +179,17 @@ const getColumnForSchema = (schema: Schema.Schema.AnyNoContext, nullable = false
|
|
|
179
179
|
return SqliteDsl.real({ schema: coreSchema, nullable })
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const value = coreAst.literal
|
|
185
|
-
if (typeof value === 'boolean') return SqliteDsl.boolean({ nullable })
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Literals based on their encoded type
|
|
189
|
-
if (SchemaAST.isLiteral(encodedAst)) {
|
|
190
|
-
const value = encodedAst.literal
|
|
191
|
-
if (typeof value === 'string') return SqliteDsl.text({ schema: coreSchema, nullable })
|
|
192
|
-
if (typeof value === 'number') {
|
|
193
|
-
// Check if the original schema is Int
|
|
194
|
-
const id = SchemaAST.getIdentifierAnnotation(coreAst).pipe(Option.getOrElse(() => ''))
|
|
195
|
-
if (id === 'Int') {
|
|
196
|
-
return SqliteDsl.integer({ schema: coreSchema, nullable })
|
|
197
|
-
}
|
|
198
|
-
return SqliteDsl.real({ schema: coreSchema, nullable })
|
|
199
|
-
}
|
|
182
|
+
if (isUint8ArraySchema(coreAst) || isUint8ArraySchema(encodedAst)) {
|
|
183
|
+
return SqliteDsl.blob({ schema: Schema.Uint8ArrayFromSelf as Schema.Schema<Uint8Array<ArrayBuffer>>, nullable })
|
|
200
184
|
}
|
|
201
185
|
|
|
186
|
+
const literalColumn = getLiteralColumnDefinition(encodedAst, coreSchema, nullable, coreAst)
|
|
187
|
+
if (literalColumn) return literalColumn
|
|
188
|
+
|
|
189
|
+
// Fallback to checking the original AST in case the encoded schema differs
|
|
190
|
+
const coreLiteralColumn = getLiteralColumnDefinition(coreAst, coreSchema, nullable, coreAst)
|
|
191
|
+
if (coreLiteralColumn) return coreLiteralColumn
|
|
192
|
+
|
|
202
193
|
// Everything else needs JSON encoding
|
|
203
194
|
return SqliteDsl.json({ schema: coreSchema, nullable })
|
|
204
195
|
}
|
|
@@ -206,10 +197,86 @@ const getColumnForSchema = (schema: Schema.Schema.AnyNoContext, nullable = false
|
|
|
206
197
|
const stripNullable = (ast: SchemaAST.AST): SchemaAST.AST => {
|
|
207
198
|
if (!SchemaAST.isUnion(ast)) return ast
|
|
208
199
|
|
|
209
|
-
//
|
|
210
|
-
const
|
|
200
|
+
// Filter out null/undefined members while preserving any annotations on the union
|
|
201
|
+
const coreTypes = ast.types.filter(
|
|
211
202
|
(type) => !(SchemaAST.isLiteral(type) && type.literal === null) && !SchemaAST.isUndefinedKeyword(type),
|
|
212
203
|
)
|
|
213
204
|
|
|
214
|
-
|
|
205
|
+
if (coreTypes.length === 0 || coreTypes.length === ast.types.length) {
|
|
206
|
+
return ast
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (coreTypes.length === 1) {
|
|
210
|
+
return coreTypes[0]!
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return SchemaAST.Union.make(coreTypes, ast.annotations)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const getLiteralColumnDefinition = (
|
|
217
|
+
ast: SchemaAST.AST,
|
|
218
|
+
schema: Schema.Schema.AnyNoContext,
|
|
219
|
+
nullable: boolean,
|
|
220
|
+
sourceAst: SchemaAST.AST,
|
|
221
|
+
): SqliteDsl.ColumnDefinition.Any | null => {
|
|
222
|
+
const literalValues = extractLiteralValues(ast)
|
|
223
|
+
if (!literalValues) return null
|
|
224
|
+
|
|
225
|
+
const literalType = getLiteralValueType(literalValues)
|
|
226
|
+
switch (literalType) {
|
|
227
|
+
case 'string':
|
|
228
|
+
return SqliteDsl.text({ schema, nullable })
|
|
229
|
+
case 'number': {
|
|
230
|
+
const id = SchemaAST.getIdentifierAnnotation(sourceAst).pipe(Option.getOrElse(() => ''))
|
|
231
|
+
if (id === 'Int' || id === 'DateFromNumber') {
|
|
232
|
+
return SqliteDsl.integer({ schema, nullable })
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const useIntegerColumn =
|
|
236
|
+
literalValues.length > 1 && literalValues.every((value) => typeof value === 'number' && Number.isInteger(value))
|
|
237
|
+
|
|
238
|
+
return useIntegerColumn ? SqliteDsl.integer({ schema, nullable }) : SqliteDsl.real({ schema, nullable })
|
|
239
|
+
}
|
|
240
|
+
case 'boolean':
|
|
241
|
+
return SqliteDsl.boolean({ nullable })
|
|
242
|
+
case 'bigint':
|
|
243
|
+
return SqliteDsl.integer({ schema, nullable })
|
|
244
|
+
default:
|
|
245
|
+
return null
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const extractLiteralValues = (ast: SchemaAST.AST): ReadonlyArray<SchemaAST.LiteralValue> | null => {
|
|
250
|
+
if (SchemaAST.isLiteral(ast)) return [ast.literal]
|
|
251
|
+
|
|
252
|
+
if (SchemaAST.isUnion(ast) && ast.types.length > 0 && ast.types.every((type) => SchemaAST.isLiteral(type))) {
|
|
253
|
+
return ast.types.map((type) => (type as SchemaAST.Literal).literal)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return null
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const getLiteralValueType = (
|
|
260
|
+
literals: ReadonlyArray<SchemaAST.LiteralValue>,
|
|
261
|
+
): 'string' | 'number' | 'boolean' | 'bigint' | null => {
|
|
262
|
+
const literalTypes = new Set(literals.map((value) => (value === null ? 'null' : typeof value)))
|
|
263
|
+
if (literalTypes.size !== 1) return null
|
|
264
|
+
|
|
265
|
+
const [literalType] = literalTypes
|
|
266
|
+
return literalType === 'string' || literalType === 'number' || literalType === 'boolean' || literalType === 'bigint'
|
|
267
|
+
? literalType
|
|
268
|
+
: null
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const isUint8ArraySchema = (ast: SchemaAST.AST): boolean => {
|
|
272
|
+
const identifier = SchemaAST.getIdentifierAnnotation(ast)
|
|
273
|
+
if (Option.isSome(identifier) && identifier.value.includes('Uint8Array')) {
|
|
274
|
+
return true
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (SchemaAST.isTupleType(ast)) {
|
|
278
|
+
return ast.elements.length === 0 && ast.rest.length === 1 && SchemaAST.isNumberKeyword(ast.rest[0]!.type)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return false
|
|
215
282
|
}
|
|
@@ -56,9 +56,9 @@ describe('makeColumnSpec', () => {
|
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
const result = makeColumnSpec(table)
|
|
59
|
-
expect(result).toMatchInlineSnapshot(`"
|
|
60
|
-
expect(result).toContain("
|
|
61
|
-
expect(result).toContain("
|
|
59
|
+
expect(result).toMatchInlineSnapshot(`""order" integer not null , "group" text "`)
|
|
60
|
+
expect(result).toContain('"order"')
|
|
61
|
+
expect(result).toContain('"group"')
|
|
62
62
|
})
|
|
63
63
|
|
|
64
64
|
it('should handle basic columns with primary keys', () => {
|
|
@@ -69,8 +69,7 @@ describe('makeColumnSpec', () => {
|
|
|
69
69
|
)
|
|
70
70
|
|
|
71
71
|
const result = makeColumnSpec(table)
|
|
72
|
-
expect(result).toMatchInlineSnapshot(`"
|
|
73
|
-
expect(result).toContain("PRIMARY KEY ('id')")
|
|
72
|
+
expect(result).toMatchInlineSnapshot(`""id" text primary key , "name" text "`)
|
|
74
73
|
})
|
|
75
74
|
|
|
76
75
|
it('should handle multi-column primary keys', () => {
|
|
@@ -85,9 +84,9 @@ describe('makeColumnSpec', () => {
|
|
|
85
84
|
|
|
86
85
|
const result = makeColumnSpec(table)
|
|
87
86
|
expect(result).toMatchInlineSnapshot(
|
|
88
|
-
`"
|
|
87
|
+
`""tenant_id" text not null , "user_id" text not null , PRIMARY KEY ("tenant_id", "user_id")"`,
|
|
89
88
|
)
|
|
90
|
-
expect(result).toContain(
|
|
89
|
+
expect(result).toContain('PRIMARY KEY ("tenant_id", "user_id")')
|
|
91
90
|
})
|
|
92
91
|
|
|
93
92
|
it('should handle auto-increment columns', () => {
|
|
@@ -101,9 +100,9 @@ describe('makeColumnSpec', () => {
|
|
|
101
100
|
)
|
|
102
101
|
|
|
103
102
|
const result = makeColumnSpec(table)
|
|
104
|
-
expect(result).toMatchInlineSnapshot(`"
|
|
103
|
+
expect(result).toMatchInlineSnapshot(`""id" integer primary key autoincrement , "title" text "`)
|
|
105
104
|
expect(result).toContain('autoincrement')
|
|
106
|
-
expect(result).toContain("PRIMARY KEY ('id')")
|
|
105
|
+
expect(result).not.toContain("PRIMARY KEY ('id')")
|
|
107
106
|
})
|
|
108
107
|
|
|
109
108
|
it('should handle columns with default values', () => {
|
|
@@ -121,7 +120,7 @@ describe('makeColumnSpec', () => {
|
|
|
121
120
|
|
|
122
121
|
const result = makeColumnSpec(table)
|
|
123
122
|
expect(result).toMatchInlineSnapshot(
|
|
124
|
-
`"
|
|
123
|
+
`""id" integer primary key , "name" text not null , "price" real default 0, "active" integer default true, "description" text default 'No description'"`,
|
|
125
124
|
)
|
|
126
125
|
expect(result).toContain('default 0')
|
|
127
126
|
expect(result).toContain('default true')
|
|
@@ -141,12 +140,28 @@ describe('makeColumnSpec', () => {
|
|
|
141
140
|
|
|
142
141
|
const result = makeColumnSpec(table)
|
|
143
142
|
expect(result).toMatchInlineSnapshot(
|
|
144
|
-
`"
|
|
143
|
+
`""id" integer primary key , "created_at" text default CURRENT_TIMESTAMP, "random_value" real default RANDOM()"`,
|
|
145
144
|
)
|
|
146
145
|
expect(result).toContain('default CURRENT_TIMESTAMP')
|
|
147
146
|
expect(result).toContain('default RANDOM()')
|
|
148
147
|
})
|
|
149
148
|
|
|
149
|
+
it('should omit default clause for thunk defaults', () => {
|
|
150
|
+
const table = SqliteAst.table(
|
|
151
|
+
'thunks',
|
|
152
|
+
[
|
|
153
|
+
createColumn('id', 'integer', { nullable: false, primaryKey: true }),
|
|
154
|
+
createColumn('token', 'text', { defaultValue: () => 'dynamic-token' }),
|
|
155
|
+
],
|
|
156
|
+
[],
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
const result = makeColumnSpec(table)
|
|
160
|
+
expect(result).toMatchInlineSnapshot(`""id" integer primary key , "token" text "`)
|
|
161
|
+
expect(result).not.toContain('dynamic-token')
|
|
162
|
+
expect(result).not.toMatch(/token" text\s+default/i)
|
|
163
|
+
})
|
|
164
|
+
|
|
150
165
|
it('should handle null default values', () => {
|
|
151
166
|
const table = SqliteAst.table(
|
|
152
167
|
'nullable_defaults',
|
|
@@ -158,9 +173,7 @@ describe('makeColumnSpec', () => {
|
|
|
158
173
|
)
|
|
159
174
|
|
|
160
175
|
const result = makeColumnSpec(table)
|
|
161
|
-
expect(result).toMatchInlineSnapshot(
|
|
162
|
-
`"'id' integer not null , 'optional_text' text default null, PRIMARY KEY ('id')"`,
|
|
163
|
-
)
|
|
176
|
+
expect(result).toMatchInlineSnapshot(`""id" integer primary key , "optional_text" text default null"`)
|
|
164
177
|
expect(result).toContain('default null')
|
|
165
178
|
})
|
|
166
179
|
|
|
@@ -190,7 +203,7 @@ describe('makeColumnSpec', () => {
|
|
|
190
203
|
|
|
191
204
|
const result = makeColumnSpec(table)
|
|
192
205
|
expect(result).toMatchInlineSnapshot(
|
|
193
|
-
`"
|
|
206
|
+
`""id" integer primary key autoincrement , "name" text not null default 'Unnamed', "created_at" text not null default CURRENT_TIMESTAMP, "status" text default 'pending'"`,
|
|
194
207
|
)
|
|
195
208
|
})
|
|
196
209
|
|
|
@@ -213,7 +226,7 @@ describe('makeColumnSpec', () => {
|
|
|
213
226
|
const result = makeColumnSpec(table)
|
|
214
227
|
// The makeColumnSpec function only generates column specifications, not indexes
|
|
215
228
|
expect(result).toMatchInlineSnapshot(
|
|
216
|
-
`"
|
|
229
|
+
`""id" integer primary key autoincrement , "email" text not null , "username" text not null , "created_at" text default CURRENT_TIMESTAMP"`,
|
|
217
230
|
)
|
|
218
231
|
// Verify the table has the indexes (even though they're not in the column spec)
|
|
219
232
|
expect(table.indexes).toHaveLength(3)
|