@rocicorp/zero 0.26.0-canary.0 → 0.26.0-canary.3
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/README.md +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +4 -4
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +22 -19
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/refresh.d.ts.map +1 -1
- package/out/replicache/src/persist/refresh.js +0 -8
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/process-scheduler.d.ts +23 -0
- package/out/replicache/src/process-scheduler.d.ts.map +1 -1
- package/out/replicache/src/process-scheduler.js +50 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +8 -0
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +11 -2
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/shared/src/custom-key-map.d.ts +4 -4
- package/out/shared/src/custom-key-map.d.ts.map +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/falsy.d.ts +3 -0
- package/out/shared/src/falsy.d.ts.map +1 -0
- package/out/shared/src/iterables.d.ts +6 -8
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +13 -7
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/options.d.ts +1 -0
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +5 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/adapters/drizzle.js +1 -2
- package/out/zero/src/adapters/prisma.d.ts +2 -0
- package/out/zero/src/adapters/prisma.d.ts.map +1 -0
- package/out/zero/src/adapters/prisma.js +6 -0
- package/out/zero/src/adapters/prisma.js.map +1 -0
- package/out/zero/src/pg.js +4 -7
- package/out/zero/src/react.js +3 -1
- package/out/zero/src/react.js.map +1 -1
- package/out/zero/src/server.js +5 -8
- package/out/zero/src/zero-cache-dev.js +7 -3
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.d.ts +3 -2
- package/out/zero-cache/src/auth/load-permissions.d.ts.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js +14 -8
- package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts +6 -0
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +16 -3
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +54 -9
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +80 -20
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +3 -0
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +26 -0
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +1 -1
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +9 -3
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration.js +9 -3
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/specs.d.ts +4 -3
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +4 -1
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +9 -3
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/observability/events.d.ts.map +1 -1
- package/out/zero-cache/src/observability/events.js +15 -5
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +10 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +11 -30
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.js +1 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/priority-op.d.ts +8 -0
- package/out/zero-cache/src/server/priority-op.d.ts.map +1 -0
- package/out/zero-cache/src/server/priority-op.js +29 -0
- package/out/zero-cache/src/server/priority-op.js.map +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +10 -10
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.js +1 -1
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +4 -7
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +68 -13
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +7 -2
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +7 -4
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +125 -180
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -10
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +26 -12
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +36 -90
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +51 -14
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +31 -36
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +25 -17
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js +2 -4
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +158 -53
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js +55 -10
- package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +210 -72
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +4 -2
- package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js +20 -4
- package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +6 -4
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +71 -25
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -0
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +6 -5
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +17 -6
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +2 -0
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +14 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
- package/out/zero-cache/src/services/heapz.js +1 -0
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +3 -1
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config.yml +1 -0
- package/out/zero-cache/src/services/mutagen/error.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/error.js +4 -1
- package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +4 -4
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +10 -24
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +8 -6
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +130 -19
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +24 -31
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +4 -4
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +38 -36
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/{change-source → replicator/schema}/column-metadata.d.ts +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -0
- package/out/zero-cache/src/services/{change-source → replicator/schema}/column-metadata.js +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -0
- package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +3 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +1 -1
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/statz.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +1 -0
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +5 -6
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +5 -23
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +65 -44
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +23 -6
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +14 -22
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +46 -67
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +22 -11
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +3 -11
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +6 -4
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +216 -243
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/lexi-version.d.ts.map +1 -1
- package/out/zero-cache/src/types/lexi-version.js +4 -1
- package/out/zero-cache/src/types/lexi-version.js.map +1 -1
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +8 -2
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/shards.js +1 -1
- package/out/zero-cache/src/types/shards.js.map +1 -1
- package/out/zero-cache/src/types/sql.d.ts +5 -0
- package/out/zero-cache/src/types/sql.d.ts.map +1 -1
- package/out/zero-cache/src/types/sql.js +5 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/subscription.js +1 -1
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +2 -3
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +2 -5
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +15 -10
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +17 -10
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +8 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +33 -0
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +6 -3
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.js +1 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/error.js +1 -1
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +15 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +11 -1
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.d.ts +4 -0
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +7 -0
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +5 -5
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +53 -8
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +1 -0
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.d.ts +4 -0
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js +3 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +16 -0
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +25 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +2 -0
- package/out/zero-protocol/src/up.d.ts.map +1 -1
- package/out/zero-react/src/mod.d.ts +3 -1
- package/out/zero-react/src/mod.d.ts.map +1 -1
- package/out/zero-react/src/paging-reducer.d.ts +61 -0
- package/out/zero-react/src/paging-reducer.d.ts.map +1 -0
- package/out/zero-react/src/paging-reducer.js +77 -0
- package/out/zero-react/src/paging-reducer.js.map +1 -0
- package/out/zero-react/src/use-query.d.ts +11 -1
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +13 -11
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/use-rows.d.ts +39 -0
- package/out/zero-react/src/use-rows.d.ts.map +1 -0
- package/out/zero-react/src/use-rows.js +130 -0
- package/out/zero-react/src/use-rows.js.map +1 -0
- package/out/zero-react/src/use-zero-virtualizer.d.ts +122 -0
- package/out/zero-react/src/use-zero-virtualizer.d.ts.map +1 -0
- package/out/zero-react/src/use-zero-virtualizer.js +342 -0
- package/out/zero-react/src/use-zero-virtualizer.js.map +1 -0
- package/out/zero-react/src/zero-provider.js +1 -1
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-server/src/adapters/drizzle.d.ts +18 -18
- package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js +8 -22
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/pg.d.ts +19 -13
- package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.d.ts +19 -13
- package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.d.ts +66 -0
- package/out/zero-server/src/adapters/prisma.d.ts.map +1 -0
- package/out/zero-server/src/adapters/prisma.js +63 -0
- package/out/zero-server/src/adapters/prisma.js.map +1 -0
- package/out/zero-server/src/custom.js +1 -15
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +9 -8
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +2 -1
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +39 -4
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +4 -1
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +18 -0
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/mod.d.ts +1 -1
- package/out/zero-solid/src/mod.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +1 -0
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.d.ts +10 -1
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero-solid/src/use-query.js +22 -5
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero.js +1 -1
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +4 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +4 -1
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +8 -2
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +12 -3
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +25 -2
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +24 -6
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +12 -3
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/mutate/mutator.js +4 -4
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.js +3 -5
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/query-registry.js +4 -4
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +1 -2
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +8 -4
- package/out/zero-cache/src/services/change-source/column-metadata.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/column-metadata.js.map +0 -1
- package/out/zero-cache/src/types/schema-versions.d.ts +0 -12
- package/out/zero-cache/src/types/schema-versions.d.ts.map +0 -1
- package/out/zero-cache/src/types/schema-versions.js +0 -28
- package/out/zero-cache/src/types/schema-versions.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-mutations.js","sources":["../../../../zero-server/src/process-mutations.ts"],"sourcesContent":["import type {LogContext, LogLevel} from '@rocicorp/logger';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {getErrorDetails, getErrorMessage} from '../../shared/src/error.ts';\nimport type {ReadonlyJSONValue} from '../../shared/src/json.ts';\nimport {promiseVoid} from '../../shared/src/resolved-promises.ts';\nimport type {MaybePromise} from '../../shared/src/types.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {MutationAlreadyProcessedError} from '../../zero-cache/src/services/mutagen/error.ts';\nimport type {ApplicationError} from '../../zero-protocol/src/application-error.ts';\nimport {\n isApplicationError,\n wrapWithApplicationError,\n} from '../../zero-protocol/src/application-error.ts';\nimport {ErrorKind} from '../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../zero-protocol/src/error-reason.ts';\nimport type {PushFailedBody} from '../../zero-protocol/src/error.ts';\nimport {\n pushBodySchema,\n pushParamsSchema,\n type CustomMutation,\n type Mutation,\n type MutationID,\n type MutationResponse,\n type PushBody,\n type PushResponse,\n} from '../../zero-protocol/src/push.ts';\nimport type {AnyMutatorRegistry} from '../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator} from '../../zql/src/mutate/mutator.ts';\nimport type {CustomMutatorDefs, CustomMutatorImpl} from './custom.ts';\nimport {createLogContext} from './logging.ts';\n\nexport interface TransactionProviderHooks {\n updateClientMutationID: () => Promise<{lastMutationID: number | bigint}>;\n writeMutationResult: (result: MutationResponse) => Promise<void>;\n}\n\nexport interface TransactionProviderInput {\n upstreamSchema: string;\n clientGroupID: string;\n clientID: string;\n mutationID: number;\n}\n\n/**\n * Defines the abstract interface for a database that PushProcessor can execute\n * transactions against.\n */\nexport interface Database<T> {\n transaction: <R>(\n callback: (\n tx: T,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ) => Promise<R>;\n}\n\nexport type ExtractTransactionType<D> = D extends Database<infer T> ? T : never;\nexport type Params = v.Infer<typeof pushParamsSchema>;\n\nexport type TransactFn<D extends Database<ExtractTransactionType<D>>> = (\n cb: TransactFnCallback<D>,\n) => Promise<MutationResponse>;\n\nexport type TransactFnCallback<D extends Database<ExtractTransactionType<D>>> =\n (\n tx: ExtractTransactionType<D>,\n mutatorName: string,\n mutatorArgs: ReadonlyJSONValue | undefined,\n ) => Promise<void>;\n\nexport type Parsed<D extends Database<ExtractTransactionType<D>>> = {\n transact: TransactFn<D>;\n mutations: CustomMutation[];\n};\n\ntype MutationPhase = 'preTransaction' | 'transactionPending' | 'postCommit';\n\nconst applicationErrorWrapper = async <T>(fn: () => Promise<T>): Promise<T> => {\n try {\n return await fn();\n } catch (error) {\n if (\n error instanceof DatabaseTransactionError ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError ||\n isApplicationError(error)\n ) {\n throw error;\n }\n\n throw wrapWithApplicationError(error);\n }\n};\n\n/**\n * @deprecated Use {@linkcode handleMutateRequest} instead.\n */\nexport const handleMutationRequest = handleMutateRequest;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryString: URLSearchParams | Record<string, string>,\n body: ReadonlyJSONValue,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n request: Request,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport async function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryStringOrRequest: Request | URLSearchParams | Record<string, string>,\n bodyOrLogLevel?: ReadonlyJSONValue | LogLevel,\n logLevel?: LogLevel,\n): Promise<PushResponse> {\n // Parse overload arguments\n const isRequestOverload = queryStringOrRequest instanceof Request;\n\n let request: Request | undefined;\n let queryString: URLSearchParams | Record<string, string>;\n let jsonBody: unknown;\n\n let lc: LogContext;\n\n if (isRequestOverload) {\n request = queryStringOrRequest;\n const level = (bodyOrLogLevel as LogLevel | undefined) ?? 'info';\n\n // Create log context early, before extracting JSON from Request\n lc = createLogContext(level).withContext('PushProcessor');\n\n const url = new URL(request.url);\n queryString = url.searchParams;\n\n try {\n jsonBody = await request.json();\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs: [],\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n } else {\n queryString = queryStringOrRequest;\n jsonBody = bodyOrLogLevel;\n const level = logLevel ?? 'info';\n lc = createLogContext(level).withContext('PushProcessor');\n }\n\n let mutationIDs: MutationID[] = [];\n\n let pushBody: PushBody;\n try {\n pushBody = v.parse(jsonBody, pushBodySchema);\n mutationIDs = pushBody.mutations.map(m => ({\n id: m.id,\n clientID: m.clientID,\n }));\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n let queryParams: Params;\n try {\n const queryStringObj =\n queryString instanceof URLSearchParams\n ? Object.fromEntries(queryString)\n : queryString;\n queryParams = v.parse(queryStringObj, pushParamsSchema, 'passthrough');\n } catch (error) {\n lc.error?.('Failed to parse push query parameters', error);\n const message = `Failed to parse push query parameters: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n if (pushBody.pushVersion !== 1) {\n const response = {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.UnsupportedPushVersion,\n mutationIDs,\n message: `Unsupported push version: ${pushBody.pushVersion}`,\n } as const satisfies PushFailedBody;\n return response;\n }\n\n const responses: MutationResponse[] = [];\n let processedCount = 0;\n\n try {\n const transactor = new Transactor(dbProvider, pushBody, queryParams, lc);\n\n // Each mutation goes through three phases:\n // 1. Pre-transaction: user logic that runs before `transact` is called. If\n // this throws we still advance LMID and persist the failure result.\n // 2. Transaction: the callback passed to `transact`, which can be retried\n // if it fails with an ApplicationError.\n // 3. Post-commit: any logic that runs after `transact` resolves. Failures\n // here are logged but the mutation remains committed.\n for (const m of pushBody.mutations) {\n assert(m.type === 'custom', 'Expected custom mutation');\n lc.debug?.(\n `Processing mutation '${m.name}' (id=${m.id}, clientID=${m.clientID})`,\n m.args,\n );\n\n let mutationPhase: MutationPhase = 'preTransaction';\n\n const transactProxy: TransactFn<D> = async innerCb => {\n mutationPhase = 'transactionPending';\n const result = await transactor.transact(m, (tx, name, args) =>\n applicationErrorWrapper(() => innerCb(tx, name, args)),\n );\n mutationPhase = 'postCommit';\n return result;\n };\n\n try {\n const res = await applicationErrorWrapper(() => cb(transactProxy, m));\n responses.push(res);\n lc.debug?.(`Mutation '${m.name}' (id=${m.id}) completed successfully`);\n\n processedCount++;\n } catch (error) {\n if (!isApplicationError(error)) {\n throw error;\n }\n\n if (mutationPhase === 'preTransaction') {\n // Pre-transaction\n await transactor.persistPreTransactionFailure(m, error);\n } else if (mutationPhase === 'postCommit') {\n // Post-commit\n lc.error?.(\n `Post-commit mutation handler failed for mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n }\n\n lc.warn?.(\n `Application error processing mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n responses.push(makeAppErrorResponse(m, error));\n\n processedCount++;\n }\n }\n\n return {\n mutations: responses,\n };\n } catch (error) {\n lc.error?.('Failed to process push request', error);\n // only include mutationIDs for mutations that were not processed\n const unprocessedMutationIDs = mutationIDs.slice(processedCount);\n\n const message = getErrorMessage(error);\n const details = getErrorDetails(error);\n\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason:\n error instanceof OutOfOrderMutation\n ? ErrorReason.OutOfOrderMutation\n : error instanceof DatabaseTransactionError\n ? ErrorReason.Database\n : ErrorReason.Internal,\n message,\n mutationIDs: unprocessedMutationIDs,\n ...(details ? {details} : {}),\n };\n }\n}\n\nclass Transactor<D extends Database<ExtractTransactionType<D>>> {\n readonly #dbProvider: D;\n readonly #req: PushBody;\n readonly #params: Params;\n readonly #lc: LogContext;\n\n constructor(dbProvider: D, req: PushBody, params: Params, lc: LogContext) {\n this.#dbProvider = dbProvider;\n this.#req = req;\n this.#params = params;\n this.#lc = lc;\n }\n\n transact = async (\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n ): Promise<MutationResponse> => {\n let appError: ApplicationError | undefined = undefined;\n for (;;) {\n try {\n const ret = await this.#transactImpl(mutation, cb, appError);\n if (appError !== undefined) {\n this.#lc.warn?.(\n `Mutation ${mutation.id} for client ${mutation.clientID} was retried after an error`,\n appError,\n );\n return makeAppErrorResponse(mutation, appError);\n }\n\n return ret;\n } catch (error) {\n if (error instanceof OutOfOrderMutation) {\n this.#lc.error?.(error);\n throw error;\n }\n\n if (error instanceof MutationAlreadyProcessedError) {\n this.#lc.warn?.(error);\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {\n error: 'alreadyProcessed',\n details: error.message,\n },\n };\n }\n\n if (isApplicationError(error)) {\n appError = error;\n this.#lc.warn?.(\n `Application error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n appError,\n );\n continue;\n }\n\n this.#lc.error?.(\n `Unexpected error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n error,\n );\n\n throw error;\n }\n }\n };\n\n async persistPreTransactionFailure(\n mutation: CustomMutation,\n appError: ApplicationError<ReadonlyJSONValue | undefined>,\n ): Promise<MutationResponse> {\n // User-land code threw before calling `transact`. We still need to bump the\n // LMID for this mutation and persist the error so that the client knows it failed.\n const ret = await this.#transactImpl(\n mutation,\n // noop callback since there's no transaction to execute\n () => promiseVoid,\n appError,\n );\n return ret;\n }\n\n async #transactImpl(\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n appError: ApplicationError | undefined,\n ): Promise<MutationResponse> {\n let transactionPhase: DatabaseTransactionPhase = 'open';\n\n try {\n const ret = await this.#dbProvider.transaction(\n async (dbTx, transactionHooks) => {\n // update the transaction phase to 'execute' after the transaction is opened\n transactionPhase = 'execute';\n\n await this.#checkAndIncrementLastMutationID(\n transactionHooks,\n mutation.clientID,\n mutation.id,\n );\n\n if (appError === undefined) {\n this.#lc.debug?.(\n `Executing mutator '${mutation.name}' (id=${mutation.id})`,\n );\n try {\n await cb(dbTx, mutation.name, mutation.args[0]);\n } catch (appError) {\n throw wrapWithApplicationError(appError);\n }\n } else {\n const mutationResult = makeAppErrorResponse(mutation, appError);\n await transactionHooks.writeMutationResult(mutationResult);\n }\n\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {},\n };\n },\n this.#getTransactionInput(mutation),\n );\n\n return ret;\n } catch (error) {\n if (\n isApplicationError(error) ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError\n ) {\n throw error;\n }\n\n throw new DatabaseTransactionError(transactionPhase, {cause: error});\n }\n }\n\n #getTransactionInput(mutation: CustomMutation): TransactionProviderInput {\n return {\n upstreamSchema: this.#params.schema,\n clientGroupID: this.#req.clientGroupID,\n clientID: mutation.clientID,\n mutationID: mutation.id,\n };\n }\n\n async #checkAndIncrementLastMutationID(\n transactionHooks: TransactionProviderHooks,\n clientID: string,\n receivedMutationID: number,\n ) {\n const {lastMutationID} = await transactionHooks.updateClientMutationID();\n\n if (receivedMutationID < lastMutationID) {\n throw new MutationAlreadyProcessedError(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n } else if (receivedMutationID > lastMutationID) {\n throw new OutOfOrderMutation(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n }\n }\n}\n\nexport class OutOfOrderMutation extends Error {\n constructor(\n clientID: string,\n receivedMutationID: number,\n lastMutationID: number | bigint,\n ) {\n super(\n `Client ${clientID} sent mutation ID ${receivedMutationID} but expected ${lastMutationID}`,\n );\n }\n}\n\nfunction makeAppErrorResponse(\n m: Mutation,\n error: ApplicationError<ReadonlyJSONValue | undefined>,\n): MutationResponse {\n return {\n id: {\n clientID: m.clientID,\n id: m.id,\n },\n result: {\n error: 'app',\n message: error.message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n}\n\n/** @deprecated Use getMutator instead */\nexport function getMutation(\n // oxlint-disable-next-line no-explicit-any\n mutators: AnyMutatorRegistry | CustomMutatorDefs<any>,\n name: string,\n // oxlint-disable-next-line no-explicit-any\n): CustomMutatorImpl<any> {\n const path = name.split(/\\.|\\|/);\n const mutator = getObjectAtPath(mutators, path);\n assert(typeof mutator === 'function', `could not find mutator ${name}`);\n\n if (isMutator(mutator)) {\n // mutator needs to be called with {tx, args, ctx}\n // CustomMutatorImpl is called with (tx, args, ctx)\n return (tx, args, ctx) => mutator.fn({args, ctx, tx});\n }\n\n // oxlint-disable-next-line no-explicit-any\n return mutator as CustomMutatorImpl<any>;\n}\n\nfunction getObjectAtPath(\n obj: Record<string, unknown>,\n path: string[],\n): unknown {\n let current: unknown = obj;\n for (const part of path) {\n if (typeof current !== 'object' || current === null || !(part in current)) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\ntype DatabaseTransactionPhase = 'open' | 'execute';\nclass DatabaseTransactionError extends Error {\n constructor(phase: DatabaseTransactionPhase, options?: ErrorOptions) {\n super(\n phase === 'open'\n ? `Failed to open database transaction: ${getErrorMessage(options?.cause)}`\n : `Database transaction failed after opening: ${getErrorMessage(options?.cause)}`,\n options,\n );\n this.name = 'DatabaseTransactionError';\n }\n}\n"],"names":["ErrorKind.PushFailed","ErrorOrigin.Server","ErrorReason.Parse","v.parse","ErrorReason.UnsupportedPushVersion","ErrorReason.OutOfOrderMutation","ErrorReason.Database","ErrorReason.Internal","appError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"process-mutations.js","sources":["../../../../zero-server/src/process-mutations.ts"],"sourcesContent":["import type {LogContext, LogLevel} from '@rocicorp/logger';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {getErrorDetails, getErrorMessage} from '../../shared/src/error.ts';\nimport type {ReadonlyJSONValue} from '../../shared/src/json.ts';\nimport {promiseVoid} from '../../shared/src/resolved-promises.ts';\nimport type {MaybePromise} from '../../shared/src/types.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {MutationAlreadyProcessedError} from '../../zero-cache/src/services/mutagen/error.ts';\nimport type {ApplicationError} from '../../zero-protocol/src/application-error.ts';\nimport {\n isApplicationError,\n wrapWithApplicationError,\n} from '../../zero-protocol/src/application-error.ts';\nimport {ErrorKind} from '../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../zero-protocol/src/error-reason.ts';\nimport type {PushFailedBody} from '../../zero-protocol/src/error.ts';\nimport {\n CLEANUP_RESULTS_MUTATION_NAME,\n cleanupResultsArgSchema,\n pushBodySchema,\n pushParamsSchema,\n type CleanupResultsArg,\n type CustomMutation,\n type Mutation,\n type MutationID,\n type MutationResponse,\n type PushBody,\n type PushResponse,\n} from '../../zero-protocol/src/push.ts';\nimport type {AnyMutatorRegistry} from '../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator} from '../../zql/src/mutate/mutator.ts';\nimport type {CustomMutatorDefs, CustomMutatorImpl} from './custom.ts';\nimport {createLogContext} from './logging.ts';\n\nexport interface TransactionProviderHooks {\n updateClientMutationID: () => Promise<{lastMutationID: number | bigint}>;\n writeMutationResult: (result: MutationResponse) => Promise<void>;\n deleteMutationResults: (args: CleanupResultsArg) => Promise<void>;\n}\n\nexport interface TransactionProviderInput {\n upstreamSchema: string;\n clientGroupID: string;\n clientID: string;\n mutationID: number;\n}\n\n/**\n * Defines the abstract interface for a database that PushProcessor can execute\n * transactions against.\n */\nexport interface Database<T> {\n transaction: <R>(\n callback: (\n tx: T,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ) => Promise<R>;\n}\n\nexport type ExtractTransactionType<D> = D extends Database<infer T> ? T : never;\nexport type Params = v.Infer<typeof pushParamsSchema>;\n\nexport type TransactFn<D extends Database<ExtractTransactionType<D>>> = (\n cb: TransactFnCallback<D>,\n) => Promise<MutationResponse>;\n\nexport type TransactFnCallback<D extends Database<ExtractTransactionType<D>>> =\n (\n tx: ExtractTransactionType<D>,\n mutatorName: string,\n mutatorArgs: ReadonlyJSONValue | undefined,\n ) => Promise<void>;\n\nexport type Parsed<D extends Database<ExtractTransactionType<D>>> = {\n transact: TransactFn<D>;\n mutations: CustomMutation[];\n};\n\ntype MutationPhase = 'preTransaction' | 'transactionPending' | 'postCommit';\n\nconst applicationErrorWrapper = async <T>(fn: () => Promise<T>): Promise<T> => {\n try {\n return await fn();\n } catch (error) {\n if (\n error instanceof DatabaseTransactionError ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError ||\n isApplicationError(error)\n ) {\n throw error;\n }\n\n throw wrapWithApplicationError(error);\n }\n};\n\n/**\n * @deprecated Use {@linkcode handleMutateRequest} instead.\n */\nexport const handleMutationRequest = handleMutateRequest;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryString: URLSearchParams | Record<string, string>,\n body: ReadonlyJSONValue,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n request: Request,\n logLevel?: LogLevel,\n): Promise<PushResponse>;\n\nexport async function handleMutateRequest<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n cb: (\n transact: TransactFn<D>,\n mutation: CustomMutation,\n ) => Promise<MutationResponse>,\n queryStringOrRequest: Request | URLSearchParams | Record<string, string>,\n bodyOrLogLevel?: ReadonlyJSONValue | LogLevel,\n logLevel?: LogLevel,\n): Promise<PushResponse> {\n // Parse overload arguments\n const isRequestOverload = queryStringOrRequest instanceof Request;\n\n let request: Request | undefined;\n let queryString: URLSearchParams | Record<string, string>;\n let jsonBody: unknown;\n\n let lc: LogContext;\n\n if (isRequestOverload) {\n request = queryStringOrRequest;\n const level = (bodyOrLogLevel as LogLevel | undefined) ?? 'info';\n\n // Create log context early, before extracting JSON from Request\n lc = createLogContext(level).withContext('PushProcessor');\n\n const url = new URL(request.url);\n queryString = url.searchParams;\n\n try {\n jsonBody = await request.json();\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs: [],\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n } else {\n queryString = queryStringOrRequest;\n jsonBody = bodyOrLogLevel;\n const level = logLevel ?? 'info';\n lc = createLogContext(level).withContext('PushProcessor');\n }\n\n let mutationIDs: MutationID[] = [];\n\n let pushBody: PushBody;\n try {\n pushBody = v.parse(jsonBody, pushBodySchema);\n mutationIDs = pushBody.mutations.map(m => ({\n id: m.id,\n clientID: m.clientID,\n }));\n } catch (error) {\n lc.error?.('Failed to parse push body', error);\n const message = `Failed to parse push body: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n let queryParams: Params;\n try {\n const queryStringObj =\n queryString instanceof URLSearchParams\n ? Object.fromEntries(queryString)\n : queryString;\n queryParams = v.parse(queryStringObj, pushParamsSchema, 'passthrough');\n } catch (error) {\n lc.error?.('Failed to parse push query parameters', error);\n const message = `Failed to parse push query parameters: ${getErrorMessage(error)}`;\n const details = getErrorDetails(error);\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Parse,\n message,\n mutationIDs,\n ...(details ? {details} : {}),\n } as const satisfies PushFailedBody;\n }\n\n if (pushBody.pushVersion !== 1) {\n const response = {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.UnsupportedPushVersion,\n mutationIDs,\n message: `Unsupported push version: ${pushBody.pushVersion}`,\n } as const satisfies PushFailedBody;\n return response;\n }\n\n const responses: MutationResponse[] = [];\n let processedCount = 0;\n\n try {\n const transactor = new Transactor(dbProvider, pushBody, queryParams, lc);\n\n // Each mutation goes through three phases:\n // 1. Pre-transaction: user logic that runs before `transact` is called. If\n // this throws we still advance LMID and persist the failure result.\n // 2. Transaction: the callback passed to `transact`, which can be retried\n // if it fails with an ApplicationError.\n // 3. Post-commit: any logic that runs after `transact` resolves. Failures\n // here are logged but the mutation remains committed.\n for (const m of pushBody.mutations) {\n // Handle internal mutations (like cleanup) directly without user dispatch\n if (m.type === 'custom' && m.name === CLEANUP_RESULTS_MUTATION_NAME) {\n lc.debug?.(\n `Processing internal mutation '${m.name}' (clientID=${m.clientID})`,\n );\n try {\n await processCleanupResultsMutation(dbProvider, m, queryParams, lc);\n // No response added - this is fire-and-forget\n processedCount++;\n } catch (error) {\n lc.warn?.(\n `Failed to process cleanup mutation for client ${m.clientID}`,\n error,\n );\n // Don't fail the whole push for cleanup errors\n processedCount++;\n }\n continue;\n }\n\n assert(m.type === 'custom', 'Expected custom mutation');\n lc.debug?.(\n `Processing mutation '${m.name}' (id=${m.id}, clientID=${m.clientID})`,\n );\n\n let mutationPhase: MutationPhase = 'preTransaction';\n\n const transactProxy: TransactFn<D> = async innerCb => {\n mutationPhase = 'transactionPending';\n const result = await transactor.transact(m, (tx, name, args) =>\n applicationErrorWrapper(() => innerCb(tx, name, args)),\n );\n mutationPhase = 'postCommit';\n return result;\n };\n\n try {\n const res = await applicationErrorWrapper(() => cb(transactProxy, m));\n responses.push(res);\n lc.debug?.(`Mutation '${m.name}' (id=${m.id}) completed successfully`);\n\n processedCount++;\n } catch (error) {\n if (!isApplicationError(error)) {\n throw error;\n }\n\n if (mutationPhase === 'preTransaction') {\n // Pre-transaction\n await transactor.persistPreTransactionFailure(m, error);\n } else if (mutationPhase === 'postCommit') {\n // Post-commit\n lc.error?.(\n `Post-commit mutation handler failed for mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n }\n\n lc.warn?.(\n `Application error processing mutation ${m.id} for client ${m.clientID}`,\n error,\n );\n responses.push(makeAppErrorResponse(m, error));\n\n processedCount++;\n }\n }\n\n return {\n mutations: responses,\n };\n } catch (error) {\n lc.error?.('Failed to process push request', error);\n // only include mutationIDs for mutations that were not processed\n const unprocessedMutationIDs = mutationIDs.slice(processedCount);\n\n const message = getErrorMessage(error);\n const details = getErrorDetails(error);\n\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason:\n error instanceof OutOfOrderMutation\n ? ErrorReason.OutOfOrderMutation\n : error instanceof DatabaseTransactionError\n ? ErrorReason.Database\n : ErrorReason.Internal,\n message,\n mutationIDs: unprocessedMutationIDs,\n ...(details ? {details} : {}),\n };\n }\n}\n\nclass Transactor<D extends Database<ExtractTransactionType<D>>> {\n readonly #dbProvider: D;\n readonly #req: PushBody;\n readonly #params: Params;\n readonly #lc: LogContext;\n\n constructor(dbProvider: D, req: PushBody, params: Params, lc: LogContext) {\n this.#dbProvider = dbProvider;\n this.#req = req;\n this.#params = params;\n this.#lc = lc;\n }\n\n transact = async (\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n ): Promise<MutationResponse> => {\n let appError: ApplicationError | undefined = undefined;\n for (;;) {\n try {\n const ret = await this.#transactImpl(mutation, cb, appError);\n if (appError !== undefined) {\n this.#lc.warn?.(\n `Mutation ${mutation.id} for client ${mutation.clientID} was retried after an error`,\n appError,\n );\n return makeAppErrorResponse(mutation, appError);\n }\n\n return ret;\n } catch (error) {\n if (error instanceof OutOfOrderMutation) {\n this.#lc.error?.(error);\n throw error;\n }\n\n if (error instanceof MutationAlreadyProcessedError) {\n this.#lc.warn?.(error);\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {\n error: 'alreadyProcessed',\n details: error.message,\n },\n };\n }\n\n if (isApplicationError(error)) {\n appError = error;\n this.#lc.warn?.(\n `Application error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n appError,\n );\n continue;\n }\n\n this.#lc.error?.(\n `Unexpected error processing mutation ${mutation.id} for client ${mutation.clientID}`,\n error,\n );\n\n throw error;\n }\n }\n };\n\n async persistPreTransactionFailure(\n mutation: CustomMutation,\n appError: ApplicationError<ReadonlyJSONValue | undefined>,\n ): Promise<MutationResponse> {\n // User-land code threw before calling `transact`. We still need to bump the\n // LMID for this mutation and persist the error so that the client knows it failed.\n const ret = await this.#transactImpl(\n mutation,\n // noop callback since there's no transaction to execute\n () => promiseVoid,\n appError,\n );\n return ret;\n }\n\n async #transactImpl(\n mutation: CustomMutation,\n cb: TransactFnCallback<D>,\n appError: ApplicationError | undefined,\n ): Promise<MutationResponse> {\n let transactionPhase: DatabaseTransactionPhase = 'open';\n\n try {\n const ret = await this.#dbProvider.transaction(\n async (dbTx, transactionHooks) => {\n // update the transaction phase to 'execute' after the transaction is opened\n transactionPhase = 'execute';\n\n await this.#checkAndIncrementLastMutationID(\n transactionHooks,\n mutation.clientID,\n mutation.id,\n );\n\n if (appError === undefined) {\n this.#lc.debug?.(\n `Executing mutator '${mutation.name}' (id=${mutation.id})`,\n );\n try {\n await cb(dbTx, mutation.name, mutation.args[0]);\n } catch (appError) {\n throw wrapWithApplicationError(appError);\n }\n } else {\n const mutationResult = makeAppErrorResponse(mutation, appError);\n await transactionHooks.writeMutationResult(mutationResult);\n }\n\n return {\n id: {\n clientID: mutation.clientID,\n id: mutation.id,\n },\n result: {},\n };\n },\n this.#getTransactionInput(mutation),\n );\n\n return ret;\n } catch (error) {\n if (\n isApplicationError(error) ||\n error instanceof OutOfOrderMutation ||\n error instanceof MutationAlreadyProcessedError\n ) {\n throw error;\n }\n\n throw new DatabaseTransactionError(transactionPhase, {cause: error});\n }\n }\n\n #getTransactionInput(mutation: CustomMutation): TransactionProviderInput {\n return {\n upstreamSchema: this.#params.schema,\n clientGroupID: this.#req.clientGroupID,\n clientID: mutation.clientID,\n mutationID: mutation.id,\n };\n }\n\n async #checkAndIncrementLastMutationID(\n transactionHooks: TransactionProviderHooks,\n clientID: string,\n receivedMutationID: number,\n ) {\n const {lastMutationID} = await transactionHooks.updateClientMutationID();\n\n if (receivedMutationID < lastMutationID) {\n throw new MutationAlreadyProcessedError(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n } else if (receivedMutationID > lastMutationID) {\n throw new OutOfOrderMutation(\n clientID,\n receivedMutationID,\n lastMutationID,\n );\n }\n }\n}\n\nexport class OutOfOrderMutation extends Error {\n constructor(\n clientID: string,\n receivedMutationID: number,\n lastMutationID: number | bigint,\n ) {\n super(\n `Client ${clientID} sent mutation ID ${receivedMutationID} but expected ${lastMutationID}`,\n );\n }\n}\n\nfunction makeAppErrorResponse(\n m: Mutation,\n error: ApplicationError<ReadonlyJSONValue | undefined>,\n): MutationResponse {\n return {\n id: {\n clientID: m.clientID,\n id: m.id,\n },\n result: {\n error: 'app',\n message: error.message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n}\n\n/** @deprecated Use getMutator instead */\nexport function getMutation(\n // oxlint-disable-next-line no-explicit-any\n mutators: AnyMutatorRegistry | CustomMutatorDefs<any>,\n name: string,\n // oxlint-disable-next-line no-explicit-any\n): CustomMutatorImpl<any> {\n const path = name.split(/\\.|\\|/);\n const mutator = getObjectAtPath(mutators, path);\n assert(typeof mutator === 'function', `could not find mutator ${name}`);\n\n if (isMutator(mutator)) {\n // mutator needs to be called with {tx, args, ctx}\n // CustomMutatorImpl is called with (tx, args, ctx)\n return (tx, args, ctx) => mutator.fn({args, ctx, tx});\n }\n\n // oxlint-disable-next-line no-explicit-any\n return mutator as CustomMutatorImpl<any>;\n}\n\nfunction getObjectAtPath(\n obj: Record<string, unknown>,\n path: string[],\n): unknown {\n let current: unknown = obj;\n for (const part of path) {\n if (typeof current !== 'object' || current === null || !(part in current)) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\n/**\n * Processes internal cleanup mutation that deletes acknowledged mutation results\n * from the upstream database. This runs without LMID tracking since it's an\n * internal operation.\n */\nasync function processCleanupResultsMutation<\n D extends Database<ExtractTransactionType<D>>,\n>(\n dbProvider: D,\n mutation: CustomMutation,\n queryParams: Params,\n lc: LogContext,\n): Promise<void> {\n const parseResult = v.test(mutation.args[0], cleanupResultsArgSchema);\n if (!parseResult.ok) {\n lc.warn?.('Cleanup mutation has invalid args', parseResult.error);\n return;\n }\n const args: CleanupResultsArg = parseResult.value;\n\n // Determine clientID for transaction input based on cleanup type\n // Note: legacy format without type field is treated as single\n const clientID =\n 'type' in args && args.type === 'bulk' ? args.clientIDs[0] : args.clientID;\n\n // Run in a transaction, using the hook for DB-specific operation.\n // Note: only upstreamSchema is used by deleteMutationResults; the other\n // fields are required by the interface but ignored for this operation.\n await dbProvider.transaction(\n async (_, hooks) => {\n await hooks.deleteMutationResults(args);\n },\n {\n upstreamSchema: queryParams.schema,\n clientGroupID: args.clientGroupID,\n clientID,\n mutationID: 0,\n },\n );\n}\n\ntype DatabaseTransactionPhase = 'open' | 'execute';\nclass DatabaseTransactionError extends Error {\n constructor(phase: DatabaseTransactionPhase, options?: ErrorOptions) {\n super(\n phase === 'open'\n ? `Failed to open database transaction: ${getErrorMessage(options?.cause)}`\n : `Database transaction failed after opening: ${getErrorMessage(options?.cause)}`,\n options,\n );\n this.name = 'DatabaseTransactionError';\n }\n}\n"],"names":["ErrorKind.PushFailed","ErrorOrigin.Server","ErrorReason.Parse","v.parse","ErrorReason.UnsupportedPushVersion","ErrorReason.OutOfOrderMutation","ErrorReason.Database","ErrorReason.Internal","appError","v.test"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-processor.js","sources":["../../../../zero-server/src/push-processor.ts"],"sourcesContent":["import {type LogLevel} from '@rocicorp/logger';\nimport {assert} from '../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../shared/src/json.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {getValueAtPath} from '../../shared/src/object-traversal.ts';\nimport {\n type CustomMutation,\n type MutationResponse,\n type PushResponse,\n} from '../../zero-protocol/src/push.ts';\nimport {\n type Database,\n type ExtractTransactionType,\n handleMutateRequest,\n type TransactFn,\n} from '../../zero-server/src/process-mutations.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {Transaction} from '../../zql/src/mutate/custom.ts';\nimport type {AnyMutatorRegistry} from '../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator} from '../../zql/src/mutate/mutator.ts';\nimport type {CustomMutatorDefs} from './custom.ts';\n\nexport class PushProcessor<\n _S extends Schema,\n D extends Database<ExtractTransactionType<D>>,\n MD extends AnyMutatorRegistry | CustomMutatorDefs<ExtractTransactionType<D>>,\n C = undefined,\n> {\n readonly #dbProvider: D;\n readonly #logLevel: LogLevel;\n readonly #context: C;\n\n constructor(dbProvider: D, context?: C, logLevel: LogLevel = 'info') {\n this.#dbProvider = dbProvider;\n this.#context = context as C;\n this.#logLevel = logLevel;\n }\n\n /**\n * Processes a push request from zero-cache.\n * This function will parse the request, check the protocol version, and process each mutation in the request.\n * - If a mutation is out of order: processing will stop and an error will be returned. The zero client will retry the mutation.\n * - If a mutation has already been processed: it will be skipped and the processing will continue.\n * - If a mutation receives an application error: it will be skipped, the error will be returned to the client, and processing will continue.\n *\n * @param mutators the custom mutators for the application\n * @param queryString the query string from the request sent by zero-cache. This will include zero's postgres schema name and appID.\n * @param body the body of the request sent by zero-cache as a JSON object.\n */\n process(\n mutators: MD,\n queryString: URLSearchParams | Record<string, string>,\n body: ReadonlyJSONValue,\n ): Promise<PushResponse>;\n\n /**\n * This override gets the query string and the body from a Request object.\n *\n * @param mutators the custom mutators for the application\n * @param request A `Request` object.\n */\n process(mutators: MD, request: Request): Promise<PushResponse>;\n process(\n mutators: MD,\n queryOrQueryString: Request | URLSearchParams | Record<string, string>,\n body?: ReadonlyJSONValue,\n ): Promise<PushResponse> {\n if (queryOrQueryString instanceof Request) {\n return handleMutateRequest(\n this.#dbProvider,\n (transact, mutation) =>\n this.#processMutation(mutators, transact, mutation),\n queryOrQueryString,\n this.#logLevel,\n );\n }\n return handleMutateRequest(\n this.#dbProvider,\n (transact, mutation) =>\n this.#processMutation(mutators, transact, mutation),\n queryOrQueryString,\n must(body),\n this.#logLevel,\n );\n }\n\n #processMutation(\n mutators: MD,\n transact: TransactFn<D>,\n _mutation: CustomMutation,\n ): Promise<MutationResponse> {\n return transact((tx, name, args) =>\n this.#dispatchMutation(mutators, tx, name, args),\n );\n }\n\n #dispatchMutation(\n mutators: MD,\n dbTx: ExtractTransactionType<D>,\n key: string,\n args: ReadonlyJSONValue | undefined,\n ): Promise<void> {\n // Legacy mutators used | as a separator, new mutators use .\n const mutator = getValueAtPath(mutators, key, /\\.|\\|/);\n assert(typeof mutator === 'function', `could not find mutator ${key}`);\n if (isMutator(mutator)) {\n return mutator.fn({\n args,\n ctx: this.#context,\n tx: dbTx as Transaction<Schema, unknown>,\n });\n }\n return mutator(dbTx, args);\n }\n}\n"],"names":[],"mappings":";;;;;;;AAsBO,MAAM,cAKX;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,YAAe,SAAa,WAAqB,QAAQ;AACnE,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,YAAY;AAAA,EACnB;AAAA,EA0BA,QACE,UACA,oBACA,MACuB;AACvB,QAAI,8BAA8B,SAAS;AACzC,aAAO;AAAA,QACL,KAAK;AAAA,QACL,CAAC,UAAU,aACT,KAAK,iBAAiB,UAAU,UAAU,QAAQ;AAAA,QACpD;AAAA,QACA,KAAK;AAAA,MAAA;AAAA,IAET;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,CAAC,UAAU,aACT,KAAK,iBAAiB,UAAU,UAAU,QAAQ;AAAA,MACpD;AAAA,MACA,KAAK,
|
|
1
|
+
{"version":3,"file":"push-processor.js","sources":["../../../../zero-server/src/push-processor.ts"],"sourcesContent":["import {type LogLevel} from '@rocicorp/logger';\nimport {assert} from '../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../shared/src/json.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {getValueAtPath} from '../../shared/src/object-traversal.ts';\nimport {\n type CustomMutation,\n type MutationResponse,\n type PushResponse,\n} from '../../zero-protocol/src/push.ts';\nimport {\n type Database,\n type ExtractTransactionType,\n handleMutateRequest,\n type TransactFn,\n} from '../../zero-server/src/process-mutations.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {Transaction} from '../../zql/src/mutate/custom.ts';\nimport type {AnyMutatorRegistry} from '../../zql/src/mutate/mutator-registry.ts';\nimport {isMutator} from '../../zql/src/mutate/mutator.ts';\nimport type {CustomMutatorDefs} from './custom.ts';\n\nexport class PushProcessor<\n _S extends Schema,\n D extends Database<ExtractTransactionType<D>>,\n MD extends AnyMutatorRegistry | CustomMutatorDefs<ExtractTransactionType<D>>,\n C = undefined,\n> {\n readonly #dbProvider: D;\n readonly #logLevel: LogLevel;\n readonly #context: C;\n\n constructor(dbProvider: D, context?: C, logLevel: LogLevel = 'info') {\n this.#dbProvider = dbProvider;\n this.#context = context as C;\n this.#logLevel = logLevel;\n }\n\n /**\n * Processes a push request from zero-cache.\n * This function will parse the request, check the protocol version, and process each mutation in the request.\n * - If a mutation is out of order: processing will stop and an error will be returned. The zero client will retry the mutation.\n * - If a mutation has already been processed: it will be skipped and the processing will continue.\n * - If a mutation receives an application error: it will be skipped, the error will be returned to the client, and processing will continue.\n *\n * @param mutators the custom mutators for the application\n * @param queryString the query string from the request sent by zero-cache. This will include zero's postgres schema name and appID.\n * @param body the body of the request sent by zero-cache as a JSON object.\n */\n process(\n mutators: MD,\n queryString: URLSearchParams | Record<string, string>,\n body: ReadonlyJSONValue,\n ): Promise<PushResponse>;\n\n /**\n * This override gets the query string and the body from a Request object.\n *\n * @param mutators the custom mutators for the application\n * @param request A `Request` object.\n */\n process(mutators: MD, request: Request): Promise<PushResponse>;\n process(\n mutators: MD,\n queryOrQueryString: Request | URLSearchParams | Record<string, string>,\n body?: ReadonlyJSONValue,\n ): Promise<PushResponse> {\n if (queryOrQueryString instanceof Request) {\n return handleMutateRequest(\n this.#dbProvider,\n (transact, mutation) =>\n this.#processMutation(mutators, transact, mutation),\n queryOrQueryString,\n this.#logLevel,\n );\n }\n return handleMutateRequest(\n this.#dbProvider,\n (transact, mutation) =>\n this.#processMutation(mutators, transact, mutation),\n queryOrQueryString,\n must(body, 'body is required when using query params directly'),\n this.#logLevel,\n );\n }\n\n #processMutation(\n mutators: MD,\n transact: TransactFn<D>,\n _mutation: CustomMutation,\n ): Promise<MutationResponse> {\n return transact((tx, name, args) =>\n this.#dispatchMutation(mutators, tx, name, args),\n );\n }\n\n #dispatchMutation(\n mutators: MD,\n dbTx: ExtractTransactionType<D>,\n key: string,\n args: ReadonlyJSONValue | undefined,\n ): Promise<void> {\n // Legacy mutators used | as a separator, new mutators use .\n const mutator = getValueAtPath(mutators, key, /\\.|\\|/);\n assert(typeof mutator === 'function', `could not find mutator ${key}`);\n if (isMutator(mutator)) {\n return mutator.fn({\n args,\n ctx: this.#context,\n tx: dbTx as Transaction<Schema, unknown>,\n });\n }\n return mutator(dbTx, args);\n }\n}\n"],"names":[],"mappings":";;;;;;;AAsBO,MAAM,cAKX;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,YAAe,SAAa,WAAqB,QAAQ;AACnE,SAAK,cAAc;AACnB,SAAK,WAAW;AAChB,SAAK,YAAY;AAAA,EACnB;AAAA,EA0BA,QACE,UACA,oBACA,MACuB;AACvB,QAAI,8BAA8B,SAAS;AACzC,aAAO;AAAA,QACL,KAAK;AAAA,QACL,CAAC,UAAU,aACT,KAAK,iBAAiB,UAAU,UAAU,QAAQ;AAAA,QACpD;AAAA,QACA,KAAK;AAAA,MAAA;AAAA,IAET;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,CAAC,UAAU,aACT,KAAK,iBAAiB,UAAU,UAAU,QAAQ;AAAA,MACpD;AAAA,MACA,KAAK,MAAM,mDAAmD;AAAA,MAC9D,KAAK;AAAA,IAAA;AAAA,EAET;AAAA,EAEA,iBACE,UACA,UACA,WAC2B;AAC3B,WAAO;AAAA,MAAS,CAAC,IAAI,MAAM,SACzB,KAAK,kBAAkB,UAAU,IAAI,MAAM,IAAI;AAAA,IAAA;AAAA,EAEnD;AAAA,EAEA,kBACE,UACA,MACA,KACA,MACe;AAEf,UAAM,UAAU,eAAe,UAAU,KAAK,OAAO;AACrD,WAAO,OAAO,YAAY,YAAY,0BAA0B,GAAG,EAAE;AACrE,QAAI,UAAU,OAAO,GAAG;AACtB,aAAO,QAAQ,GAAG;AAAA,QAChB;AAAA,QACA,KAAK,KAAK;AAAA,QACV,IAAI;AAAA,MAAA,CACL;AAAA,IACH;AACA,WAAO,QAAQ,MAAM,IAAI;AAAA,EAC3B;AACF;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/schema.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AACxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAkBlE,wBAAsB,eAAe,CAAC,CAAC,SAAS,MAAM,EACpD,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,EACrC,MAAM,EAAE,CAAC,GACR,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/schema.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,uCAAuC,CAAC;AACxE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gCAAgC,CAAC;AAkBlE,wBAAsB,eAAe,CAAC,CAAC,SAAS,MAAM,EACpD,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,EACrC,MAAM,EAAE,CAAC,GACR,OAAO,CAAC,YAAY,CAAC,CA2GvB;AAwCD,MAAM,MAAM,0BAA0B,GAClC;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,YAAY,GACzB,0BAA0B,EAAE,CAkD9B"}
|
|
@@ -69,7 +69,10 @@ async function getServerSchema(dbTransaction, schema) {
|
|
|
69
69
|
const isEnum = (row.elemTyptype ?? row.typtype) === Enum;
|
|
70
70
|
let type = row.dataType.toLowerCase();
|
|
71
71
|
if (isArray) {
|
|
72
|
-
type = must(
|
|
72
|
+
type = must(
|
|
73
|
+
row.elemTypname,
|
|
74
|
+
`Array column "${row.column}" in table "${tableName}" is missing element type name`
|
|
75
|
+
);
|
|
73
76
|
} else if (isEnum) {
|
|
74
77
|
type = row.typename;
|
|
75
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sources":["../../../../zero-server/src/schema.ts"],"sourcesContent":["import {assert} from '../../shared/src/asserts.ts';\nimport type {Enum} from '../../shared/src/enum.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {formatPg, sql} from '../../z2s/src/sql.ts';\nimport * as PostgresTypeClass from '../../zero-cache/src/db/postgres-type-class-enum.ts';\nimport {dataTypeToZqlValueType} from '../../zero-cache/src/types/pg-data-type.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {ServerSchema} from '../../zero-types/src/server-schema.ts';\nimport type {DBTransaction} from '../../zql/src/mutate/custom.ts';\n\ntype PostgresTypeClass = Enum<typeof PostgresTypeClass>;\n\ntype ServerSchemaRow = {\n schema: string;\n table: string;\n column: string;\n dataType: string;\n length: string | null;\n precision: string | null;\n scale: string | null;\n typtype: PostgresTypeClass;\n typename: string;\n elemTyptype: PostgresTypeClass | null;\n elemTypname: string | null;\n};\n\nexport async function getServerSchema<S extends Schema>(\n dbTransaction: DBTransaction<unknown>,\n schema: S,\n): Promise<ServerSchema> {\n const schemaTablePairs: [string, string][] = Object.values(schema.tables).map(\n ({name, serverName}) => {\n let schemaTablePair: [string, string] = ['public', serverName ?? name];\n if (serverName) {\n const firstPeriod = serverName.indexOf('.');\n if (firstPeriod > -1) {\n schemaTablePair = [\n serverName.substring(0, firstPeriod),\n serverName.substring(firstPeriod + 1, serverName.length),\n ];\n }\n }\n return schemaTablePair;\n },\n );\n\n if (schemaTablePairs.length === 0) {\n return {}; // No pairs to query for\n }\n\n // Cast all inputs to text and all outputs to text to avoid\n // any conversions customer's DBTransaction impl has on other types.\n const inClause = sql.join(\n schemaTablePairs.map(\n ([schema, table]) => sql`(${schema}::text, ${table}::text)`,\n ),\n ',',\n );\n const query = sql`\n SELECT\n c.table_schema::text AS schema,\n c.table_name::text AS table,\n c.column_name::text AS column,\n c.data_type::text AS \"dataType\",\n c.character_maximum_length AS length,\n c.numeric_precision AS precision,\n c.numeric_scale AS scale,\n t.typtype::text AS typtype,\n t.typname::text AS typename,\n CASE WHEN t.typelem <> 0 THEN et.typtype::text ELSE NULL END AS \"elemTyptype\",\n CASE WHEN t.typelem <> 0 THEN et.typname::text ELSE NULL END AS \"elemTypname\"\n FROM\n information_schema.columns c\n JOIN\n pg_catalog.pg_type t ON c.udt_name = t.typname\n LEFT JOIN\n pg_catalog.pg_type et ON t.typelem = et.oid\n JOIN\n pg_catalog.pg_namespace n ON t.typnamespace = n.oid\n WHERE\n (c.table_schema, c.table_name) IN (${inClause})\n `;\n const {text, values} = formatPg(query);\n const results: Iterable<ServerSchemaRow> = (await dbTransaction.query(\n text,\n values,\n )) as Iterable<ServerSchemaRow>;\n\n const serverSchema: ServerSchema = {};\n\n for (const row of results) {\n const tableName =\n row.schema === 'public' ? row.table : `${row.schema}.${row.table}`;\n let tableSchema = serverSchema[tableName];\n if (!tableSchema) {\n tableSchema = {};\n serverSchema[tableName] = tableSchema;\n }\n const isArray = row.elemTyptype !== null;\n const isEnum = (row.elemTyptype ?? row.typtype) === PostgresTypeClass.Enum;\n let type = row.dataType.toLowerCase();\n if (isArray) {\n type = must(row.elemTypname);\n } else if (isEnum) {\n type = row.typename;\n }\n if (\n (type === 'bpchar' ||\n type === 'character' ||\n type === 'character varying' ||\n type === 'varchar') &&\n row.length\n ) {\n type = `${type}(${row.length})`;\n }\n if (\n (type === 'numeric' || type === 'decimal') &&\n row.precision !== null &&\n row.scale !== null\n ) {\n type = `${type}(${row.precision}, ${row.scale})`;\n }\n tableSchema[row.column] = {\n type,\n isEnum,\n isArray,\n };\n }\n\n const errors = checkSchemasAreCompatible(schema, serverSchema);\n assert(errors.length === 0, () => makeSchemaIncompatibleErrorMessage(errors));\n\n return serverSchema;\n}\n\nfunction makeSchemaIncompatibleErrorMessage(\n errors: SchemaIncompatibilityError[],\n) {\n if (errors.length === 0) {\n return 'No schema incompatibilities found.';\n }\n\n const messages: string[] = [];\n\n for (const error of errors) {\n switch (error.type) {\n case 'missingTable':\n messages.push(\n `Table \"${error.table}\" is defined in your zero schema but does not exist in the database.`,\n );\n break;\n case 'missingColumn':\n messages.push(\n `Column \"${error.column}\" in table \"${error.table}\" is defined in your zero schema but does not exist in the database.`,\n );\n break;\n case 'typeError':\n messages.push(\n `Type mismatch for column \"${error.column}\" in table \"${error.table}\": ${error.requiredType === undefined ? `${error.pgType} is currently unsupported in Zero. Please file a bug at https://bugs.rocicorp.dev/` : `${error.pgType} should be mapped to ${error.requiredType} in Zero not ${error.declaredType}.`}`,\n );\n break;\n }\n }\n\n return [\n 'Schema incompatibility detected between your zero schema definition and the database:',\n '',\n ...messages.map(msg => ` - ${msg}`),\n '',\n 'Please update your schema definition to match the database or migrate your database to match the schema.',\n ].join('\\n');\n}\n\nexport type SchemaIncompatibilityError =\n | {\n type: 'typeError';\n table: string;\n column: string;\n pgType: string;\n declaredType: string;\n requiredType: string | undefined;\n }\n | {\n type: 'missingColumn';\n table: string;\n column: string;\n }\n | {\n type: 'missingTable';\n table: string;\n };\n\nexport function checkSchemasAreCompatible(\n schema: Schema,\n serverSchema: ServerSchema,\n): SchemaIncompatibilityError[] {\n const errors: SchemaIncompatibilityError[] = [];\n // Check that all tables in schema exist in serverSchema\n for (const table of Object.values(schema.tables)) {\n const serverTableName = table.serverName ?? table.name;\n\n if (!serverSchema[serverTableName]) {\n errors.push({\n type: 'missingTable',\n table: serverTableName,\n });\n continue;\n }\n\n // Check that all columns in the table exist in serverSchema\n for (const [columnName, column] of Object.entries(table.columns)) {\n const serverColumnName = column.serverName ?? columnName;\n\n if (!serverSchema[serverTableName][serverColumnName]) {\n errors.push({\n type: 'missingColumn',\n table: serverTableName,\n column: serverColumnName,\n });\n continue;\n }\n\n // Check type compatibility\n const serverColumn = serverSchema[serverTableName][serverColumnName];\n const declaredType = column.type;\n const pgType = serverColumn.type;\n const requiredType = dataTypeToZqlValueType(\n pgType,\n serverColumn.isEnum,\n serverColumn.isArray,\n );\n if (requiredType !== declaredType) {\n errors.push({\n type: 'typeError',\n table: serverTableName,\n column: serverColumnName,\n pgType,\n declaredType,\n requiredType,\n });\n }\n }\n }\n\n return errors;\n}\n"],"names":["schema","PostgresTypeClass.Enum"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema.js","sources":["../../../../zero-server/src/schema.ts"],"sourcesContent":["import {assert} from '../../shared/src/asserts.ts';\nimport type {Enum} from '../../shared/src/enum.ts';\nimport {must} from '../../shared/src/must.ts';\nimport {formatPg, sql} from '../../z2s/src/sql.ts';\nimport * as PostgresTypeClass from '../../zero-cache/src/db/postgres-type-class-enum.ts';\nimport {dataTypeToZqlValueType} from '../../zero-cache/src/types/pg-data-type.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {ServerSchema} from '../../zero-types/src/server-schema.ts';\nimport type {DBTransaction} from '../../zql/src/mutate/custom.ts';\n\ntype PostgresTypeClass = Enum<typeof PostgresTypeClass>;\n\ntype ServerSchemaRow = {\n schema: string;\n table: string;\n column: string;\n dataType: string;\n length: string | null;\n precision: string | null;\n scale: string | null;\n typtype: PostgresTypeClass;\n typename: string;\n elemTyptype: PostgresTypeClass | null;\n elemTypname: string | null;\n};\n\nexport async function getServerSchema<S extends Schema>(\n dbTransaction: DBTransaction<unknown>,\n schema: S,\n): Promise<ServerSchema> {\n const schemaTablePairs: [string, string][] = Object.values(schema.tables).map(\n ({name, serverName}) => {\n let schemaTablePair: [string, string] = ['public', serverName ?? name];\n if (serverName) {\n const firstPeriod = serverName.indexOf('.');\n if (firstPeriod > -1) {\n schemaTablePair = [\n serverName.substring(0, firstPeriod),\n serverName.substring(firstPeriod + 1, serverName.length),\n ];\n }\n }\n return schemaTablePair;\n },\n );\n\n if (schemaTablePairs.length === 0) {\n return {}; // No pairs to query for\n }\n\n // Cast all inputs to text and all outputs to text to avoid\n // any conversions customer's DBTransaction impl has on other types.\n const inClause = sql.join(\n schemaTablePairs.map(\n ([schema, table]) => sql`(${schema}::text, ${table}::text)`,\n ),\n ',',\n );\n const query = sql`\n SELECT\n c.table_schema::text AS schema,\n c.table_name::text AS table,\n c.column_name::text AS column,\n c.data_type::text AS \"dataType\",\n c.character_maximum_length AS length,\n c.numeric_precision AS precision,\n c.numeric_scale AS scale,\n t.typtype::text AS typtype,\n t.typname::text AS typename,\n CASE WHEN t.typelem <> 0 THEN et.typtype::text ELSE NULL END AS \"elemTyptype\",\n CASE WHEN t.typelem <> 0 THEN et.typname::text ELSE NULL END AS \"elemTypname\"\n FROM\n information_schema.columns c\n JOIN\n pg_catalog.pg_type t ON c.udt_name = t.typname\n LEFT JOIN\n pg_catalog.pg_type et ON t.typelem = et.oid\n JOIN\n pg_catalog.pg_namespace n ON t.typnamespace = n.oid\n WHERE\n (c.table_schema, c.table_name) IN (${inClause})\n `;\n const {text, values} = formatPg(query);\n const results: Iterable<ServerSchemaRow> = (await dbTransaction.query(\n text,\n values,\n )) as Iterable<ServerSchemaRow>;\n\n const serverSchema: ServerSchema = {};\n\n for (const row of results) {\n const tableName =\n row.schema === 'public' ? row.table : `${row.schema}.${row.table}`;\n let tableSchema = serverSchema[tableName];\n if (!tableSchema) {\n tableSchema = {};\n serverSchema[tableName] = tableSchema;\n }\n const isArray = row.elemTyptype !== null;\n const isEnum = (row.elemTyptype ?? row.typtype) === PostgresTypeClass.Enum;\n let type = row.dataType.toLowerCase();\n if (isArray) {\n type = must(\n row.elemTypname,\n `Array column \"${row.column}\" in table \"${tableName}\" is missing element type name`,\n );\n } else if (isEnum) {\n type = row.typename;\n }\n if (\n (type === 'bpchar' ||\n type === 'character' ||\n type === 'character varying' ||\n type === 'varchar') &&\n row.length\n ) {\n type = `${type}(${row.length})`;\n }\n if (\n (type === 'numeric' || type === 'decimal') &&\n row.precision !== null &&\n row.scale !== null\n ) {\n type = `${type}(${row.precision}, ${row.scale})`;\n }\n tableSchema[row.column] = {\n type,\n isEnum,\n isArray,\n };\n }\n\n const errors = checkSchemasAreCompatible(schema, serverSchema);\n assert(errors.length === 0, () => makeSchemaIncompatibleErrorMessage(errors));\n\n return serverSchema;\n}\n\nfunction makeSchemaIncompatibleErrorMessage(\n errors: SchemaIncompatibilityError[],\n) {\n if (errors.length === 0) {\n return 'No schema incompatibilities found.';\n }\n\n const messages: string[] = [];\n\n for (const error of errors) {\n switch (error.type) {\n case 'missingTable':\n messages.push(\n `Table \"${error.table}\" is defined in your zero schema but does not exist in the database.`,\n );\n break;\n case 'missingColumn':\n messages.push(\n `Column \"${error.column}\" in table \"${error.table}\" is defined in your zero schema but does not exist in the database.`,\n );\n break;\n case 'typeError':\n messages.push(\n `Type mismatch for column \"${error.column}\" in table \"${error.table}\": ${error.requiredType === undefined ? `${error.pgType} is currently unsupported in Zero. Please file a bug at https://bugs.rocicorp.dev/` : `${error.pgType} should be mapped to ${error.requiredType} in Zero not ${error.declaredType}.`}`,\n );\n break;\n }\n }\n\n return [\n 'Schema incompatibility detected between your zero schema definition and the database:',\n '',\n ...messages.map(msg => ` - ${msg}`),\n '',\n 'Please update your schema definition to match the database or migrate your database to match the schema.',\n ].join('\\n');\n}\n\nexport type SchemaIncompatibilityError =\n | {\n type: 'typeError';\n table: string;\n column: string;\n pgType: string;\n declaredType: string;\n requiredType: string | undefined;\n }\n | {\n type: 'missingColumn';\n table: string;\n column: string;\n }\n | {\n type: 'missingTable';\n table: string;\n };\n\nexport function checkSchemasAreCompatible(\n schema: Schema,\n serverSchema: ServerSchema,\n): SchemaIncompatibilityError[] {\n const errors: SchemaIncompatibilityError[] = [];\n // Check that all tables in schema exist in serverSchema\n for (const table of Object.values(schema.tables)) {\n const serverTableName = table.serverName ?? table.name;\n\n if (!serverSchema[serverTableName]) {\n errors.push({\n type: 'missingTable',\n table: serverTableName,\n });\n continue;\n }\n\n // Check that all columns in the table exist in serverSchema\n for (const [columnName, column] of Object.entries(table.columns)) {\n const serverColumnName = column.serverName ?? columnName;\n\n if (!serverSchema[serverTableName][serverColumnName]) {\n errors.push({\n type: 'missingColumn',\n table: serverTableName,\n column: serverColumnName,\n });\n continue;\n }\n\n // Check type compatibility\n const serverColumn = serverSchema[serverTableName][serverColumnName];\n const declaredType = column.type;\n const pgType = serverColumn.type;\n const requiredType = dataTypeToZqlValueType(\n pgType,\n serverColumn.isEnum,\n serverColumn.isArray,\n );\n if (requiredType !== declaredType) {\n errors.push({\n type: 'typeError',\n table: serverTableName,\n column: serverColumnName,\n pgType,\n declaredType,\n requiredType,\n });\n }\n }\n }\n\n return errors;\n}\n"],"names":["schema","PostgresTypeClass.Enum"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zql-database.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/zql-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"zql-database.d.ts","sourceRoot":"","sources":["../../../../zero-server/src/zql-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,2BAA2B,CAAC;AAG5D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAgB,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,EACV,aAAa,EACb,KAAK,EACL,UAAU,EACX,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAqB,KAAK,eAAe,EAAC,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EACV,QAAQ,EACR,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;GAMG;AACH,qBAAa,WAAW,CAAC,OAAO,SAAS,MAAM,EAAE,mBAAmB,CAClE,YAAW,QAAQ,CAAC,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;;IAElE,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,mBAAmB,CAAC,CAAC;gBAG3C,UAAU,EAAE,YAAY,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,OAAO;IAK1E,WAAW,CAAC,CAAC,EACX,QAAQ,EAAE,CACR,EAAE,EAAE,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,EACjD,gBAAgB,EAAE,wBAAwB,KACvC,YAAY,CAAC,CAAC,CAAC,EACpB,gBAAgB,CAAC,EAAE,wBAAwB,GAC1C,OAAO,CAAC,CAAC,CAAC;IA8Eb,GAAG,CAAC,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,OAAO,EAC1D,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EACtC,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;CAGnC"}
|
|
@@ -45,6 +45,24 @@ class ZQLDatabase {
|
|
|
45
45
|
)}::text::json)`
|
|
46
46
|
);
|
|
47
47
|
await dbTx.query(formatted.text, formatted.values);
|
|
48
|
+
},
|
|
49
|
+
async deleteMutationResults(args) {
|
|
50
|
+
if ("type" in args && args.type === "bulk") {
|
|
51
|
+
const formatted = formatPg(
|
|
52
|
+
sql`DELETE FROM ${sql.ident(upstreamSchema)}."mutations"
|
|
53
|
+
WHERE "clientGroupID" = ${args.clientGroupID}
|
|
54
|
+
AND "clientID" = ANY(${args.clientIDs})`
|
|
55
|
+
);
|
|
56
|
+
await dbTx.query(formatted.text, formatted.values);
|
|
57
|
+
} else {
|
|
58
|
+
const formatted = formatPg(
|
|
59
|
+
sql`DELETE FROM ${sql.ident(upstreamSchema)}."mutations"
|
|
60
|
+
WHERE "clientGroupID" = ${args.clientGroupID}
|
|
61
|
+
AND "clientID" = ${args.clientID}
|
|
62
|
+
AND "mutationID" <= ${args.upToMutationID}`
|
|
63
|
+
);
|
|
64
|
+
await dbTx.query(formatted.text, formatted.values);
|
|
65
|
+
}
|
|
48
66
|
}
|
|
49
67
|
});
|
|
50
68
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zql-database.js","sources":["../../../../zero-server/src/zql-database.ts"],"sourcesContent":["import type {MaybePromise} from '../../shared/src/types.ts';\nimport {formatPg, sql} from '../../z2s/src/sql.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {DBConnection, DBTransaction} from '../../zql/src/mutate/custom.ts';\nimport type {\n HumanReadable,\n Query,\n RunOptions,\n} from '../../zql/src/query/query.ts';\nimport {CRUDMutatorFactory, type TransactionImpl} from './custom.ts';\nimport type {\n Database,\n TransactionProviderHooks,\n TransactionProviderInput,\n} from './process-mutations.ts';\n\n/**\n * Implements a Database for use with PushProcessor that is backed by Postgres.\n *\n * This implementation also implements the same ZQL interfaces for reading and\n * writing data that the Zero client does, so that mutator functions can be\n * shared across client and server.\n */\nexport class ZQLDatabase<TSchema extends Schema, TWrappedTransaction>\n implements Database<TransactionImpl<TSchema, TWrappedTransaction>>\n{\n readonly connection: DBConnection<TWrappedTransaction>;\n readonly #crudFactory: CRUDMutatorFactory<TSchema>;\n\n constructor(connection: DBConnection<TWrappedTransaction>, schema: TSchema) {\n this.connection = connection;\n this.#crudFactory = new CRUDMutatorFactory(schema);\n }\n\n transaction<R>(\n callback: (\n tx: TransactionImpl<TSchema, TWrappedTransaction>,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ): Promise<R> {\n // Icky hack. This is just here to have user not have to do this.\n // These interfaces need to be factored better.\n const {\n upstreamSchema = '',\n clientGroupID = '',\n clientID = '',\n mutationID = 0,\n } = transactionInput ?? {};\n return this.connection.transaction(async dbTx => {\n const zeroTx = await this.#makeServerTransaction(\n dbTx,\n clientID,\n mutationID,\n );\n\n return callback(zeroTx, {\n async updateClientMutationID() {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.clients \n as current (\"clientGroupID\", \"clientID\", \"lastMutationID\")\n VALUES (${clientGroupID}, ${clientID}, ${1})\n ON CONFLICT (\"clientGroupID\", \"clientID\")\n DO UPDATE SET \"lastMutationID\" = current.\"lastMutationID\" + 1\n RETURNING \"lastMutationID\"`,\n );\n\n const [{lastMutationID}] = (await dbTx.query(\n formatted.text,\n formatted.values,\n )) as {lastMutationID: bigint}[];\n\n return {lastMutationID};\n },\n\n async writeMutationResult(result) {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.mutations\n (\"clientGroupID\", \"clientID\", \"mutationID\", \"result\")\n VALUES (${clientGroupID}, ${result.id.clientID}, ${result.id.id}, ${JSON.stringify(\n result.result,\n )}::text::json)`,\n );\n await dbTx.query(formatted.text, formatted.values);\n },\n });\n });\n }\n\n #makeServerTransaction(\n dbTx: DBTransaction<TWrappedTransaction>,\n clientID: string,\n mutationID: number,\n ) {\n return this.#crudFactory.createTransaction(dbTx, clientID, mutationID);\n }\n\n run<TTable extends keyof TSchema['tables'] & string, TReturn>(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n return this.transaction(tx => tx.run(query, options));\n }\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"zql-database.js","sources":["../../../../zero-server/src/zql-database.ts"],"sourcesContent":["import type {MaybePromise} from '../../shared/src/types.ts';\nimport {formatPg, sql} from '../../z2s/src/sql.ts';\nimport type {CleanupResultsArg} from '../../zero-protocol/src/push.ts';\nimport type {Schema} from '../../zero-types/src/schema.ts';\nimport type {DBConnection, DBTransaction} from '../../zql/src/mutate/custom.ts';\nimport type {\n HumanReadable,\n Query,\n RunOptions,\n} from '../../zql/src/query/query.ts';\nimport {CRUDMutatorFactory, type TransactionImpl} from './custom.ts';\nimport type {\n Database,\n TransactionProviderHooks,\n TransactionProviderInput,\n} from './process-mutations.ts';\n\n/**\n * Implements a Database for use with PushProcessor that is backed by Postgres.\n *\n * This implementation also implements the same ZQL interfaces for reading and\n * writing data that the Zero client does, so that mutator functions can be\n * shared across client and server.\n */\nexport class ZQLDatabase<TSchema extends Schema, TWrappedTransaction>\n implements Database<TransactionImpl<TSchema, TWrappedTransaction>>\n{\n readonly connection: DBConnection<TWrappedTransaction>;\n readonly #crudFactory: CRUDMutatorFactory<TSchema>;\n\n constructor(connection: DBConnection<TWrappedTransaction>, schema: TSchema) {\n this.connection = connection;\n this.#crudFactory = new CRUDMutatorFactory(schema);\n }\n\n transaction<R>(\n callback: (\n tx: TransactionImpl<TSchema, TWrappedTransaction>,\n transactionHooks: TransactionProviderHooks,\n ) => MaybePromise<R>,\n transactionInput?: TransactionProviderInput,\n ): Promise<R> {\n // Icky hack. This is just here to have user not have to do this.\n // These interfaces need to be factored better.\n const {\n upstreamSchema = '',\n clientGroupID = '',\n clientID = '',\n mutationID = 0,\n } = transactionInput ?? {};\n return this.connection.transaction(async dbTx => {\n const zeroTx = await this.#makeServerTransaction(\n dbTx,\n clientID,\n mutationID,\n );\n\n return callback(zeroTx, {\n async updateClientMutationID() {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.clients \n as current (\"clientGroupID\", \"clientID\", \"lastMutationID\")\n VALUES (${clientGroupID}, ${clientID}, ${1})\n ON CONFLICT (\"clientGroupID\", \"clientID\")\n DO UPDATE SET \"lastMutationID\" = current.\"lastMutationID\" + 1\n RETURNING \"lastMutationID\"`,\n );\n\n const [{lastMutationID}] = (await dbTx.query(\n formatted.text,\n formatted.values,\n )) as {lastMutationID: bigint}[];\n\n return {lastMutationID};\n },\n\n async writeMutationResult(result) {\n const formatted = formatPg(\n sql`INSERT INTO ${sql.ident(upstreamSchema)}.mutations\n (\"clientGroupID\", \"clientID\", \"mutationID\", \"result\")\n VALUES (${clientGroupID}, ${result.id.clientID}, ${result.id.id}, ${JSON.stringify(\n result.result,\n )}::text::json)`,\n );\n await dbTx.query(formatted.text, formatted.values);\n },\n\n async deleteMutationResults(args: CleanupResultsArg) {\n if ('type' in args && args.type === 'bulk') {\n // Bulk deletion: delete all mutations for multiple clients\n const formatted = formatPg(\n sql`DELETE FROM ${sql.ident(upstreamSchema)}.\"mutations\"\n WHERE \"clientGroupID\" = ${args.clientGroupID}\n AND \"clientID\" = ANY(${args.clientIDs})`,\n );\n await dbTx.query(formatted.text, formatted.values);\n } else {\n // Single client (explicit 'single' or legacy without type): delete up to mutation ID\n const formatted = formatPg(\n sql`DELETE FROM ${sql.ident(upstreamSchema)}.\"mutations\"\n WHERE \"clientGroupID\" = ${args.clientGroupID}\n AND \"clientID\" = ${args.clientID}\n AND \"mutationID\" <= ${args.upToMutationID}`,\n );\n await dbTx.query(formatted.text, formatted.values);\n }\n },\n });\n });\n }\n\n #makeServerTransaction(\n dbTx: DBTransaction<TWrappedTransaction>,\n clientID: string,\n mutationID: number,\n ) {\n return this.#crudFactory.createTransaction(dbTx, clientID, mutationID);\n }\n\n run<TTable extends keyof TSchema['tables'] & string, TReturn>(\n query: Query<TTable, TSchema, TReturn>,\n options?: RunOptions,\n ): Promise<HumanReadable<TReturn>> {\n return this.transaction(tx => tx.run(query, options));\n }\n}\n"],"names":[],"mappings":";;AAwBO,MAAM,YAEb;AAAA,EACW;AAAA,EACA;AAAA,EAET,YAAY,YAA+C,QAAiB;AAC1E,SAAK,aAAa;AAClB,SAAK,eAAe,IAAI,mBAAmB,MAAM;AAAA,EACnD;AAAA,EAEA,YACE,UAIA,kBACY;AAGZ,UAAM;AAAA,MACJ,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,aAAa;AAAA,IAAA,IACX,oBAAoB,CAAA;AACxB,WAAO,KAAK,WAAW,YAAY,OAAM,SAAQ;AAC/C,YAAM,SAAS,MAAM,KAAK;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAGF,aAAO,SAAS,QAAQ;AAAA,QACtB,MAAM,yBAAyB;AAC7B,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA;AAAA,kCAErB,aAAa,KAAK,QAAQ,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA,UAAA;AAMxD,gBAAM,CAAC,EAAC,eAAA,CAAe,IAAK,MAAM,KAAK;AAAA,YACrC,UAAU;AAAA,YACV,UAAU;AAAA,UAAA;AAGZ,iBAAO,EAAC,eAAA;AAAA,QACV;AAAA,QAEA,MAAM,oBAAoB,QAAQ;AAChC,gBAAM,YAAY;AAAA,YAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA;AAAA,0BAE7B,aAAa,KAAK,OAAO,GAAG,QAAQ,KAAK,OAAO,GAAG,EAAE,KAAK,KAAK;AAAA,cACvE,OAAO;AAAA,YAAA,CACR;AAAA,UAAA;AAEP,gBAAM,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM;AAAA,QACnD;AAAA,QAEA,MAAM,sBAAsB,MAAyB;AACnD,cAAI,UAAU,QAAQ,KAAK,SAAS,QAAQ;AAE1C,kBAAM,YAAY;AAAA,cAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA,4CACb,KAAK,aAAa;AAAA,2CACnB,KAAK,SAAS;AAAA,YAAA;AAE7C,kBAAM,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM;AAAA,UACnD,OAAO;AAEL,kBAAM,YAAY;AAAA,cAChB,kBAAkB,IAAI,MAAM,cAAc,CAAC;AAAA,4CACb,KAAK,aAAa;AAAA,uCACvB,KAAK,QAAQ;AAAA,0CACV,KAAK,cAAc;AAAA,YAAA;AAEjD,kBAAM,KAAK,MAAM,UAAU,MAAM,UAAU,MAAM;AAAA,UACnD;AAAA,QACF;AAAA,MAAA,CACD;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,uBACE,MACA,UACA,YACA;AACA,WAAO,KAAK,aAAa,kBAAkB,MAAM,UAAU,UAAU;AAAA,EACvE;AAAA,EAEA,IACE,OACA,SACiC;AACjC,WAAO,KAAK,YAAY,CAAA,OAAM,GAAG,IAAI,OAAO,OAAO,CAAC;AAAA,EACtD;AACF;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { useConnectionState } from './use-connection-state.ts';
|
|
2
|
-
export { createQuery, useQuery, type CreateQueryOptions, type UseQueryOptions, } from './use-query.ts';
|
|
2
|
+
export { createQuery, useQuery, type CreateQueryOptions, type MaybeQueryResult, type QueryResult, type UseQueryOptions, } from './use-query.ts';
|
|
3
3
|
export { useZeroOnline } from './use-zero-online.ts';
|
|
4
4
|
export { createUseZero, createZero, useZero, ZeroProvider } from './use-zero.ts';
|
|
5
5
|
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../../zero-solid/src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAC,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAC,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../../zero-solid/src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,WAAW,EACX,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAC,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAC,MAAM,eAAe,CAAC"}
|
|
@@ -19,6 +19,7 @@ import "../../zero-protocol/src/custom-queries.js";
|
|
|
19
19
|
import "../../zero-protocol/src/client-schema.js";
|
|
20
20
|
import "../../zero-schema/src/permissions.js";
|
|
21
21
|
import "../../shared/src/document-visible.js";
|
|
22
|
+
import "../../shared/src/iterables.js";
|
|
22
23
|
import "../../replicache/src/btree/node.js";
|
|
23
24
|
import "compare-utf8";
|
|
24
25
|
import "../../replicache/src/sync/push.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solid-view.js","sources":["../../../../zero-solid/src/solid-view.ts"],"sourcesContent":["import {produce, reconcile, type SetStoreFunction} from 'solid-js/store';\nimport {emptyArray} from '../../shared/src/sentinels.ts';\nimport {\n applyChange,\n idSymbol,\n skipYields,\n type ViewChange,\n} from './bindings.ts';\nimport {\n type AnyViewFactory,\n type Change,\n type Entry,\n type ErroredQuery,\n type Format,\n type Input,\n type Node,\n type Output,\n type Query,\n type QueryErrorDetails,\n type QueryResultDetails,\n type Schema,\n type Stream,\n type TTL,\n} from './zero.ts';\n\nexport type State = [Entry, QueryResultDetails];\n\nexport const COMPLETE: QueryResultDetails = Object.freeze({type: 'complete'});\nexport const UNKNOWN: QueryResultDetails = Object.freeze({type: 'unknown'});\n\nexport class SolidView implements Output {\n readonly #input: Input;\n readonly #format: Format;\n readonly #onDestroy: () => void;\n readonly #retry: () => void;\n\n #setState: SetStoreFunction<State>;\n\n // Optimization: if the store is currently empty we build up\n // the view on a plain old JS object stored at #builderRoot, and return\n // that for the new state on transaction commit. This avoids building up\n // large views from scratch via solid produce. The proxy object used by\n // solid produce is slow and in this case we don't care about solid tracking\n // the fine grained changes (everything has changed, it's all new). For a\n // test case with a view with 3000 rows, each row having 2 children, this\n // optimization reduced #applyChanges time from 743ms to 133ms.\n #builderRoot: Entry | undefined;\n #pendingChanges: ViewChange[] = [];\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n onTransactionCommit: (cb: () => void) => void,\n format: Format,\n onDestroy: () => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n setState: SetStoreFunction<State>,\n retry: () => void,\n ) {\n this.#input = input;\n onTransactionCommit(this.#onTransactionCommit);\n this.#format = format;\n this.#onDestroy = onDestroy;\n this.#updateTTL = updateTTL;\n this.#retry = retry;\n\n input.setOutput(this);\n\n const initialRoot = this.#createEmptyRoot();\n this.#applyChangesToRoot(\n skipYields(input.fetch({})),\n node => ({type: 'add', node}),\n initialRoot,\n );\n\n this.#setState = setState;\n this.#setState(\n reconcile(\n [\n initialRoot,\n queryComplete === true\n ? COMPLETE\n : 'error' in queryComplete\n ? this.#makeError(queryComplete)\n : UNKNOWN,\n ],\n {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n },\n ),\n );\n\n if (isEmptyRoot(initialRoot)) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n\n if (queryComplete !== true && !('error' in queryComplete)) {\n void queryComplete\n .then(() => {\n this.#setState(prev => [prev[0], COMPLETE]);\n })\n .catch((error: ErroredQuery) => {\n this.#setState(prev => [prev[0], this.#makeError(error)]);\n });\n }\n }\n\n #makeError(error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry: this.#retry,\n refetch: this.#retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n }\n\n destroy(): void {\n this.#onDestroy();\n }\n\n #onTransactionCommit = () => {\n const builderRoot = this.#builderRoot;\n if (builderRoot) {\n if (!isEmptyRoot(builderRoot)) {\n this.#setState(\n 0,\n reconcile(builderRoot, {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n }),\n );\n this.#setState(prev => [builderRoot, prev[1]]);\n this.#builderRoot = undefined;\n }\n } else {\n try {\n this.#applyChanges(this.#pendingChanges, c => c);\n } finally {\n this.#pendingChanges = [];\n }\n }\n };\n\n push(change: Change) {\n // Delay updating the solid store state until the transaction commit\n // (because each update of the solid store is quite expensive). If\n // this.#builderRoot is defined apply the changes to it (we are building\n // from an empty root), otherwise queue the changes to be applied\n // using produce at the end of the transaction but read the relationships\n // now as they are only valid to read when the push is received.\n if (this.#builderRoot) {\n this.#applyChangeToRoot(change, this.#builderRoot);\n } else {\n this.#pendingChanges.push(materializeRelationships(change));\n }\n return emptyArray;\n }\n\n #applyChanges<T>(changes: Iterable<T>, mapper: (v: T) => ViewChange): void {\n this.#setState(\n produce((draftState: State) => {\n this.#applyChangesToRoot<T>(changes, mapper, draftState[0]);\n if (isEmptyRoot(draftState[0])) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n }),\n );\n }\n\n #applyChangesToRoot<T>(\n changes: Iterable<T>,\n mapper: (v: T) => ViewChange,\n root: Entry,\n ) {\n for (const change of changes) {\n this.#applyChangeToRoot(mapper(change), root);\n }\n }\n\n #applyChangeToRoot(change: ViewChange, root: Entry) {\n applyChange(\n root,\n change,\n this.#input.getSchema(),\n '',\n this.#format,\n true /* withIDs */,\n );\n }\n\n #createEmptyRoot(): Entry {\n return {\n '': this.#format.singular ? undefined : [],\n };\n }\n\n updateTTL(ttl: TTL): void {\n this.#updateTTL(ttl);\n }\n}\n\nfunction materializeRelationships(change: Change): ViewChange {\n switch (change.type) {\n case 'add':\n return {type: 'add', node: materializeNodeRelationships(change.node)};\n case 'remove':\n return {type: 'remove', node: materializeNodeRelationships(change.node)};\n case 'child':\n return {\n type: 'child',\n node: {row: change.node.row},\n child: {\n relationshipName: change.child.relationshipName,\n change: materializeRelationships(change.child.change),\n },\n };\n case 'edit':\n return {\n type: 'edit',\n node: {row: change.node.row},\n oldNode: {row: change.oldNode.row},\n };\n }\n}\n\nfunction materializeNodeRelationships(node: Node): Node {\n const relationships: Record<string, () => Stream<Node>> = {};\n for (const relationship in node.relationships) {\n const materialized: Node[] = [];\n for (const n of skipYields(node.relationships[relationship]())) {\n materialized.push(materializeNodeRelationships(n));\n }\n relationships[relationship] = () => materialized;\n }\n return {\n row: node.row,\n relationships,\n };\n}\n\nfunction isEmptyRoot(entry: Entry) {\n const data = entry[''];\n return data === undefined || (Array.isArray(data) && data.length === 0);\n}\n\nexport function createSolidViewFactory(\n setState: SetStoreFunction<State>,\n retry?: () => void,\n) {\n function solidViewFactory<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n _query: Query<TTable, TSchema, TReturn>,\n input: Input,\n format: Format,\n onDestroy: () => void,\n onTransactionCommit: (cb: () => void) => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n return new SolidView(\n input,\n onTransactionCommit,\n format,\n onDestroy,\n queryComplete,\n updateTTL,\n setState,\n retry || (() => {}),\n );\n }\n\n solidViewFactory satisfies AnyViewFactory;\n\n return solidViewFactory;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"solid-view.js","sources":["../../../../zero-solid/src/solid-view.ts"],"sourcesContent":["import {produce, reconcile, type SetStoreFunction} from 'solid-js/store';\nimport {emptyArray} from '../../shared/src/sentinels.ts';\nimport {\n applyChange,\n idSymbol,\n skipYields,\n type ViewChange,\n} from './bindings.ts';\nimport {\n type AnyViewFactory,\n type Change,\n type Entry,\n type ErroredQuery,\n type Format,\n type Input,\n type Node,\n type Output,\n type Query,\n type QueryErrorDetails,\n type QueryResultDetails,\n type Schema,\n type Stream,\n type TTL,\n} from './zero.ts';\n\nexport type State = [Entry, QueryResultDetails];\n\nexport const COMPLETE: QueryResultDetails = Object.freeze({type: 'complete'});\nexport const UNKNOWN: QueryResultDetails = Object.freeze({type: 'unknown'});\n\nexport class SolidView implements Output {\n readonly #input: Input;\n readonly #format: Format;\n readonly #onDestroy: () => void;\n readonly #retry: () => void;\n\n #setState: SetStoreFunction<State>;\n\n // Optimization: if the store is currently empty we build up\n // the view on a plain old JS object stored at #builderRoot, and return\n // that for the new state on transaction commit. This avoids building up\n // large views from scratch via solid produce. The proxy object used by\n // solid produce is slow and in this case we don't care about solid tracking\n // the fine grained changes (everything has changed, it's all new). For a\n // test case with a view with 3000 rows, each row having 2 children, this\n // optimization reduced #applyChanges time from 743ms to 133ms.\n #builderRoot: Entry | undefined;\n #pendingChanges: ViewChange[] = [];\n readonly #updateTTL: (ttl: TTL) => void;\n\n constructor(\n input: Input,\n onTransactionCommit: (cb: () => void) => void,\n format: Format,\n onDestroy: () => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n setState: SetStoreFunction<State>,\n retry: () => void,\n ) {\n this.#input = input;\n onTransactionCommit(this.#onTransactionCommit);\n this.#format = format;\n this.#onDestroy = onDestroy;\n this.#updateTTL = updateTTL;\n this.#retry = retry;\n\n input.setOutput(this);\n\n const initialRoot = this.#createEmptyRoot();\n this.#applyChangesToRoot(\n skipYields(input.fetch({})),\n node => ({type: 'add', node}),\n initialRoot,\n );\n\n this.#setState = setState;\n this.#setState(\n reconcile(\n [\n initialRoot,\n queryComplete === true\n ? COMPLETE\n : 'error' in queryComplete\n ? this.#makeError(queryComplete)\n : UNKNOWN,\n ],\n {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n },\n ),\n );\n\n if (isEmptyRoot(initialRoot)) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n\n if (queryComplete !== true && !('error' in queryComplete)) {\n void queryComplete\n .then(() => {\n this.#setState(prev => [prev[0], COMPLETE]);\n })\n .catch((error: ErroredQuery) => {\n this.#setState(prev => [prev[0], this.#makeError(error)]);\n });\n }\n }\n\n #makeError(error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry: this.#retry,\n refetch: this.#retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n }\n\n destroy(): void {\n this.#onDestroy();\n }\n\n #onTransactionCommit = () => {\n const builderRoot = this.#builderRoot;\n if (builderRoot) {\n if (!isEmptyRoot(builderRoot)) {\n this.#setState(\n 0,\n reconcile(builderRoot, {\n // solidjs's types want a string, but a symbol works\n key: idSymbol as unknown as string,\n }),\n );\n this.#setState(prev => [builderRoot, prev[1]]);\n this.#builderRoot = undefined;\n }\n } else {\n try {\n this.#applyChanges(this.#pendingChanges, c => c);\n } finally {\n this.#pendingChanges = [];\n }\n }\n };\n\n push(change: Change) {\n // Delay updating the solid store state until the transaction commit\n // (because each update of the solid store is quite expensive). If\n // this.#builderRoot is defined apply the changes to it (we are building\n // from an empty root), otherwise queue the changes to be applied\n // using produce at the end of the transaction but read the relationships\n // now as they are only valid to read when the push is received.\n if (this.#builderRoot) {\n this.#applyChangeToRoot(change, this.#builderRoot);\n } else {\n this.#pendingChanges.push(materializeRelationships(change));\n }\n return emptyArray;\n }\n\n #applyChanges<T>(changes: Iterable<T>, mapper: (v: T) => ViewChange): void {\n this.#setState(\n produce((draftState: State) => {\n this.#applyChangesToRoot<T>(changes, mapper, draftState[0]);\n if (isEmptyRoot(draftState[0])) {\n this.#builderRoot = this.#createEmptyRoot();\n }\n }),\n );\n }\n\n #applyChangesToRoot<T>(\n changes: Iterable<T>,\n mapper: (v: T) => ViewChange,\n root: Entry,\n ) {\n for (const change of changes) {\n this.#applyChangeToRoot(mapper(change), root);\n }\n }\n\n #applyChangeToRoot(change: ViewChange, root: Entry) {\n applyChange(\n root,\n change,\n this.#input.getSchema(),\n '',\n this.#format,\n true /* withIDs */,\n );\n }\n\n #createEmptyRoot(): Entry {\n return {\n '': this.#format.singular ? undefined : [],\n };\n }\n\n updateTTL(ttl: TTL): void {\n this.#updateTTL(ttl);\n }\n}\n\nfunction materializeRelationships(change: Change): ViewChange {\n switch (change.type) {\n case 'add':\n return {type: 'add', node: materializeNodeRelationships(change.node)};\n case 'remove':\n return {type: 'remove', node: materializeNodeRelationships(change.node)};\n case 'child':\n return {\n type: 'child',\n node: {row: change.node.row},\n child: {\n relationshipName: change.child.relationshipName,\n change: materializeRelationships(change.child.change),\n },\n };\n case 'edit':\n return {\n type: 'edit',\n node: {row: change.node.row},\n oldNode: {row: change.oldNode.row},\n };\n }\n}\n\nfunction materializeNodeRelationships(node: Node): Node {\n const relationships: Record<string, () => Stream<Node>> = {};\n for (const relationship in node.relationships) {\n const materialized: Node[] = [];\n for (const n of skipYields(node.relationships[relationship]())) {\n materialized.push(materializeNodeRelationships(n));\n }\n relationships[relationship] = () => materialized;\n }\n return {\n row: node.row,\n relationships,\n };\n}\n\nfunction isEmptyRoot(entry: Entry) {\n const data = entry[''];\n return data === undefined || (Array.isArray(data) && data.length === 0);\n}\n\nexport function createSolidViewFactory(\n setState: SetStoreFunction<State>,\n retry?: () => void,\n) {\n function solidViewFactory<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n >(\n _query: Query<TTable, TSchema, TReturn>,\n input: Input,\n format: Format,\n onDestroy: () => void,\n onTransactionCommit: (cb: () => void) => void,\n queryComplete: true | ErroredQuery | Promise<true>,\n updateTTL: (ttl: TTL) => void,\n ) {\n return new SolidView(\n input,\n onTransactionCommit,\n format,\n onDestroy,\n queryComplete,\n updateTTL,\n setState,\n retry || (() => {}),\n );\n }\n\n solidViewFactory satisfies AnyViewFactory;\n\n return solidViewFactory;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { type Accessor } from 'solid-js';
|
|
2
|
-
import { type DefaultContext, type DefaultSchema, type HumanReadable, type PullRow, type QueryOrQueryRequest, type QueryResultDetails, type ReadonlyJSONValue, type Schema, type TTL } from './zero.ts';
|
|
2
|
+
import { type DefaultContext, type DefaultSchema, type Falsy, type HumanReadable, type PullRow, type QueryOrQueryRequest, type QueryResultDetails, type ReadonlyJSONValue, type Schema, type TTL } from './zero.ts';
|
|
3
3
|
export type QueryResult<TReturn> = readonly [
|
|
4
4
|
Accessor<HumanReadable<TReturn>>,
|
|
5
5
|
Accessor<QueryResultDetails & {}>
|
|
6
6
|
];
|
|
7
|
+
/**
|
|
8
|
+
* Result type for "maybe queries" - queries that may be falsy.
|
|
9
|
+
* The data value can be undefined when the query is falsy/disabled.
|
|
10
|
+
*/
|
|
11
|
+
export type MaybeQueryResult<TReturn> = readonly [
|
|
12
|
+
Accessor<HumanReadable<TReturn> | undefined>,
|
|
13
|
+
Accessor<QueryResultDetails & {}>
|
|
14
|
+
];
|
|
7
15
|
/**
|
|
8
16
|
* @deprecated Use {@linkcode UseQueryOptions} instead.
|
|
9
17
|
*/
|
|
@@ -18,4 +26,5 @@ export type UseQueryOptions = {
|
|
|
18
26
|
*/
|
|
19
27
|
export declare function createQuery<TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TSchema extends Schema = DefaultSchema, TReturn = PullRow<TTable, TSchema>, TContext = DefaultContext>(querySignal: Accessor<QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>>, options?: CreateQueryOptions | Accessor<CreateQueryOptions>): QueryResult<TReturn>;
|
|
20
28
|
export declare function useQuery<TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TSchema extends Schema = DefaultSchema, TReturn = PullRow<TTable, TSchema>, TContext = DefaultContext>(querySignal: Accessor<QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>>, options?: UseQueryOptions | Accessor<UseQueryOptions>): QueryResult<TReturn>;
|
|
29
|
+
export declare function useQuery<TTable extends keyof TSchema['tables'] & string, TInput extends ReadonlyJSONValue | undefined, TOutput extends ReadonlyJSONValue | undefined, TSchema extends Schema = DefaultSchema, TReturn = PullRow<TTable, TSchema>, TContext = DefaultContext>(querySignal: Accessor<QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext> | Falsy>, options?: UseQueryOptions | Accessor<UseQueryOptions>): MaybeQueryResult<TReturn>;
|
|
21
30
|
//# sourceMappingURL=use-query.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-query.d.ts","sourceRoot":"","sources":["../../../../zero-solid/src/use-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,QAAQ,EACd,MAAM,UAAU,CAAC;AASlB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,GAAG,EACT,MAAM,WAAW,CAAC;AAEnB,MAAM,MAAM,WAAW,CAAC,OAAO,IAAI,SAAS;IAC1C,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,kBAAkB,GAAG,EAAE,CAAC;CAClC,CAAC;AAGF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;CACvB,CAAC;AAGF;;GAEG;AACH,wBAAgB,WAAW,CACzB,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAC/C,MAAM,SAAS,iBAAiB,GAAG,SAAS,EAC5C,OAAO,SAAS,iBAAiB,GAAG,SAAS,EAC7C,OAAO,SAAS,MAAM,GAAG,aAAa,EACtC,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,QAAQ,GAAG,cAAc,EAEzB,WAAW,EAAE,QAAQ,CACnB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CACzE,EACD,OAAO,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CAAC,kBAAkB,CAAC,GAC1D,WAAW,CAAC,OAAO,CAAC,CAEtB;
|
|
1
|
+
{"version":3,"file":"use-query.d.ts","sourceRoot":"","sources":["../../../../zero-solid/src/use-query.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,QAAQ,EACd,MAAM,UAAU,CAAC;AASlB,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,GAAG,EACT,MAAM,WAAW,CAAC;AAEnB,MAAM,MAAM,WAAW,CAAC,OAAO,IAAI,SAAS;IAC1C,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,kBAAkB,GAAG,EAAE,CAAC;CAClC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,IAAI,SAAS;IAC/C,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,kBAAkB,GAAG,EAAE,CAAC;CAClC,CAAC;AAGF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;CACvB,CAAC;AAGF;;GAEG;AACH,wBAAgB,WAAW,CACzB,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAC/C,MAAM,SAAS,iBAAiB,GAAG,SAAS,EAC5C,OAAO,SAAS,iBAAiB,GAAG,SAAS,EAC7C,OAAO,SAAS,MAAM,GAAG,aAAa,EACtC,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,QAAQ,GAAG,cAAc,EAEzB,WAAW,EAAE,QAAQ,CACnB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CACzE,EACD,OAAO,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CAAC,kBAAkB,CAAC,GAC1D,WAAW,CAAC,OAAO,CAAC,CAEtB;AAGD,wBAAgB,QAAQ,CACtB,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAC/C,MAAM,SAAS,iBAAiB,GAAG,SAAS,EAC5C,OAAO,SAAS,iBAAiB,GAAG,SAAS,EAC7C,OAAO,SAAS,MAAM,GAAG,aAAa,EACtC,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,QAAQ,GAAG,cAAc,EAEzB,WAAW,EAAE,QAAQ,CACnB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CACzE,EACD,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC,GACpD,WAAW,CAAC,OAAO,CAAC,CAAC;AAGxB,wBAAgB,QAAQ,CACtB,MAAM,SAAS,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,MAAM,EAC/C,MAAM,SAAS,iBAAiB,GAAG,SAAS,EAC5C,OAAO,SAAS,iBAAiB,GAAG,SAAS,EAC7C,OAAO,SAAS,MAAM,GAAG,aAAa,EACtC,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,QAAQ,GAAG,cAAc,EAEzB,WAAW,EAAE,QAAQ,CACjB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,GACxE,KAAK,CACR,EACD,OAAO,CAAC,EAAE,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC,GACpD,gBAAgB,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -23,6 +23,7 @@ import "../../zero-protocol/src/custom-queries.js";
|
|
|
23
23
|
import "../../zero-protocol/src/client-schema.js";
|
|
24
24
|
import "../../zero-schema/src/permissions.js";
|
|
25
25
|
import "../../shared/src/document-visible.js";
|
|
26
|
+
import "../../shared/src/iterables.js";
|
|
26
27
|
import "../../replicache/src/btree/node.js";
|
|
27
28
|
import "../../replicache/src/sync/push.js";
|
|
28
29
|
import "../../shared/src/valita.js";
|
|
@@ -52,15 +53,31 @@ function useQuery(querySignal, options) {
|
|
|
52
53
|
setRefetchKey((k) => k + 1);
|
|
53
54
|
};
|
|
54
55
|
const zero = useZero();
|
|
55
|
-
const q = createMemo(() =>
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
const q = createMemo(() => {
|
|
57
|
+
const query = querySignal();
|
|
58
|
+
if (!query) return void 0;
|
|
59
|
+
return addContextToQuery(query, zero().context);
|
|
60
|
+
});
|
|
61
|
+
const qi = createMemo(() => {
|
|
62
|
+
const query = q();
|
|
63
|
+
if (!query) return void 0;
|
|
64
|
+
return asQueryInternals(query);
|
|
65
|
+
});
|
|
66
|
+
const hash = createMemo(() => qi()?.hash());
|
|
58
67
|
const ttl = createMemo(() => normalize(options)?.ttl ?? DEFAULT_TTL_MS);
|
|
59
68
|
const initialTTL = ttl();
|
|
60
69
|
const view = createMemo(() => {
|
|
61
|
-
hash();
|
|
70
|
+
const currentHash = hash();
|
|
62
71
|
refetchKey();
|
|
72
|
+
if (currentHash === void 0) {
|
|
73
|
+
setState([{ "": void 0 }, UNKNOWN]);
|
|
74
|
+
return void 0;
|
|
75
|
+
}
|
|
63
76
|
const untrackedQuery = untrack(q);
|
|
77
|
+
if (!untrackedQuery) {
|
|
78
|
+
setState([{ "": void 0 }, UNKNOWN]);
|
|
79
|
+
return void 0;
|
|
80
|
+
}
|
|
64
81
|
const v = zero().materialize(
|
|
65
82
|
untrackedQuery,
|
|
66
83
|
createSolidViewFactory(setState, refetch),
|
|
@@ -75,7 +92,7 @@ function useQuery(querySignal, options) {
|
|
|
75
92
|
on(
|
|
76
93
|
ttl,
|
|
77
94
|
(currentTTL) => {
|
|
78
|
-
view()
|
|
95
|
+
view()?.updateTTL(currentTTL);
|
|
79
96
|
},
|
|
80
97
|
{ defer: true }
|
|
81
98
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-query.js","sources":["../../../../zero-solid/src/use-query.ts"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n untrack,\n type Accessor,\n} from 'solid-js';\nimport {createStore} from 'solid-js/store';\nimport {\n addContextToQuery,\n asQueryInternals,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {createSolidViewFactory, UNKNOWN, type State} from './solid-view.ts';\nimport {useZero} from './use-zero.ts';\nimport {\n type DefaultContext,\n type DefaultSchema,\n type HumanReadable,\n type PullRow,\n type QueryOrQueryRequest,\n type QueryResultDetails,\n type ReadonlyJSONValue,\n type Schema,\n type TTL,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn>>,\n Accessor<QueryResultDetails & {}>,\n];\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode UseQueryOptions} instead.\n */\nexport type CreateQueryOptions = {\n ttl?: TTL | undefined;\n};\n\nexport type UseQueryOptions = {\n ttl?: TTL | undefined;\n};\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode useQuery} instead.\n */\nexport function createQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: CreateQueryOptions | Accessor<CreateQueryOptions>,\n): QueryResult<TReturn> {\n return useQuery(querySignal, options);\n}\n\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn> {\n const [state, setState] = createStore<State>([\n {\n '': undefined,\n },\n UNKNOWN,\n ]);\n const initialRefetchKey = 0;\n const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);\n\n const refetch = () => {\n setRefetchKey(k => k + 1);\n };\n\n const zero = useZero<TSchema, undefined, TContext>();\n const q = createMemo(() =>
|
|
1
|
+
{"version":3,"file":"use-query.js","sources":["../../../../zero-solid/src/use-query.ts"],"sourcesContent":["import {\n createEffect,\n createMemo,\n createSignal,\n on,\n onCleanup,\n untrack,\n type Accessor,\n} from 'solid-js';\nimport {createStore} from 'solid-js/store';\nimport {\n addContextToQuery,\n asQueryInternals,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {createSolidViewFactory, UNKNOWN, type State} from './solid-view.ts';\nimport {useZero} from './use-zero.ts';\nimport {\n type DefaultContext,\n type DefaultSchema,\n type Falsy,\n type HumanReadable,\n type PullRow,\n type QueryOrQueryRequest,\n type QueryResultDetails,\n type ReadonlyJSONValue,\n type Schema,\n type TTL,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn>>,\n Accessor<QueryResultDetails & {}>,\n];\n\n/**\n * Result type for \"maybe queries\" - queries that may be falsy.\n * The data value can be undefined when the query is falsy/disabled.\n */\nexport type MaybeQueryResult<TReturn> = readonly [\n Accessor<HumanReadable<TReturn> | undefined>,\n Accessor<QueryResultDetails & {}>,\n];\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode UseQueryOptions} instead.\n */\nexport type CreateQueryOptions = {\n ttl?: TTL | undefined;\n};\n\nexport type UseQueryOptions = {\n ttl?: TTL | undefined;\n};\n\n// Deprecated in 0.22\n/**\n * @deprecated Use {@linkcode useQuery} instead.\n */\nexport function createQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: CreateQueryOptions | Accessor<CreateQueryOptions>,\n): QueryResult<TReturn> {\n return useQuery(querySignal, options);\n}\n\n// Overload 1: Query - returns QueryResult<TReturn>\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn>;\n\n// Overload 2: Maybe query\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): MaybeQueryResult<TReturn>;\n\n// Implementation\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n querySignal: Accessor<\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy\n >,\n options?: UseQueryOptions | Accessor<UseQueryOptions>,\n): QueryResult<TReturn> | MaybeQueryResult<TReturn> {\n const [state, setState] = createStore<State>([\n {\n '': undefined,\n },\n UNKNOWN,\n ]);\n const initialRefetchKey = 0;\n const [refetchKey, setRefetchKey] = createSignal(initialRefetchKey);\n\n const refetch = () => {\n setRefetchKey(k => k + 1);\n };\n\n const zero = useZero<TSchema, undefined, TContext>();\n\n // Handle possibly falsy queries\n const q = createMemo(() => {\n const query = querySignal();\n if (!query) return undefined;\n return addContextToQuery(query, zero().context);\n });\n\n const qi = createMemo(() => {\n const query = q();\n if (!query) return undefined;\n return asQueryInternals(query);\n });\n\n const hash = createMemo(() => qi()?.hash());\n const ttl = createMemo(() => normalize(options)?.ttl ?? DEFAULT_TTL_MS);\n\n const initialTTL = ttl();\n\n const view = createMemo(() => {\n // Depend on hash instead of query to avoid recreating the view when the\n // query object changes but the hash is the same.\n const currentHash = hash();\n refetchKey();\n\n // If query is falsy, don't create a view and reset state to undefined\n if (currentHash === undefined) {\n setState([{'': undefined}, UNKNOWN]);\n return undefined;\n }\n\n const untrackedQuery = untrack(q);\n if (!untrackedQuery) {\n setState([{'': undefined}, UNKNOWN]);\n return undefined;\n }\n\n const v = zero().materialize(\n untrackedQuery,\n createSolidViewFactory(setState, refetch),\n {\n ttl: initialTTL,\n },\n );\n\n onCleanup(() => v.destroy());\n\n return v;\n });\n\n // Update TTL on existing view when it changes.\n createEffect(\n on(\n ttl,\n currentTTL => {\n view()?.updateTTL(currentTTL);\n },\n {defer: true},\n ),\n );\n\n return [() => state[0][''] as HumanReadable<TReturn>, () => state[1]];\n}\n\nfunction normalize<T>(options?: T | Accessor<T | undefined>): T | undefined {\n return typeof options === 'function' ? (options as Accessor<T>)() : options;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DO,SAAS,YAQd,aAGA,SACsB;AACtB,SAAO,SAAS,aAAa,OAAO;AACtC;AAkCO,SAAS,SAQd,aAIA,SACkD;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,YAAmB;AAAA,IAC3C;AAAA,MACE,IAAI;AAAA,IAAA;AAAA,IAEN;AAAA,EAAA,CACD;AACD,QAAM,oBAAoB;AAC1B,QAAM,CAAC,YAAY,aAAa,IAAI,aAAa,iBAAiB;AAElE,QAAM,UAAU,MAAM;AACpB,kBAAc,CAAA,MAAK,IAAI,CAAC;AAAA,EAC1B;AAEA,QAAM,OAAO,QAAA;AAGb,QAAM,IAAI,WAAW,MAAM;AACzB,UAAM,QAAQ,YAAA;AACd,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,kBAAkB,OAAO,KAAA,EAAO,OAAO;AAAA,EAChD,CAAC;AAED,QAAM,KAAK,WAAW,MAAM;AAC1B,UAAM,QAAQ,EAAA;AACd,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,iBAAiB,KAAK;AAAA,EAC/B,CAAC;AAED,QAAM,OAAO,WAAW,MAAM,GAAA,GAAM,MAAM;AAC1C,QAAM,MAAM,WAAW,MAAM,UAAU,OAAO,GAAG,OAAO,cAAc;AAEtE,QAAM,aAAa,IAAA;AAEnB,QAAM,OAAO,WAAW,MAAM;AAG5B,UAAM,cAAc,KAAA;AACpB,eAAA;AAGA,QAAI,gBAAgB,QAAW;AAC7B,eAAS,CAAC,EAAC,IAAI,OAAA,GAAY,OAAO,CAAC;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,QAAQ,CAAC;AAChC,QAAI,CAAC,gBAAgB;AACnB,eAAS,CAAC,EAAC,IAAI,OAAA,GAAY,OAAO,CAAC;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,OAAO;AAAA,MACf;AAAA,MACA,uBAAuB,UAAU,OAAO;AAAA,MACxC;AAAA,QACE,KAAK;AAAA,MAAA;AAAA,IACP;AAGF,cAAU,MAAM,EAAE,SAAS;AAE3B,WAAO;AAAA,EACT,CAAC;AAGD;AAAA,IACE;AAAA,MACE;AAAA,MACA,CAAA,eAAc;AACZ,aAAA,GAAQ,UAAU,UAAU;AAAA,MAC9B;AAAA,MACA,EAAC,OAAO,KAAA;AAAA,IAAI;AAAA,EACd;AAGF,SAAO,CAAC,MAAM,MAAM,CAAC,EAAE,EAAE,GAA6B,MAAM,MAAM,CAAC,CAAC;AACtE;AAEA,SAAS,UAAa,SAAsD;AAC1E,SAAO,OAAO,YAAY,aAAc,QAAA,IAA4B;AACtE;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-zero.js","sources":["../../../../zero-solid/src/use-zero.ts"],"sourcesContent":["import {\n batch,\n createContext,\n createEffect,\n createMemo,\n onCleanup,\n splitProps,\n untrack,\n useContext,\n type Accessor,\n type JSX,\n} from 'solid-js';\nimport {\n Zero,\n type CustomMutatorDefs,\n type DefaultContext,\n type DefaultSchema,\n type Schema,\n type ZeroOptions,\n} from './zero.ts';\n\nconst ZeroContext = createContext<\n // oxlint-disable-next-line no-explicit-any\n Accessor<Zero<any, any, any>> | undefined\n>(undefined);\n\n/**\n * @deprecated Use {@linkcode ZeroProvider} instead of managing your own Zero instance.\n */\nexport function createZero<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>(options: ZeroOptions<S, MD, Context>): Zero<S, MD, Context> {\n const opts = {\n ...options,\n batchViewUpdates: batch,\n };\n return new Zero(opts);\n}\n\nexport function useZero<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>(): () => Zero<S, MD, Context> {\n const zero = useContext(ZeroContext);\n\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero;\n}\n\n/**\n * @deprecated Use {@linkcode useZero} instead, alongside default types defined with:\n *\n * ```ts\n * declare module '@rocicorp/zero' {\n * interface DefaultTypes {\n * schema: typeof schema;\n * context: Context;\n * }\n * }\n */\nexport function createUseZero<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>() {\n return () => useZero<S, MD, Context>();\n}\n\nconst NO_AUTH_SET = Symbol();\n\nexport function ZeroProvider<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>(\n props: {\n children: JSX.Element;\n init?: (zero: Zero<S, MD, Context>) => void;\n } & (\n | {\n zero: Zero<S, MD, Context>;\n }\n | ZeroOptions<S, MD, Context>\n ),\n) {\n const zero = createMemo(() => {\n if ('zero' in props) {\n return props.zero;\n }\n\n const [, options] = splitProps(props, ['children', 'auth']);\n\n const authValue = untrack(() => props.auth);\n const createdZero = new Zero({\n ...options,\n ...(authValue !== undefined ? {auth: authValue} : {}),\n batchViewUpdates: batch,\n });\n options.init?.(createdZero);\n onCleanup(() => createdZero.close());\n return createdZero;\n });\n\n const auth = createMemo<\n typeof NO_AUTH_SET | ZeroOptions<S, MD, Context>['auth']\n >(() => ('auth' in props ? props.auth : NO_AUTH_SET));\n\n let prevAuth: typeof NO_AUTH_SET | ZeroOptions<S, MD, Context>['auth'] =\n NO_AUTH_SET;\n\n createEffect(() => {\n const currentZero = zero();\n if (!currentZero) {\n return;\n }\n\n const currentAuth = auth();\n\n if (prevAuth === NO_AUTH_SET) {\n prevAuth = currentAuth;\n return;\n }\n\n if (currentAuth !== prevAuth) {\n prevAuth = currentAuth;\n void currentZero.connection.connect({\n auth: currentAuth === NO_AUTH_SET ? undefined : currentAuth,\n });\n }\n });\n\n return ZeroContext.Provider({\n value: zero,\n get children() {\n return props.children;\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAM,cAAc,cAGlB,MAAS;AAKJ,SAAS,WAId,SAA4D;AAC5D,QAAM,OAAO;AAAA,IACX,GAAG;AAAA,IACH,kBAAkB;AAAA,EAAA;AAEpB,SAAO,IAAI,KAAK,IAAI;AACtB;AAEO,SAAS,UAIgB;AAC9B,QAAM,OAAO,WAAW,WAAW;AAEnC,MAAI,SAAS,QAAW;AACtB,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,SAAO;AACT;AAaO,SAAS,gBAIZ;AACF,SAAO,MAAM,QAAA;AACf;AAEA,MAAM,cAAc,OAAA;AAEb,SAAS,aAKd,OASA;AACA,QAAM,OAAO,WAAW,MAAM;AAC5B,QAAI,UAAU,OAAO;AACnB,aAAO,MAAM;AAAA,IACf;AAEA,UAAM,CAAA,EAAG,OAAO,IAAI,WAAW,OAAO,CAAC,YAAY,MAAM,CAAC;AAE1D,UAAM,YAAY,QAAQ,MAAM,MAAM,IAAI;AAC1C,UAAM,cAAc,IAAI,KAAK;AAAA,MAC3B,GAAG;AAAA,MACH,GAAI,cAAc,SAAY,EAAC,MAAM,UAAA,IAAa,CAAA;AAAA,MAClD,kBAAkB;AAAA,IAAA,CACnB;AACD,YAAQ,OAAO,WAAW;AAC1B,cAAU,MAAM,YAAY,OAAO;AACnC,WAAO;AAAA,EACT,CAAC;AAED,QAAM,OAAO,WAEX,MAAO,UAAU,QAAQ,MAAM,OAAO,WAAY;AAEpD,MAAI,WACF;AAEF,eAAa,MAAM;AACjB,UAAM,cAAc,KAAA;AACpB,QAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"use-zero.js","sources":["../../../../zero-solid/src/use-zero.ts"],"sourcesContent":["import {\n batch,\n createContext,\n createEffect,\n createMemo,\n onCleanup,\n splitProps,\n untrack,\n useContext,\n type Accessor,\n type JSX,\n} from 'solid-js';\nimport {\n Zero,\n type CustomMutatorDefs,\n type DefaultContext,\n type DefaultSchema,\n type Schema,\n type ZeroOptions,\n} from './zero.ts';\n\nconst ZeroContext = createContext<\n // oxlint-disable-next-line no-explicit-any\n Accessor<Zero<any, any, any>> | undefined\n>(undefined);\n\n/**\n * @deprecated Use {@linkcode ZeroProvider} instead of managing your own Zero instance.\n */\nexport function createZero<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>(options: ZeroOptions<S, MD, Context>): Zero<S, MD, Context> {\n const opts = {\n ...options,\n batchViewUpdates: batch,\n };\n return new Zero(opts);\n}\n\nexport function useZero<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>(): () => Zero<S, MD, Context> {\n const zero = useContext(ZeroContext);\n\n if (zero === undefined) {\n throw new Error('useZero must be used within a ZeroProvider');\n }\n return zero;\n}\n\n/**\n * @deprecated Use {@linkcode useZero} instead, alongside default types defined with:\n *\n * ```ts\n * declare module '@rocicorp/zero' {\n * interface DefaultTypes {\n * schema: typeof schema;\n * context: Context;\n * }\n * }\n */\nexport function createUseZero<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>() {\n return () => useZero<S, MD, Context>();\n}\n\nconst NO_AUTH_SET = Symbol();\n\nexport function ZeroProvider<\n S extends Schema = DefaultSchema,\n MD extends CustomMutatorDefs | undefined = undefined,\n Context = DefaultContext,\n>(\n props: {\n children: JSX.Element;\n init?: (zero: Zero<S, MD, Context>) => void;\n } & (\n | {\n zero: Zero<S, MD, Context>;\n }\n | ZeroOptions<S, MD, Context>\n ),\n) {\n const zero = createMemo(() => {\n if ('zero' in props) {\n return props.zero;\n }\n\n const [, options] = splitProps(props, ['children', 'auth']);\n\n const authValue = untrack(() => props.auth);\n const createdZero = new Zero({\n ...options,\n ...(authValue !== undefined ? {auth: authValue} : {}),\n batchViewUpdates: batch,\n });\n options.init?.(createdZero);\n onCleanup(() => createdZero.close());\n return createdZero;\n });\n\n const auth = createMemo<\n typeof NO_AUTH_SET | ZeroOptions<S, MD, Context>['auth']\n >(() => ('auth' in props ? props.auth : NO_AUTH_SET));\n\n let prevAuth: typeof NO_AUTH_SET | ZeroOptions<S, MD, Context>['auth'] =\n NO_AUTH_SET;\n\n createEffect(() => {\n const currentZero = zero();\n if (!currentZero || 'zero' in props) {\n return;\n }\n\n const currentAuth = auth();\n\n if (prevAuth === NO_AUTH_SET) {\n prevAuth = currentAuth;\n return;\n }\n\n if (currentAuth !== prevAuth) {\n prevAuth = currentAuth;\n void currentZero.connection.connect({\n auth: currentAuth === NO_AUTH_SET ? undefined : currentAuth,\n });\n }\n });\n\n return ZeroContext.Provider({\n value: zero,\n get children() {\n return props.children;\n },\n });\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAM,cAAc,cAGlB,MAAS;AAKJ,SAAS,WAId,SAA4D;AAC5D,QAAM,OAAO;AAAA,IACX,GAAG;AAAA,IACH,kBAAkB;AAAA,EAAA;AAEpB,SAAO,IAAI,KAAK,IAAI;AACtB;AAEO,SAAS,UAIgB;AAC9B,QAAM,OAAO,WAAW,WAAW;AAEnC,MAAI,SAAS,QAAW;AACtB,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,SAAO;AACT;AAaO,SAAS,gBAIZ;AACF,SAAO,MAAM,QAAA;AACf;AAEA,MAAM,cAAc,OAAA;AAEb,SAAS,aAKd,OASA;AACA,QAAM,OAAO,WAAW,MAAM;AAC5B,QAAI,UAAU,OAAO;AACnB,aAAO,MAAM;AAAA,IACf;AAEA,UAAM,CAAA,EAAG,OAAO,IAAI,WAAW,OAAO,CAAC,YAAY,MAAM,CAAC;AAE1D,UAAM,YAAY,QAAQ,MAAM,MAAM,IAAI;AAC1C,UAAM,cAAc,IAAI,KAAK;AAAA,MAC3B,GAAG;AAAA,MACH,GAAI,cAAc,SAAY,EAAC,MAAM,UAAA,IAAa,CAAA;AAAA,MAClD,kBAAkB;AAAA,IAAA,CACnB;AACD,YAAQ,OAAO,WAAW;AAC1B,cAAU,MAAM,YAAY,OAAO;AACnC,WAAO;AAAA,EACT,CAAC;AAED,QAAM,OAAO,WAEX,MAAO,UAAU,QAAQ,MAAM,OAAO,WAAY;AAEpD,MAAI,WACF;AAEF,eAAa,MAAM;AACjB,UAAM,cAAc,KAAA;AACpB,QAAI,CAAC,eAAe,UAAU,OAAO;AACnC;AAAA,IACF;AAEA,UAAM,cAAc,KAAA;AAEpB,QAAI,aAAa,aAAa;AAC5B,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,gBAAgB,UAAU;AAC5B,iBAAW;AACX,WAAK,YAAY,WAAW,QAAQ;AAAA,QAClC,MAAM,gBAAgB,cAAc,SAAY;AAAA,MAAA,CACjD;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO,YAAY,SAAS;AAAA,IAC1B,OAAO;AAAA,IACP,IAAI,WAAW;AACb,aAAO,MAAM;AAAA,IACf;AAAA,EAAA,CACD;AACH;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/constraint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAG1E,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;CAC/B,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,GAAG,GACP,OAAO,CAOT;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,UAAU,GAChB,OAAO,CAOT;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,UAAU,GAClB,OAAO,CAET;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,EACrB,OAAO,EAAE,UAAU,GAClB,OAAO,CAiBT;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS,GACnB,eAAe,EAAE,CAcnB;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,OAAO,EAAE,UAAU,GAClB,UAAU,GAAG,SAAS,CA4BxB;
|
|
1
|
+
{"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/constraint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAChB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAC,GAAG,EAAE,KAAK,EAAC,MAAM,oCAAoC,CAAC;AACnE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,2CAA2C,CAAC;AAG1E,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;CAC/B,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,GAAG,GACP,OAAO,CAOT;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,UAAU,GAChB,OAAO,CAOT;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,UAAU,GAClB,OAAO,CAET;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,EACrB,OAAO,EAAE,UAAU,GAClB,OAAO,CAiBT;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS,GACnB,eAAe,EAAE,CAcnB;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,OAAO,EAAE,UAAU,GAClB,UAAU,GAAG,SAAS,CA4BxB;AAmBD,qBAAa,eAAe;;;IAY1B,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO;IAI/B,GAAG,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAM7B"}
|
|
@@ -72,7 +72,10 @@ function primaryKeyConstraintFromFilters(condition, primary) {
|
|
|
72
72
|
}
|
|
73
73
|
function extractColumn(condition) {
|
|
74
74
|
if (condition.left.type === "column") {
|
|
75
|
-
assert(
|
|
75
|
+
assert(
|
|
76
|
+
condition.right.type === "literal",
|
|
77
|
+
() => `extractColumn: expected right side to be literal, got ${condition.right.type}`
|
|
78
|
+
);
|
|
76
79
|
return { name: condition.left.name, value: condition.right.value };
|
|
77
80
|
}
|
|
78
81
|
return void 0;
|