@livestore/common 0.4.0-dev.2 → 0.4.0-dev.20
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 +17 -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 +36 -29
- package/dist/devtools/devtools-messages-leader.d.ts.map +1 -1
- package/dist/devtools/devtools-messages-leader.js +8 -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 +8 -4
- package/dist/leader-thread/LeaderSyncProcessor.d.ts.map +1 -1
- package/dist/leader-thread/LeaderSyncProcessor.js +156 -73
- package/dist/leader-thread/LeaderSyncProcessor.js.map +1 -1
- package/dist/leader-thread/eventlog.d.ts +15 -21
- package/dist/leader-thread/eventlog.d.ts.map +1 -1
- package/dist/leader-thread/eventlog.js +18 -18
- 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 +30 -42
- 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/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/types.d.ts +21 -19
- package/dist/leader-thread/types.d.ts.map +1 -1
- 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/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 +46 -7
- 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 +17 -10
- 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 +17 -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 +8 -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 +242 -103
- package/src/leader-thread/eventlog.ts +33 -34
- package/src/leader-thread/leader-worker-devtools.ts +50 -54
- 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/recreate-db.ts +15 -7
- package/src/leader-thread/shutdown-channel.ts +16 -2
- package/src/leader-thread/types.ts +21 -19
- package/src/logging.ts +62 -0
- package/src/make-client-session.ts +9 -3
- package/src/materializer-helper.ts +27 -10
- 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 +120 -8
- 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 +60 -7
- 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 +2 -1
- package/src/schema/state/sqlite/mod.ts +4 -3
- package/src/schema/state/sqlite/query-builder/api.ts +19 -10
- 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 +9 -8
- 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
|
@@ -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)
|
|
@@ -10,33 +10,58 @@ import { type SqliteAst, SqliteDsl } from './db-schema/mod.ts'
|
|
|
10
10
|
* ```
|
|
11
11
|
*/
|
|
12
12
|
export const makeColumnSpec = (tableAst: SqliteAst.Table) => {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
13
|
+
const pkColumns = tableAst.columns.filter((_) => _.primaryKey)
|
|
14
|
+
const hasSinglePk = pkColumns.length === 1
|
|
15
|
+
const pkColumn = hasSinglePk ? pkColumns[0] : undefined
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// Build column definitions, handling the special SQLite rule that AUTOINCREMENT
|
|
18
|
+
// is only valid on a single column declared as INTEGER PRIMARY KEY (column-level).
|
|
19
|
+
const columnDefStrs = tableAst.columns.map((column) =>
|
|
20
|
+
toSqliteColumnSpec(column, {
|
|
21
|
+
inlinePrimaryKey: hasSinglePk && column === pkColumn && column.primaryKey === true,
|
|
22
|
+
}),
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// For composite primary keys, add a table-level PRIMARY KEY clause.
|
|
26
|
+
if (pkColumns.length > 1) {
|
|
27
|
+
const quotedPkCols = pkColumns.map((_) => `"${_.name}"`)
|
|
28
|
+
columnDefStrs.push(`PRIMARY KEY (${quotedPkCols.join(', ')})`)
|
|
18
29
|
}
|
|
19
30
|
|
|
20
31
|
return columnDefStrs.join(', ')
|
|
21
32
|
}
|
|
22
33
|
|
|
23
34
|
/** NOTE primary keys are applied on a table level not on a column level to account for multi-column primary keys */
|
|
24
|
-
const toSqliteColumnSpec = (column: SqliteAst.Column) => {
|
|
35
|
+
const toSqliteColumnSpec = (column: SqliteAst.Column, opts: { inlinePrimaryKey: boolean }) => {
|
|
25
36
|
const columnTypeStr = column.type._tag
|
|
26
|
-
|
|
27
|
-
|
|
37
|
+
// When PRIMARY KEY is declared inline, NOT NULL is implied and should not be emitted,
|
|
38
|
+
// and AUTOINCREMENT must immediately follow PRIMARY KEY within the same constraint.
|
|
39
|
+
const nullableStr = opts.inlinePrimaryKey ? '' : column.nullable === false ? 'not null' : ''
|
|
40
|
+
|
|
41
|
+
// Only include AUTOINCREMENT when it's valid: single-column INTEGER PRIMARY KEY
|
|
42
|
+
const includeAutoIncrement = opts.inlinePrimaryKey && column.type._tag === 'integer' && column.autoIncrement === true
|
|
43
|
+
|
|
44
|
+
const pkStr = opts.inlinePrimaryKey ? 'primary key' : ''
|
|
45
|
+
const autoIncrementStr = includeAutoIncrement ? 'autoincrement' : ''
|
|
46
|
+
|
|
28
47
|
const defaultValueStr = (() => {
|
|
29
48
|
if (column.default._tag === 'None') return ''
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
if (SqliteDsl.
|
|
50
|
+
const defaultValue = column.default.value
|
|
51
|
+
if (SqliteDsl.isDefaultThunk(defaultValue)) return ''
|
|
52
|
+
|
|
53
|
+
const resolvedDefault = SqliteDsl.resolveColumnDefault(defaultValue)
|
|
54
|
+
|
|
55
|
+
if (resolvedDefault === null) return 'default null'
|
|
56
|
+
if (SqliteDsl.isSqlDefaultValue(resolvedDefault)) return `default ${resolvedDefault.sql}`
|
|
33
57
|
|
|
34
58
|
const encodeValue = Schema.encodeSync(column.schema)
|
|
35
|
-
const encodedDefaultValue = encodeValue(
|
|
59
|
+
const encodedDefaultValue = encodeValue(resolvedDefault)
|
|
36
60
|
|
|
37
61
|
if (columnTypeStr === 'text') return `default '${encodedDefaultValue}'`
|
|
38
62
|
return `default ${encodedDefaultValue}`
|
|
39
63
|
})()
|
|
40
64
|
|
|
41
|
-
|
|
65
|
+
// Ensure order: PRIMARY KEY [AUTOINCREMENT] [NOT NULL] ...
|
|
66
|
+
return `"${column.name}" ${columnTypeStr} ${pkStr} ${autoIncrementStr} ${nullableStr} ${defaultValueStr}`
|
|
42
67
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { omitUndefineds } from '@livestore/utils'
|
|
2
|
+
import { type Option, Schema, SchemaAST } from '@livestore/utils/effect'
|
|
2
3
|
|
|
3
4
|
import { hashCode } from '../hash.ts'
|
|
4
5
|
|
|
@@ -45,9 +46,7 @@ export const index = (
|
|
|
45
46
|
): Index => ({
|
|
46
47
|
_tag: 'index',
|
|
47
48
|
columns,
|
|
48
|
-
name,
|
|
49
|
-
unique,
|
|
50
|
-
primaryKey,
|
|
49
|
+
...omitUndefineds({ name, unique, primaryKey }),
|
|
51
50
|
})
|
|
52
51
|
|
|
53
52
|
export type ForeignKey = {
|
|
@@ -85,7 +84,19 @@ export type DbSchema = {
|
|
|
85
84
|
export const dbSchema = (tables: Table[]): DbSchema => ({ _tag: 'dbSchema', tables })
|
|
86
85
|
|
|
87
86
|
/**
|
|
88
|
-
*
|
|
87
|
+
* Helper to detect if a column is a JSON column (has parseJson transformation)
|
|
88
|
+
*/
|
|
89
|
+
const isJsonColumn = (column: Column): boolean => {
|
|
90
|
+
if (column.type._tag !== 'text') return false
|
|
91
|
+
|
|
92
|
+
// Check if the schema AST is a parseJson transformation
|
|
93
|
+
const ast = column.schema.ast
|
|
94
|
+
return ast._tag === 'Transformation' && ast.annotations.schemaId === SchemaAST.ParseJsonSchemaId
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* NOTE we're now including JSON schema information for JSON columns
|
|
99
|
+
* to detect client document schema changes
|
|
89
100
|
*/
|
|
90
101
|
export const hash = (obj: Table | Column | Index | ForeignKey | DbSchema): number =>
|
|
91
102
|
hashCode(JSON.stringify(trimInfoForHasing(obj)))
|
|
@@ -101,7 +112,7 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
|
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
case 'column': {
|
|
104
|
-
|
|
115
|
+
const baseInfo: Record<string, any> = {
|
|
105
116
|
_tag: 'column',
|
|
106
117
|
name: obj.name,
|
|
107
118
|
type: obj.type._tag,
|
|
@@ -110,6 +121,15 @@ const trimInfoForHasing = (obj: Table | Column | Index | ForeignKey | DbSchema):
|
|
|
110
121
|
autoIncrement: obj.autoIncrement,
|
|
111
122
|
default: obj.default,
|
|
112
123
|
}
|
|
124
|
+
|
|
125
|
+
// NEW: Include schema hash for JSON columns
|
|
126
|
+
// This ensures that changes to the JSON schema are detected
|
|
127
|
+
if (isJsonColumn(obj) && obj.schema) {
|
|
128
|
+
// Use Effect's Schema.hash for consistent hashing
|
|
129
|
+
baseInfo.jsonSchemaHash = Schema.hash(obj.schema)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return baseInfo
|
|
113
133
|
}
|
|
114
134
|
case 'index': {
|
|
115
135
|
return {
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import { casesHandled } from '@livestore/utils'
|
|
2
2
|
import { Option, Schema } from '@livestore/utils/effect'
|
|
3
3
|
|
|
4
|
+
export type SqlDefaultValue = {
|
|
5
|
+
readonly sql: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const isSqlDefaultValue = (value: unknown): value is SqlDefaultValue => {
|
|
9
|
+
return typeof value === 'object' && value !== null && 'sql' in value && typeof (value as any).sql === 'string'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ColumnDefaultThunk<T> = () => T
|
|
13
|
+
|
|
14
|
+
export const isDefaultThunk = (value: unknown): value is ColumnDefaultThunk<unknown> => typeof value === 'function'
|
|
15
|
+
|
|
16
|
+
export type ColumnDefaultValue<T> = T | null | ColumnDefaultThunk<T | null> | SqlDefaultValue
|
|
17
|
+
|
|
18
|
+
export const resolveColumnDefault = <T>(value: ColumnDefaultValue<T>): T | null | SqlDefaultValue =>
|
|
19
|
+
isDefaultThunk(value) ? (value as ColumnDefaultThunk<T | null>)() : value
|
|
20
|
+
|
|
4
21
|
export type ColumnDefinition<TEncoded, TDecoded> = {
|
|
5
22
|
readonly columnType: FieldColumnType
|
|
6
23
|
readonly schema: Schema.Schema<TDecoded, TEncoded>
|
|
7
|
-
readonly default: Option.Option<
|
|
24
|
+
readonly default: Option.Option<ColumnDefaultValue<TDecoded>>
|
|
8
25
|
/** @default false */
|
|
9
26
|
readonly nullable: boolean
|
|
10
27
|
/** @default false */
|
|
@@ -27,9 +44,17 @@ export const isColumnDefinition = (value: unknown): value is ColumnDefinition.An
|
|
|
27
44
|
)
|
|
28
45
|
}
|
|
29
46
|
|
|
47
|
+
type MaybeNull<T, TNullable extends boolean> = T | (TNullable extends true ? null : never)
|
|
48
|
+
|
|
49
|
+
type ColumnDefaultArg<T, TNullable extends boolean> =
|
|
50
|
+
| MaybeNull<T, TNullable>
|
|
51
|
+
| ColumnDefaultThunk<MaybeNull<T, TNullable>>
|
|
52
|
+
| SqlDefaultValue
|
|
53
|
+
| NoDefault
|
|
54
|
+
|
|
30
55
|
export type ColumnDefinitionInput = {
|
|
31
56
|
readonly schema?: Schema.Schema<unknown>
|
|
32
|
-
readonly default?: unknown
|
|
57
|
+
readonly default?: ColumnDefaultArg<unknown, boolean>
|
|
33
58
|
readonly nullable?: boolean
|
|
34
59
|
readonly primaryKey?: boolean
|
|
35
60
|
readonly autoIncrement?: boolean
|
|
@@ -38,14 +63,6 @@ export type ColumnDefinitionInput = {
|
|
|
38
63
|
export const NoDefault = Symbol.for('NoDefault')
|
|
39
64
|
export type NoDefault = typeof NoDefault
|
|
40
65
|
|
|
41
|
-
export type SqlDefaultValue = {
|
|
42
|
-
readonly sql: string
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const isSqlDefaultValue = (value: unknown): value is SqlDefaultValue => {
|
|
46
|
-
return typeof value === 'object' && value !== null && 'sql' in value && typeof value.sql === 'string'
|
|
47
|
-
}
|
|
48
|
-
|
|
49
66
|
export type ColDefFn<TColumnType extends FieldColumnType> = {
|
|
50
67
|
(): {
|
|
51
68
|
columnType: TColumnType
|
|
@@ -59,7 +76,7 @@ export type ColDefFn<TColumnType extends FieldColumnType> = {
|
|
|
59
76
|
TEncoded extends DefaultEncodedForColumnType<TColumnType>,
|
|
60
77
|
TDecoded = DefaultEncodedForColumnType<TColumnType>,
|
|
61
78
|
const TNullable extends boolean = false,
|
|
62
|
-
const TDefault extends TDecoded
|
|
79
|
+
const TDefault extends ColumnDefaultArg<NoInfer<TDecoded>, TNullable> = NoDefault,
|
|
63
80
|
const TPrimaryKey extends boolean = false,
|
|
64
81
|
const TAutoIncrement extends boolean = false,
|
|
65
82
|
>(args: {
|
|
@@ -132,7 +149,7 @@ export type SpecializedColDefFn<
|
|
|
132
149
|
<
|
|
133
150
|
TDecoded = TBaseDecoded,
|
|
134
151
|
const TNullable extends boolean = false,
|
|
135
|
-
const TDefault extends TDecoded
|
|
152
|
+
const TDefault extends ColumnDefaultArg<NoInfer<TDecoded>, TNullable> = NoDefault,
|
|
136
153
|
const TPrimaryKey extends boolean = false,
|
|
137
154
|
const TAutoIncrement extends boolean = false,
|
|
138
155
|
>(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Nullable } from '@livestore/utils'
|
|
2
|
+
import { omitUndefineds } from '@livestore/utils'
|
|
2
3
|
import type { Option, Types } from '@livestore/utils/effect'
|
|
3
4
|
import { Schema } from '@livestore/utils/effect'
|
|
4
5
|
|
|
@@ -46,7 +47,7 @@ export const table = <TTableName extends string, TColumns extends Columns, TInde
|
|
|
46
47
|
indexes: indexesToAst(indexes ?? []),
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
return { name, columns, indexes, ast }
|
|
50
|
+
return { name, columns, ...omitUndefineds({ indexes }), ast }
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
export type AnyIfConstained<In, Out> = '__constrained' extends keyof In ? any : Out
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
2
2
|
|
|
3
3
|
import type { MigrationOptions } from '../../../adapter-types.ts'
|
|
4
|
-
import type { Materializer } from '../../EventDef.ts'
|
|
4
|
+
import type { Materializer } from '../../EventDef/mod.ts'
|
|
5
5
|
import type { InternalState } from '../../schema.ts'
|
|
6
6
|
import { ClientDocumentTableDefSymbol, tableIsClientDocumentTable } from './client-document-def.ts'
|
|
7
7
|
import { SqliteAst } from './db-schema/mod.ts'
|
|
8
|
-
import { stateSystemTables } from './system-tables.ts'
|
|
8
|
+
import { stateSystemTables } from './system-tables/state-tables.ts'
|
|
9
9
|
import type { TableDef, TableDefBase } from './table-def.ts'
|
|
10
10
|
|
|
11
|
-
export * from '../../EventDef.ts'
|
|
11
|
+
export * from '../../EventDef/mod.ts'
|
|
12
12
|
export {
|
|
13
13
|
type ClientDocumentTableDef,
|
|
14
14
|
ClientDocumentTableDefSymbol,
|
|
15
15
|
type ClientDocumentTableOptions,
|
|
16
16
|
clientDocument,
|
|
17
|
+
createOptimisticEventSchema,
|
|
17
18
|
tableIsClientDocumentTable,
|
|
18
19
|
} from './client-document-def.ts'
|
|
19
20
|
export * from './column-annotations.ts'
|
|
@@ -3,7 +3,7 @@ import { type Option, Predicate, type Schema } from '@livestore/utils/effect'
|
|
|
3
3
|
|
|
4
4
|
import type { SessionIdSymbol } from '../../../../adapter-types.ts'
|
|
5
5
|
import type { SqlValue } from '../../../../util.ts'
|
|
6
|
-
import type { ClientDocumentTableDef } from '../client-document-def.ts'
|
|
6
|
+
import type { ClientDocumentTableDef, ClientDocumentTableDefSymbol } from '../client-document-def.ts'
|
|
7
7
|
import type { SqliteDsl } from '../db-schema/mod.ts'
|
|
8
8
|
import type { TableDefBase } from '../table-def.ts'
|
|
9
9
|
|
|
@@ -347,22 +347,26 @@ export namespace QueryBuilder {
|
|
|
347
347
|
>
|
|
348
348
|
|
|
349
349
|
/**
|
|
350
|
-
*
|
|
350
|
+
* Upsert: insert a row, or handle conflicts on existing rows.
|
|
351
|
+
* Equivalent to SQLite's `INSERT ... ON CONFLICT` clause.
|
|
352
|
+
*
|
|
353
|
+
* Actions:
|
|
354
|
+
* - `'ignore'`: Skip the insert if a row with the same key exists
|
|
355
|
+
* - `'replace'`: Delete the existing row and insert the new one
|
|
356
|
+
* - `'update'`: Update specific columns on the existing row
|
|
357
|
+
*
|
|
351
358
|
* ```ts
|
|
359
|
+
* // Ignore: skip if row exists
|
|
352
360
|
* db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'ignore')
|
|
353
|
-
* ```
|
|
354
361
|
*
|
|
355
|
-
*
|
|
356
|
-
* ```ts
|
|
362
|
+
* // Replace: delete existing row and insert new one
|
|
357
363
|
* db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'replace')
|
|
358
|
-
* ```
|
|
359
364
|
*
|
|
360
|
-
*
|
|
361
|
-
* ```ts
|
|
365
|
+
* // Update: merge specific columns into existing row
|
|
362
366
|
* db.todos.insert({ id: '123', text: 'Buy milk', status: 'active' }).onConflict('id', 'update', { text: 'Buy soy milk' })
|
|
363
367
|
* ```
|
|
364
368
|
*
|
|
365
|
-
* NOTE
|
|
369
|
+
* NOTE: Composite primary keys are not yet supported.
|
|
366
370
|
*/
|
|
367
371
|
readonly onConflict: {
|
|
368
372
|
<TTarget extends SingleOrReadonlyArray<keyof TTableDef['sqliteDef']['columns']>>(
|
|
@@ -437,7 +441,12 @@ export namespace QueryBuilder {
|
|
|
437
441
|
|
|
438
442
|
export namespace RowQuery {
|
|
439
443
|
export type GetOrCreateOptions<TTableDef extends ClientDocumentTableDef.TraitAny> = {
|
|
440
|
-
|
|
444
|
+
/**
|
|
445
|
+
* Default value to use instead of the default value from the table definition
|
|
446
|
+
*/
|
|
447
|
+
default: TTableDef[ClientDocumentTableDefSymbol]['options']['partialSet'] extends false
|
|
448
|
+
? TTableDef['Value']
|
|
449
|
+
: Partial<TTableDef['Value']>
|
|
441
450
|
}
|
|
442
451
|
|
|
443
452
|
// TODO get rid of this
|
|
@@ -7,6 +7,8 @@ import type { State } from '../../../mod.ts'
|
|
|
7
7
|
import type { QueryBuilderAst } from './api.ts'
|
|
8
8
|
|
|
9
9
|
// Helper functions for SQL generation
|
|
10
|
+
const quoteIdentifier = (identifier: string): string => `"${identifier.replace(/"/g, '""')}"`
|
|
11
|
+
|
|
10
12
|
const formatWhereClause = (
|
|
11
13
|
whereConditions: ReadonlyArray<QueryBuilderAst.Where>,
|
|
12
14
|
tableDef: State.SQLite.TableDefBase,
|
|
@@ -16,13 +18,15 @@ const formatWhereClause = (
|
|
|
16
18
|
|
|
17
19
|
const whereClause = whereConditions
|
|
18
20
|
.map(({ col, op, value }) => {
|
|
21
|
+
const quotedCol = quoteIdentifier(col)
|
|
22
|
+
|
|
19
23
|
// Handle NULL values
|
|
20
24
|
if (value === null) {
|
|
21
25
|
if (op !== '=' && op !== '!=') {
|
|
22
26
|
throw new Error(`Unsupported operator for NULL value: ${op}`)
|
|
23
27
|
}
|
|
24
28
|
const opStmt = op === '=' ? 'IS' : 'IS NOT'
|
|
25
|
-
return `${
|
|
29
|
+
return `${quotedCol} ${opStmt} NULL`
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
// Get column definition and encode value
|
|
@@ -48,11 +52,11 @@ const formatWhereClause = (
|
|
|
48
52
|
const encodedValues = value.map((v) => Schema.encodeSync(colDef.schema)(v)) as SqlValue[]
|
|
49
53
|
bindValues.push(...encodedValues)
|
|
50
54
|
const placeholders = encodedValues.map(() => '?').join(', ')
|
|
51
|
-
return `${
|
|
55
|
+
return `${quotedCol} ${op} (${placeholders})`
|
|
52
56
|
} else {
|
|
53
57
|
const encodedValue = Schema.encodeSync(colDef.schema)(value)
|
|
54
58
|
bindValues.push(encodedValue as SqlValue)
|
|
55
|
-
return `${
|
|
59
|
+
return `${quotedCol} ${op} ?`
|
|
56
60
|
}
|
|
57
61
|
})
|
|
58
62
|
.join(' AND ')
|
|
@@ -62,7 +66,7 @@ const formatWhereClause = (
|
|
|
62
66
|
|
|
63
67
|
const formatReturningClause = (returning?: string[]): string => {
|
|
64
68
|
if (!returning || returning.length === 0) return ''
|
|
65
|
-
return ` RETURNING ${returning.join(', ')}`
|
|
69
|
+
return ` RETURNING ${returning.map(quoteIdentifier).join(', ')}`
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: SqlValue[]; usedTables: Set<string> } => {
|
|
@@ -72,6 +76,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
72
76
|
// INSERT query
|
|
73
77
|
if (ast._tag === 'InsertQuery') {
|
|
74
78
|
const columns = Object.keys(ast.values)
|
|
79
|
+
const quotedColumns = columns.map(quoteIdentifier)
|
|
75
80
|
const placeholders = columns.map(() => '?').join(', ')
|
|
76
81
|
const encodedValues = Schema.encodeSync(ast.tableDef.insertSchema)(ast.values)
|
|
77
82
|
|
|
@@ -91,7 +96,8 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
91
96
|
// For REPLACE, the conflict target is implied and no further clause is needed
|
|
92
97
|
} else {
|
|
93
98
|
// Build the ON CONFLICT clause for IGNORE or UPDATE
|
|
94
|
-
|
|
99
|
+
const conflictTargets = ast.onConflict.targets.map(quoteIdentifier).join(', ')
|
|
100
|
+
conflictClause = ` ON CONFLICT (${conflictTargets}) `
|
|
95
101
|
if (ast.onConflict.action._tag === 'ignore') {
|
|
96
102
|
conflictClause += 'DO NOTHING'
|
|
97
103
|
} else {
|
|
@@ -105,8 +111,9 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
105
111
|
const updates = updateCols
|
|
106
112
|
.map((col) => {
|
|
107
113
|
const value = updateValues[col]
|
|
114
|
+
const quotedCol = quoteIdentifier(col)
|
|
108
115
|
// If the value is undefined, use excluded.col
|
|
109
|
-
return value === undefined ? `${
|
|
116
|
+
return value === undefined ? `${quotedCol} = excluded.${quotedCol}` : `${quotedCol} = ?`
|
|
110
117
|
})
|
|
111
118
|
.join(', ')
|
|
112
119
|
|
|
@@ -129,7 +136,7 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
129
136
|
}
|
|
130
137
|
|
|
131
138
|
// Construct the main query part
|
|
132
|
-
let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${
|
|
139
|
+
let query = `${insertVerb} INTO '${ast.tableDef.sqliteDef.name}' (${quotedColumns.join(', ')}) VALUES (${placeholders})`
|
|
133
140
|
|
|
134
141
|
// Append the conflict clause if it was generated (i.e., not for REPLACE)
|
|
135
142
|
query += conflictClause
|
|
@@ -157,7 +164,9 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
157
164
|
bindValues.push(encodedValues[col] as SqlValue)
|
|
158
165
|
})
|
|
159
166
|
|
|
160
|
-
let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns
|
|
167
|
+
let query = `UPDATE '${ast.tableDef.sqliteDef.name}' SET ${setColumns
|
|
168
|
+
.map((col) => `${quoteIdentifier(col)} = ?`)
|
|
169
|
+
.join(', ')}`
|
|
161
170
|
|
|
162
171
|
const whereClause = formatWhereClause(ast.where, ast.tableDef, bindValues)
|
|
163
172
|
if (whereClause) query += ` ${whereClause}`
|
|
@@ -201,31 +210,31 @@ export const astToSql = (ast: QueryBuilderAst): { query: string; bindValues: Sql
|
|
|
201
210
|
const encodedId = ast.id === SessionIdSymbol ? ast.id : Schema.encodeSync(idColDef.schema)(ast.id)
|
|
202
211
|
|
|
203
212
|
return {
|
|
204
|
-
query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE id = ?`,
|
|
213
|
+
query: `SELECT * FROM '${ast.tableDef.sqliteDef.name}' WHERE ${quoteIdentifier('id')} = ?`,
|
|
205
214
|
bindValues: [encodedId as SqlValue],
|
|
206
215
|
usedTables,
|
|
207
216
|
}
|
|
208
217
|
}
|
|
209
218
|
|
|
210
219
|
// SELECT query
|
|
211
|
-
const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.join(', ')
|
|
220
|
+
const columnsStmt = ast.select.columns.length === 0 ? '*' : ast.select.columns.map(quoteIdentifier).join(', ')
|
|
212
221
|
const selectStmt = `SELECT ${columnsStmt}`
|
|
213
222
|
const fromStmt = `FROM '${ast.tableDef.sqliteDef.name}'`
|
|
214
223
|
const whereStmt = formatWhereClause(ast.where, ast.tableDef, bindValues)
|
|
215
224
|
|
|
216
225
|
const orderByStmt =
|
|
217
226
|
ast.orderBy.length > 0
|
|
218
|
-
? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${col} ${direction}`).join(', ')}`
|
|
227
|
+
? `ORDER BY ${ast.orderBy.map(({ col, direction }) => `${quoteIdentifier(col)} ${direction}`).join(', ')}`
|
|
219
228
|
: ''
|
|
220
229
|
|
|
221
230
|
const limitStmt = ast.limit._tag === 'Some' ? `LIMIT ?` : ''
|
|
222
231
|
const offsetStmt = ast.offset._tag === 'Some' ? `OFFSET ?` : ''
|
|
223
232
|
|
|
224
|
-
// Push
|
|
225
|
-
if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
|
|
233
|
+
// Push limit and offset values in the correct order matching the query string
|
|
226
234
|
if (ast.limit._tag === 'Some') bindValues.push(ast.limit.value)
|
|
235
|
+
if (ast.offset._tag === 'Some') bindValues.push(ast.offset.value)
|
|
227
236
|
|
|
228
|
-
const query = [selectStmt, fromStmt, whereStmt, orderByStmt,
|
|
237
|
+
const query = [selectStmt, fromStmt, whereStmt, orderByStmt, limitStmt, offsetStmt]
|
|
229
238
|
.map((clause) => clause.trim())
|
|
230
239
|
.filter((clause) => clause.length > 0)
|
|
231
240
|
.join(' ')
|