@rocicorp/zero 1.12.0-canary.3 → 1.12.0-canary.4
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/out/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
- package/out/analyze-query/src/analyze-cli.js +4 -3
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/analyze-query/src/bin-analyze.js +5 -3
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/analyze-query/src/bin-transform.js +3 -2
- package/out/analyze-query/src/bin-transform.js.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/ast-to-zql/src/bin.js +3 -2
- package/out/ast-to-zql/src/bin.js.map +1 -1
- package/out/ast-to-zql/src/format.js.map +1 -1
- package/out/datadog/src/datadog-log-sink.js +5 -4
- package/out/datadog/src/datadog-log-sink.js.map +1 -1
- package/out/otel/src/log-options.js.map +1 -1
- package/out/replicache/src/btree/node.js +13 -11
- package/out/replicache/src/btree/node.js.map +1 -1
- package/out/replicache/src/btree/read.js +4 -2
- package/out/replicache/src/btree/read.js.map +1 -1
- package/out/replicache/src/btree/splice.js.map +1 -1
- package/out/replicache/src/btree/write.js +9 -5
- package/out/replicache/src/btree/write.js.map +1 -1
- package/out/replicache/src/config.js +1 -2
- package/out/replicache/src/connection-loop.js.map +1 -1
- package/out/replicache/src/dag/chunk.js +1 -1
- package/out/replicache/src/dag/gc.js.map +1 -1
- package/out/replicache/src/dag/lazy-store.js +8 -7
- package/out/replicache/src/dag/lazy-store.js.map +1 -1
- package/out/replicache/src/dag/store-impl.js +1 -1
- package/out/replicache/src/dag/store-impl.js.map +1 -1
- package/out/replicache/src/dag/visitor.js.map +1 -1
- package/out/replicache/src/db/commit.js +5 -3
- package/out/replicache/src/db/commit.js.map +1 -1
- package/out/replicache/src/db/read.js +1 -1
- package/out/replicache/src/db/read.js.map +1 -1
- package/out/replicache/src/db/rebase.js.map +1 -1
- package/out/replicache/src/db/write.js +5 -2
- package/out/replicache/src/db/write.js.map +1 -1
- package/out/replicache/src/deleted-clients.js +3 -2
- package/out/replicache/src/deleted-clients.js.map +1 -1
- package/out/replicache/src/expo-sqlite.js +1 -2
- package/out/replicache/src/frozen-json.js +1 -1
- package/out/replicache/src/frozen-json.js.map +1 -1
- package/out/replicache/src/get-default-puller.js +1 -1
- package/out/replicache/src/hash.js +1 -1
- package/out/replicache/src/hash.js.map +1 -1
- package/out/replicache/src/impl.js +1 -2
- package/out/replicache/src/index-defs.js +5 -3
- package/out/replicache/src/index-defs.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/idb-store.js +1 -1
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-fallback-store.js +1 -1
- package/out/replicache/src/kv/mem-fallback-store.js.map +1 -1
- package/out/replicache/src/kv/mem-store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/types.js.map +1 -1
- package/out/replicache/src/kv/read-impl.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +1 -1
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/write-impl-base.js +4 -1
- package/out/replicache/src/kv/write-impl-base.js.map +1 -1
- package/out/replicache/src/kv/write-impl.js.map +1 -1
- package/out/replicache/src/log-options.js +2 -1
- package/out/replicache/src/log-options.js.map +1 -1
- package/out/replicache/src/make-idb-name.js +1 -1
- package/out/replicache/src/new-client-channel.js +9 -7
- package/out/replicache/src/new-client-channel.js.map +1 -1
- package/out/replicache/src/on-persist-channel.js +1 -1
- package/out/replicache/src/on-persist-channel.js.map +1 -1
- package/out/replicache/src/op-sqlite.js +1 -2
- package/out/replicache/src/pending-mutations.js +2 -1
- package/out/replicache/src/pending-mutations.js.map +1 -1
- package/out/replicache/src/persist/client-gc.js +2 -2
- package/out/replicache/src/persist/client-gc.js.map +1 -1
- package/out/replicache/src/persist/client-group-gc.js +2 -2
- package/out/replicache/src/persist/client-group-gc.js.map +1 -1
- package/out/replicache/src/persist/client-groups.js +1 -1
- package/out/replicache/src/persist/client-groups.js.map +1 -1
- package/out/replicache/src/persist/clients.js +1 -1
- package/out/replicache/src/persist/clients.js.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +5 -4
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
- package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
- package/out/replicache/src/persist/heartbeat.js +2 -2
- package/out/replicache/src/persist/heartbeat.js.map +1 -1
- package/out/replicache/src/persist/idb-databases-store.js +1 -1
- package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
- package/out/replicache/src/persist/make-client-id.js +1 -1
- package/out/replicache/src/persist/make-client-id.js.map +1 -1
- package/out/replicache/src/persist/persist.js +3 -2
- package/out/replicache/src/persist/persist.js.map +1 -1
- package/out/replicache/src/persist/refresh.js +8 -5
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/replicache-impl.js +3 -3
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/scan-iterator.js.map +1 -1
- package/out/replicache/src/scan-options.js +7 -6
- package/out/replicache/src/scan-options.js.map +1 -1
- package/out/replicache/src/sqlite.js +1 -2
- package/out/replicache/src/subscriptions.js +1 -1
- package/out/replicache/src/subscriptions.js.map +1 -1
- package/out/replicache/src/sync/diff.js +3 -1
- package/out/replicache/src/sync/diff.js.map +1 -1
- package/out/replicache/src/sync/ids.js.map +1 -1
- package/out/replicache/src/sync/patch.js +2 -4
- package/out/replicache/src/sync/patch.js.map +1 -1
- package/out/replicache/src/sync/pull.js +3 -1
- package/out/replicache/src/sync/pull.js.map +1 -1
- package/out/replicache/src/sync/push.js.map +1 -1
- package/out/replicache/src/sync/request-id.js +1 -1
- package/out/replicache/src/sync/request-id.js.map +1 -1
- package/out/replicache/src/transactions.js +1 -1
- package/out/replicache/src/transactions.js.map +1 -1
- package/out/shared/src/arrays.js +4 -1
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/asserts.js +1 -1
- package/out/shared/src/bigint-json.d.ts +9 -0
- package/out/shared/src/bigint-json.d.ts.map +1 -1
- package/out/shared/src/bigint-json.js +27 -2
- package/out/shared/src/bigint-json.js.map +1 -1
- package/out/shared/src/broadcast-channel.js +1 -1
- package/out/shared/src/btree-set.js +11 -8
- package/out/shared/src/btree-set.js.map +1 -1
- package/out/shared/src/cache.js.map +1 -1
- package/out/shared/src/config.js +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/custom-key-set.js.map +1 -1
- package/out/shared/src/deep-clone.js +1 -1
- package/out/shared/src/document-visible.js.map +1 -1
- package/out/shared/src/dotenv.js.map +1 -1
- package/out/shared/src/error.js +1 -1
- package/out/shared/src/error.js.map +1 -1
- package/out/shared/src/hash.js +2 -2
- package/out/shared/src/hash.js.map +1 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/json-schema.js.map +1 -1
- package/out/shared/src/json.js.map +1 -1
- package/out/shared/src/logging-test-utils.js +1 -1
- package/out/shared/src/logging.js +1 -1
- package/out/shared/src/logging.js.map +1 -1
- package/out/shared/src/navigator.js +1 -1
- package/out/shared/src/options.js +9 -12
- package/out/shared/src/options.js.map +1 -1
- package/out/shared/src/promise-race.js.map +1 -1
- package/out/shared/src/queue.js.map +1 -1
- package/out/shared/src/record-proxy.js.map +1 -1
- package/out/shared/src/ring-buffer.js.map +1 -1
- package/out/shared/src/size-of-value.js +7 -10
- package/out/shared/src/size-of-value.js.map +1 -1
- package/out/shared/src/sorted-entries.js.map +1 -1
- package/out/shared/src/tdigest-schema.js.map +1 -1
- package/out/shared/src/tdigest.js.map +1 -1
- package/out/shared/src/valita.js +1 -1
- package/out/shared/src/valita.js.map +1 -1
- package/out/z2s/src/compiler.js +2 -4
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.js +1 -1
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +212 -189
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/adapters/drizzle.js +1 -2
- package/out/zero/src/adapters/kysely.js +1 -2
- package/out/zero/src/adapters/pg.js +1 -2
- package/out/zero/src/adapters/postgresjs.js +1 -2
- package/out/zero/src/adapters/prisma.js +1 -2
- package/out/zero/src/analyze.js +1 -2
- package/out/zero/src/change-protocol/v0.js +1 -2
- package/out/zero/src/expo-sqlite.js +1 -2
- package/out/zero/src/op-sqlite.js +1 -2
- package/out/zero/src/react-native.js.map +1 -1
- package/out/zero/src/sqlite.js +1 -2
- package/out/zero/src/zero-cache-dev.js +10 -9
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero/src/zero-out.js +2 -1
- package/out/zero/src/zero-out.js.map +1 -1
- package/out/zero-cache/src/auth/auth.js +1 -1
- package/out/zero-cache/src/auth/auth.js.map +1 -1
- package/out/zero-cache/src/auth/jwt.js +4 -1
- package/out/zero-cache/src/auth/jwt.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js +3 -2
- package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +5 -16
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/network.js +1 -1
- package/out/zero-cache/src/config/network.js.map +1 -1
- package/out/zero-cache/src/config/server-context.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +5 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +13 -2
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +1 -1
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/db/create.js.map +1 -1
- package/out/zero-cache/src/db/index-predicate.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.d.ts +2 -2
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +1 -1
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.js +5 -3
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy-binary.js +4 -3
- package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy.js +0 -1
- package/out/zero-cache/src/db/pg-copy.js.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
- package/out/zero-cache/src/db/run-transaction.js.map +1 -1
- package/out/zero-cache/src/db/specs.js +7 -5
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
- package/out/zero-cache/src/db/statements.d.ts.map +1 -1
- package/out/zero-cache/src/db/statements.js +9 -2
- package/out/zero-cache/src/db/statements.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +5 -3
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/db/warmup.js.map +1 -1
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/observability/log-throttle.js.map +1 -1
- package/out/zero-cache/src/observability/metrics.js.map +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js +4 -2
- package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
- package/out/zero-cache/src/scripts/permissions.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/logging.js +1 -1
- package/out/zero-cache/src/server/logging.js.map +1 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
- package/out/zero-cache/src/server/otel-start.js.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -2
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +2 -1
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/runner/runtime.js +2 -1
- package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
- package/out/zero-cache/src/server/slot-keeper.js.map +1 -1
- package/out/zero-cache/src/server/syncer-assigner.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +6 -1
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.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/common/backfill-manager.js +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +3 -3
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +3 -3
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +3 -3
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +4 -6
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +5 -3
- 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/binary-reader.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +3 -2
- 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/lsn.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js +3 -3
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -1
- 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/index-predicate.js +13 -12
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
- 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.js +1 -1
- 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/replica-stage-enum.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +9 -6
- 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.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
- 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.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/mod.js +1 -2
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.js +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js +2 -3
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +2 -2
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +5 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +21 -21
- 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.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/drain-tracker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.js +11 -10
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +3 -3
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/replica-poller.js +1 -1
- package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.js +12 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +2 -2
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +4 -6
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +1 -3
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +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 +2 -2
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +2 -2
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js +0 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
- package/out/zero-cache/src/services/heapz.js +2 -1
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +1 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +4 -2
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +1 -1
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +2 -2
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
- package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
- package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +3 -2
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.js +4 -3
- package/out/zero-cache/src/services/plannerz.js.map +1 -1
- package/out/zero-cache/src/services/profz.js +5 -3
- package/out/zero-cache/src/services/profz.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-db.js +3 -2
- package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +1 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +4 -3
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.js +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.js +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +19 -7
- 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 +31 -15
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +10 -7
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/runner.js.map +1 -1
- package/out/zero-cache/src/services/running-state.js.map +1 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
- package/out/zero-cache/src/services/statz.js +2 -1
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
- 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 +24 -3
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +15 -2
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.js +46 -6
- package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js +2 -2
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +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 +10 -5
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +12 -4
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +2 -2
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +5 -3
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- 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 +8 -5
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.js +1 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +7 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +8 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +6 -5
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
- 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 +13 -9
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/error-with-level.js.map +1 -1
- package/out/zero-cache/src/types/lexi-version.js.map +1 -1
- package/out/zero-cache/src/types/lite.js +1 -1
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/pg-data-type.js +1 -1
- package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
- package/out/zero-cache/src/types/pg.js +6 -4
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.js +2 -2
- package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
- package/out/zero-cache/src/types/processes.js +1 -1
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/profiler.js.map +1 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/streams.js +10 -9
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/types/strings.js.map +1 -1
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/types/timeout.js +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js +1 -1
- package/out/zero-cache/src/types/ws.js +1 -1
- package/out/zero-cache/src/workers/connection.js +5 -6
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/mutator.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +5 -4
- 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 +9 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +4 -4
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/active-clients-manager.js +1 -1
- package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/bindings.js +11 -11
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.js +1 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +1 -1
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/crud.js +1 -1
- package/out/zero-client/src/client/crud.js.map +1 -1
- package/out/zero-client/src/client/custom.js +1 -1
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/enable-analytics.js +1 -1
- package/out/zero-client/src/client/enable-analytics.js.map +1 -1
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
- package/out/zero-client/src/client/inspector/client.js.map +1 -1
- package/out/zero-client/src/client/inspector/html-dialog-prompt.js +1 -1
- package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/query.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +1 -3
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/keys.js +2 -1
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/log-options.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +5 -3
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/metrics.js +3 -5
- package/out/zero-client/src/client/metrics.js.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.js +2 -2
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/reload-error-handler.js +4 -3
- package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.js +19 -11
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.js +23 -23
- package/out/zero-client/src/util/nanoid.js.map +1 -1
- package/out/zero-permissions/src/permissions.js +3 -2
- package/out/zero-permissions/src/permissions.js.map +1 -1
- package/out/zero-pg/src/mod.js +9 -9
- package/out/zero-protocol/src/analyze-query-result.js +1 -1
- package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
- package/out/zero-protocol/src/application-error.js.map +1 -1
- package/out/zero-protocol/src/ast.js +19 -9
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
- package/out/zero-protocol/src/client-schema.js +1 -1
- package/out/zero-protocol/src/client-schema.js.map +1 -1
- package/out/zero-protocol/src/close-connection.js +1 -1
- package/out/zero-protocol/src/close-connection.js.map +1 -1
- package/out/zero-protocol/src/connect.js +1 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/custom-queries.js +1 -1
- package/out/zero-protocol/src/custom-queries.js.map +1 -1
- package/out/zero-protocol/src/data.js +4 -2
- package/out/zero-protocol/src/data.js.map +1 -1
- package/out/zero-protocol/src/delete-clients.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +27 -27
- package/out/zero-protocol/src/down.js.map +1 -1
- package/out/zero-protocol/src/error.js.map +1 -1
- package/out/zero-protocol/src/inspect-down.d.ts +81 -81
- package/out/zero-protocol/src/inspect-down.js +1 -1
- package/out/zero-protocol/src/inspect-down.js.map +1 -1
- package/out/zero-protocol/src/inspect-up.js +1 -1
- package/out/zero-protocol/src/inspect-up.js.map +1 -1
- package/out/zero-protocol/src/mutate-server.js +1 -1
- package/out/zero-protocol/src/mutate-server.js.map +1 -1
- package/out/zero-protocol/src/mutation-id.js.map +1 -1
- package/out/zero-protocol/src/mutation.js +1 -1
- package/out/zero-protocol/src/mutation.js.map +1 -1
- package/out/zero-protocol/src/mutations-patch.js +1 -1
- package/out/zero-protocol/src/mutations-patch.js.map +1 -1
- package/out/zero-protocol/src/ping.js +1 -1
- package/out/zero-protocol/src/ping.js.map +1 -1
- package/out/zero-protocol/src/poke.d.ts +6 -6
- package/out/zero-protocol/src/poke.js +1 -1
- package/out/zero-protocol/src/poke.js.map +1 -1
- package/out/zero-protocol/src/pong.js +1 -1
- package/out/zero-protocol/src/pong.js.map +1 -1
- package/out/zero-protocol/src/primary-key.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -0
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/pull.js +1 -1
- package/out/zero-protocol/src/pull.js.map +1 -1
- package/out/zero-protocol/src/push.js +1 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/queries-patch.js +1 -1
- package/out/zero-protocol/src/queries-patch.js.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
- package/out/zero-protocol/src/query-hash.js +2 -2
- package/out/zero-protocol/src/query-server.js +1 -1
- package/out/zero-protocol/src/query-server.js.map +1 -1
- package/out/zero-protocol/src/row-patch.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +60 -60
- package/out/zero-protocol/src/up.js.map +1 -1
- package/out/zero-protocol/src/update-auth.js.map +1 -1
- package/out/zero-protocol/src/version.js.map +1 -1
- package/out/zero-react/src/bindings.js +11 -11
- package/out/zero-react/src/mod.js +5 -5
- package/out/zero-react/src/use-query.js +1 -1
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/zero-provider.d.ts +1 -1
- package/out/zero-react/src/zero-provider.d.ts.map +1 -1
- package/out/zero-react/src/zero-provider.js +2 -1
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-react/src/zero.js +23 -23
- package/out/zero-schema/src/builder/schema-builder.js +3 -2
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
- package/out/zero-schema/src/builder/table-builder.js +1 -1
- package/out/zero-schema/src/builder/table-builder.js.map +1 -1
- package/out/zero-schema/src/compiled-permissions.js.map +1 -1
- package/out/zero-schema/src/name-mapper.js +7 -5
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-schema/src/schema-config.js +1 -1
- package/out/zero-schema/src/schema-config.js.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/kysely.js.map +1 -1
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.js.map +1 -1
- package/out/zero-server/src/closable-db-transaction.js.map +1 -1
- package/out/zero-server/src/custom.js +1 -1
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.js +8 -8
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/queries/process-queries.js +2 -1
- package/out/zero-server/src/queries/process-queries.js.map +1 -1
- package/out/zero-server/src/schema.js +7 -7
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/bindings.js +11 -11
- package/out/zero-solid/src/mod.js +5 -5
- package/out/zero-solid/src/solid-view.js +1 -1
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-connection-state.js +2 -1
- package/out/zero-solid/src/use-connection-state.js.map +1 -1
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero-online.js +2 -1
- package/out/zero-solid/src/use-zero-online.js.map +1 -1
- package/out/zero-solid/src/use-zero.js +3 -2
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zero-solid/src/zero.js +23 -23
- package/out/zero-types/src/name-mapper.js.map +1 -1
- package/out/zql/src/builder/builder.js +15 -13
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -1
- package/out/zql/src/builder/debug-delegate.js.map +1 -1
- package/out/zql/src/builder/like.js +0 -1
- package/out/zql/src/builder/like.js.map +1 -1
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.js.map +1 -1
- package/out/zql/src/ivm/constraint.js +1 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.js.map +1 -1
- package/out/zql/src/ivm/exists.js +20 -18
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +1 -1
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter-push.js.map +1 -1
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +1 -3
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join-index-tap.js.map +1 -1
- package/out/zql/src/ivm/join-index.js.map +1 -1
- package/out/zql/src/ivm/join-utils.js +11 -13
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.js +26 -22
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/memory-storage.js.map +1 -1
- package/out/zql/src/ivm/operator.js +2 -2
- package/out/zql/src/ivm/push-accumulated.js +0 -1
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/skip-yields.js.map +1 -1
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/take-gate.js.map +1 -1
- package/out/zql/src/ivm/take.js +1 -1
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +1 -1
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +1 -1
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/mutate/crud.js +3 -2
- package/out/zql/src/mutate/crud.js.map +1 -1
- package/out/zql/src/planner/planner-builder.js +1 -1
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/planner/planner-fan-in.js.map +1 -1
- package/out/zql/src/planner/planner-fan-out.js.map +1 -1
- package/out/zql/src/planner/planner-filter.js.map +1 -1
- package/out/zql/src/planner/planner-graph.js +1 -5
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/planner/planner-join.js +1 -1
- package/out/zql/src/planner/planner-join.js.map +1 -1
- package/out/zql/src/planner/planner-source.js.map +1 -1
- package/out/zql/src/planner/planner-terminus.js.map +1 -1
- package/out/zql/src/query/create-builder.js +2 -1
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/expression.js +1 -1
- package/out/zql/src/query/expression.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/named.js +2 -1
- package/out/zql/src/query/named.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +1 -1
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-impl.js +3 -2
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-registry.js +1 -1
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zql/src/query/query-transitions.js +1 -1
- package/out/zql/src/query/query-transitions.js.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +3 -2
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/static-query.js.map +1 -1
- package/out/zql/src/query/ttl.js +8 -8
- package/out/zql/src/query/ttl.js.map +1 -1
- package/out/zql/src/query/validate-input.js.map +1 -1
- package/out/zqlite/src/database-storage.d.ts +27 -8
- package/out/zqlite/src/database-storage.d.ts.map +1 -1
- package/out/zqlite/src/database-storage.js +190 -53
- package/out/zqlite/src/database-storage.js.map +1 -1
- package/out/zqlite/src/db.d.ts +47 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +121 -21
- package/out/zqlite/src/db.js.map +1 -1
- package/out/zqlite/src/explain-queries.js.map +1 -1
- package/out/zqlite/src/fetch-sql.js.map +1 -1
- package/out/zqlite/src/index-usage.js.map +1 -1
- package/out/zqlite/src/internal/sql-inline.js.map +1 -1
- package/out/zqlite/src/internal/sql.js.map +1 -1
- package/out/zqlite/src/internal/statement-cache.d.ts +7 -0
- package/out/zqlite/src/internal/statement-cache.d.ts.map +1 -1
- package/out/zqlite/src/internal/statement-cache.js +11 -4
- package/out/zqlite/src/internal/statement-cache.js.map +1 -1
- package/out/zqlite/src/mod.js +5 -5
- package/out/zqlite/src/pending-delta.js.map +1 -1
- package/out/zqlite/src/query-builder.js +1 -1
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/query-delegate.js.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.js +2 -5
- package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +3 -2
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +11 -0
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +62 -25
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +17 -15
- package/out/otel/src/maybe-time.d.ts +0 -3
- package/out/otel/src/maybe-time.d.ts.map +0 -1
- package/out/otel/src/maybe-time.js +0 -15
- package/out/otel/src/maybe-time.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database-storage.js","names":["#stmts","#options","#db","#checkpoint","#maybeCheckpoint","#numWrites","#scan","#get","#set","#del","#destroy"],"sources":["../../../../zqlite/src/database-storage.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {JSONValue} from '../../shared/src/json.ts';\nimport type {Storage} from '../../zql/src/ivm/operator.ts';\nimport type {Stream} from '../../zql/src/ivm/stream.ts';\nimport type {Statement} from './db.ts';\nimport {Database} from './db.ts';\n\nexport interface ClientGroupStorage {\n /** Creates a {@link Storage} instance for a single operator. */\n createStorage(): Storage;\n\n /** Deletes all storage for the client group. */\n destroy(): void;\n}\n\ntype Statements = {\n get: Statement;\n set: Statement;\n del: Statement;\n scan: Statement;\n clear: Statement;\n clearOp: Statement;\n commit: Statement;\n begin: Statement;\n};\n\n// Exported for testing.\nexport const CREATE_STORAGE_TABLE = `\n CREATE TABLE storage (\n clientGroupID TEXT,\n op NUMBER,\n key TEXT,\n val TEXT,\n PRIMARY KEY(clientGroupID, op, key)\n )\n `;\n\n/**\n * The most values each operator's storage keeps in memory. The storage is in\n * SQLite so that operator state can spill to disk, so only a few values per\n * operator are kept: profiles of the view-syncer gain as much from 64 as from\n * 1,024.\n */\nconst MAX_CACHED_ENTRIES_PER_OP = 64;\n\nconst defaultOptions = {\n commitInterval: 5_000,\n compactionThresholdBytes: 50 * 1024 * 1024,\n};\n\nexport class DatabaseStorage {\n static create(\n lc: LogContext,\n path: string,\n options = defaultOptions,\n ): DatabaseStorage {\n // SQLite is used for ephemeral storage (i.e. similar to RAM) that can spill to\n // disk to avoid consuming too much memory. Each worker thread gets its own\n // database (file) and acts as the single reader/writer of the DB, so\n // `locking_mode` is set to `EXCLUSIVE` for performance. Similarly, since\n // durability is not important, `synchronous` is set to `OFF` for performance.\n const db = new Database(lc, path);\n db.unsafeMode(true); // Allows journal_mode = OFF\n db.pragma('locking_mode = EXCLUSIVE');\n db.pragma('foreign_keys = OFF');\n db.pragma('journal_mode = OFF');\n db.pragma('synchronous = OFF');\n db.pragma('auto_vacuum = INCREMENTAL');\n\n db.prepare(CREATE_STORAGE_TABLE).run();\n lc.debug?.(`Created DatabaseStorage backed by ${path}`);\n return new DatabaseStorage(db, options);\n }\n\n readonly #stmts: Statements;\n readonly #options: typeof defaultOptions;\n readonly #db: Database;\n #numWrites = 0;\n\n constructor(db: Database, options = defaultOptions) {\n this.#stmts = {\n get: db.prepare(`\n SELECT val FROM storage WHERE\n clientGroupID = ? AND op = ? AND key = ?\n `),\n set: db.prepare(`\n INSERT INTO storage (clientGroupID, op, key, val)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(clientGroupID, op, key) \n DO \n UPDATE SET val = excluded.val\n `),\n del: db.prepare(`\n DELETE FROM storage WHERE\n clientGroupID = ? AND op = ? AND key = ?\n `),\n scan: db.prepare(`\n SELECT key, val FROM storage WHERE\n clientGroupID = ? AND op = ? AND key >= ?\n `),\n clear: db.prepare(`\n DELETE FROM storage WHERE clientGroupID = ?\n `),\n clearOp: db.prepare(`\n DELETE FROM storage WHERE clientGroupID = ? AND op = ?\n `),\n commit: db.prepare('COMMIT'),\n begin: db.prepare('BEGIN'),\n };\n this.#stmts.begin.run();\n this.#options = options;\n this.#db = db;\n }\n\n close() {\n this.#checkpoint();\n this.#db.close();\n }\n\n #get(cgID: string, opID: number, key: string): JSONValue | undefined {\n this.#maybeCheckpoint();\n const row = this.#stmts.get.get<{val: string}>(cgID, opID, key);\n return row ? JSON.parse(row.val) : undefined;\n }\n\n #set(cgID: string, opID: number, key: string, val: JSONValue) {\n this.#maybeCheckpoint();\n this.#stmts.set.run(cgID, opID, key, JSON.stringify(val));\n }\n\n #del(cgID: string, opID: number, key: string) {\n this.#maybeCheckpoint();\n this.#stmts.del.run(cgID, opID, key);\n }\n\n #destroy(cgID: string, opID: number) {\n this.#maybeCheckpoint();\n this.#stmts.clearOp.run(cgID, opID);\n }\n\n /**\n * We don't need to commit every single write to the DB\n * since we're not concerned with durability.\n * Waiting on commits can be expensive, so we commit\n * every `COMMIT_INTERVAL` writes.\n */\n #maybeCheckpoint() {\n if (++this.#numWrites >= this.#options.commitInterval) {\n this.#checkpoint();\n }\n }\n\n #checkpoint() {\n this.#stmts.commit.run();\n this.#stmts.begin.run();\n this.#numWrites = 0;\n }\n\n *#scan(\n cgID: string,\n opID: number,\n opts: {prefix: string} = {prefix: ''},\n ): Stream<[string, JSONValue]> {\n const {prefix} = opts;\n for (const {key, val} of this.#stmts.scan.iterate<{\n key: string;\n val: string;\n }>(cgID, opID, prefix)) {\n if (!key.startsWith(prefix)) {\n return;\n }\n yield [key, JSON.parse(val)];\n }\n }\n\n createClientGroupStorage(cgID: string): ClientGroupStorage {\n // The caches of the group's live operator storages.\n const caches = new Set<Map<string, JSONValue | undefined>>();\n const destroy = () => {\n this.#stmts.clear.run(cgID);\n for (const cache of caches) {\n cache.clear();\n }\n this.#checkpoint();\n this.#db.compact(this.#options.compactionThresholdBytes);\n };\n this.#stmts.clear.run(cgID);\n\n let nextOpID = 1;\n return {\n createStorage: () => {\n const opID = nextOpID++;\n // The operator's most recently read and written values, `undefined`\n // for a key known to be absent. Operators read the same key again and\n // again (Cap and Take read their state on every fetch and push), so\n // this saves most of the SQLite reads. Like MemoryStorage, `get`\n // returns the stored value itself, which operators do not mutate.\n const cache = new Map<string, JSONValue | undefined>();\n caches.add(cache);\n const cacheSet = (key: string, val: JSONValue | undefined) => {\n if (cache.size >= MAX_CACHED_ENTRIES_PER_OP && !cache.has(key)) {\n cache.clear();\n }\n cache.set(key, val);\n };\n return {\n get: (key, def?) => {\n let val = cache.get(key);\n if (val === undefined && !cache.has(key)) {\n val = this.#get(cgID, opID, key);\n cacheSet(key, val);\n }\n return val === undefined ? def : val;\n },\n // The cache is updated only once the database is, so a failed write\n // leaves it consistent with the database.\n set: (key, val) => {\n this.#set(cgID, opID, key, val);\n cacheSet(key, val);\n },\n del: key => {\n this.#del(cgID, opID, key);\n cacheSet(key, undefined);\n },\n scan: opts => this.#scan(cgID, opID, opts),\n destroy: () => {\n this.#destroy(cgID, opID);\n cache.clear();\n caches.delete(cache);\n },\n };\n },\n\n destroy,\n };\n }\n}\n"],"mappings":";;AA2BA,IAAa,uBAAuB;;;;;;;;;;;;;;;AAgBpC,IAAM,4BAA4B;AAElC,IAAM,iBAAiB;CACrB,gBAAgB;CAChB,0BAA0B,KAAK,OAAO;AACxC;AAEA,IAAa,kBAAb,MAAa,gBAAgB;CAC3B,OAAO,OACL,IACA,MACA,UAAU,gBACO;EAMjB,MAAM,KAAK,IAAI,SAAS,IAAI,IAAI;EAChC,GAAG,WAAW,IAAI;EAClB,GAAG,OAAO,0BAA0B;EACpC,GAAG,OAAO,oBAAoB;EAC9B,GAAG,OAAO,oBAAoB;EAC9B,GAAG,OAAO,mBAAmB;EAC7B,GAAG,OAAO,2BAA2B;EAErC,GAAG,QAAQ,oBAAoB,EAAE,IAAI;EACrC,GAAG,QAAQ,qCAAqC,MAAM;EACtD,OAAO,IAAI,gBAAgB,IAAI,OAAO;CACxC;CAEA;CACA;CACA;CACA,aAAa;CAEb,YAAY,IAAc,UAAU,gBAAgB;EAClD,KAAKA,SAAS;GACZ,KAAK,GAAG,QAAQ;;;OAGf;GACD,KAAK,GAAG,QAAQ;;;;;;OAMf;GACD,KAAK,GAAG,QAAQ;;;OAGf;GACD,MAAM,GAAG,QAAQ;;;OAGhB;GACD,OAAO,GAAG,QAAQ;;OAEjB;GACD,SAAS,GAAG,QAAQ;;OAEnB;GACD,QAAQ,GAAG,QAAQ,QAAQ;GAC3B,OAAO,GAAG,QAAQ,OAAO;EAC3B;EACA,KAAKA,OAAO,MAAM,IAAI;EACtB,KAAKC,WAAW;EAChB,KAAKC,MAAM;CACb;CAEA,QAAQ;EACN,KAAKC,YAAY;EACjB,KAAKD,IAAI,MAAM;CACjB;CAEA,KAAK,MAAc,MAAc,KAAoC;EACnE,KAAKE,iBAAiB;EACtB,MAAM,MAAM,KAAKJ,OAAO,IAAI,IAAmB,MAAM,MAAM,GAAG;EAC9D,OAAO,MAAM,KAAK,MAAM,IAAI,GAAG,IAAI,KAAA;CACrC;CAEA,KAAK,MAAc,MAAc,KAAa,KAAgB;EAC5D,KAAKI,iBAAiB;EACtB,KAAKJ,OAAO,IAAI,IAAI,MAAM,MAAM,KAAK,KAAK,UAAU,GAAG,CAAC;CAC1D;CAEA,KAAK,MAAc,MAAc,KAAa;EAC5C,KAAKI,iBAAiB;EACtB,KAAKJ,OAAO,IAAI,IAAI,MAAM,MAAM,GAAG;CACrC;CAEA,SAAS,MAAc,MAAc;EACnC,KAAKI,iBAAiB;EACtB,KAAKJ,OAAO,QAAQ,IAAI,MAAM,IAAI;CACpC;;;;;;;CAQA,mBAAmB;EACjB,IAAI,EAAE,KAAKK,cAAc,KAAKJ,SAAS,gBACrC,KAAKE,YAAY;CAErB;CAEA,cAAc;EACZ,KAAKH,OAAO,OAAO,IAAI;EACvB,KAAKA,OAAO,MAAM,IAAI;EACtB,KAAKK,aAAa;CACpB;CAEA,CAACC,MACC,MACA,MACA,OAAyB,EAAC,QAAQ,GAAE,GACP;EAC7B,MAAM,EAAC,WAAU;EACjB,KAAK,MAAM,EAAC,KAAK,SAAQ,KAAKN,OAAO,KAAK,QAGvC,MAAM,MAAM,MAAM,GAAG;GACtB,IAAI,CAAC,IAAI,WAAW,MAAM,GACxB;GAEF,MAAM,CAAC,KAAK,KAAK,MAAM,GAAG,CAAC;EAC7B;CACF;CAEA,yBAAyB,MAAkC;EAEzD,MAAM,yBAAS,IAAI,IAAwC;EAC3D,MAAM,gBAAgB;GACpB,KAAKA,OAAO,MAAM,IAAI,IAAI;GAC1B,KAAK,MAAM,SAAS,QAClB,MAAM,MAAM;GAEd,KAAKG,YAAY;GACjB,KAAKD,IAAI,QAAQ,KAAKD,SAAS,wBAAwB;EACzD;EACA,KAAKD,OAAO,MAAM,IAAI,IAAI;EAE1B,IAAI,WAAW;EACf,OAAO;GACL,qBAAqB;IACnB,MAAM,OAAO;IAMb,MAAM,wBAAQ,IAAI,IAAmC;IACrD,OAAO,IAAI,KAAK;IAChB,MAAM,YAAY,KAAa,QAA+B;KAC5D,IAAI,MAAM,QAAQ,6BAA6B,CAAC,MAAM,IAAI,GAAG,GAC3D,MAAM,MAAM;KAEd,MAAM,IAAI,KAAK,GAAG;IACpB;IACA,OAAO;KACL,MAAM,KAAK,QAAS;MAClB,IAAI,MAAM,MAAM,IAAI,GAAG;MACvB,IAAI,QAAQ,KAAA,KAAa,CAAC,MAAM,IAAI,GAAG,GAAG;OACxC,MAAM,KAAKO,KAAK,MAAM,MAAM,GAAG;OAC/B,SAAS,KAAK,GAAG;MACnB;MACA,OAAO,QAAQ,KAAA,IAAY,MAAM;KACnC;KAGA,MAAM,KAAK,QAAQ;MACjB,KAAKC,KAAK,MAAM,MAAM,KAAK,GAAG;MAC9B,SAAS,KAAK,GAAG;KACnB;KACA,MAAK,QAAO;MACV,KAAKC,KAAK,MAAM,MAAM,GAAG;MACzB,SAAS,KAAK,KAAA,CAAS;KACzB;KACA,OAAM,SAAQ,KAAKH,MAAM,MAAM,MAAM,IAAI;KACzC,eAAe;MACb,KAAKI,SAAS,MAAM,IAAI;MACxB,MAAM,MAAM;MACZ,OAAO,OAAO,KAAK;KACrB;IACF;GACF;GAEA;EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"database-storage.js","names":[],"sources":["../../../../zqlite/src/database-storage.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {JSONValue} from '../../shared/src/json.ts';\nimport {getSizeOfEntry} from '../../shared/src/size-of-value.ts';\nimport {compareValues} from '../../zql/src/ivm/data.ts';\nimport type {Storage} from '../../zql/src/ivm/operator.ts';\nimport type {Stream} from '../../zql/src/ivm/stream.ts';\nimport type {Statement} from './db.ts';\nimport {Database} from './db.ts';\n\nexport interface ClientGroupStorage {\n /** Creates a {@link Storage} instance for a single operator. */\n createStorage(): Storage;\n\n /** Deletes all storage for the client group. */\n destroy(): void;\n}\n\ntype Statements = {\n get: Statement;\n set: Statement;\n del: Statement;\n scan: Statement;\n clear: Statement;\n clearOp: Statement;\n commit: Statement;\n begin: Statement;\n};\n\n// Exported for testing.\nexport const CREATE_STORAGE_TABLE = `\n CREATE TABLE storage (\n clientGroupID TEXT,\n op NUMBER,\n key TEXT,\n val TEXT,\n PRIMARY KEY(clientGroupID, op, key)\n )\n `;\n\n/**\n * The most values the storage of a spilled operator keeps in memory. Profiles\n * of the view-syncer gain as much from 64 as from 1,024.\n */\nconst MAX_CACHED_ENTRIES_PER_OP = 64;\n\n/**\n * When the operators' values go over `maxMemoryBytes`, operators are spilled\n * until they are back under this proportion of it, so that spilling, which\n * sorts the operators by last use, happens in batches.\n */\nconst SPILL_TARGET_PROPORTION = 0.9;\n\n/**\n * The heap bytes that operator state takes per byte of {@link getSizeOfEntry}.\n * Measured with `heapUsed` on view-syncer operator state, mostly Cap's\n * `{size, pks}` and Take's `{size, bound}`.\n */\nconst HEAP_BYTES_PER_SIZE = 2.6;\n\nexport type DatabaseStorageOptions = {\n commitInterval?: number | undefined;\n compactionThresholdBytes?: number | undefined;\n /**\n * The most heap bytes, as estimated from {@link getSizeOfEntry}, that the\n * operators of all client groups keep in memory before the least recently\n * used ones spill to SQLite. 0, the default, keeps every operator's values\n * in SQLite.\n */\n maxMemoryBytes?: number | undefined;\n};\n\nconst defaultOptions = {\n commitInterval: 5_000,\n compactionThresholdBytes: 50 * 1024 * 1024,\n maxMemoryBytes: 0,\n};\n\n/**\n * The storage of one operator. Its values live in `values` until the\n * operator is spilled, and in SQLite afterwards, with the most recently used\n * of them in `cache`.\n */\nclass OpStorage {\n readonly cgID: string;\n readonly opID: number;\n /** `undefined` once spilled. */\n values: Map<string, JSONValue> | undefined;\n /** The {@link getSizeOfEntry} of `values`. */\n size = 0;\n lastUsed = 0;\n /**\n * Once spilled, the operator's most recently read and written values,\n * `undefined` for a key known to be absent. Operators read the same key\n * again and again (Cap and Take read their state on every fetch and push),\n * so this saves most of the SQLite reads.\n */\n readonly cache = new Map<string, JSONValue | undefined>();\n\n constructor(cgID: string, opID: number, inMemory: boolean) {\n this.cgID = cgID;\n this.opID = opID;\n this.values = inMemory ? new Map() : undefined;\n }\n\n cacheSet(key: string, val: JSONValue | undefined) {\n const {cache} = this;\n if (cache.size >= MAX_CACHED_ENTRIES_PER_OP && !cache.has(key)) {\n cache.clear();\n }\n cache.set(key, val);\n }\n}\n\n/**\n * Operator storage for the client groups of a sync worker.\n *\n * Each operator keeps its values in a `Map`, so reading a key that was never\n * written does not ask SQLite. When the values of all of the operators go\n * over `maxMemoryBytes`, the least recently used operators spill: their\n * values are written to SQLite, where they stay until the operator is\n * destroyed.\n *\n * Like `MemoryStorage`, `get` returns the stored value itself, which\n * operators do not mutate.\n */\nexport class DatabaseStorage {\n static create(\n lc: LogContext,\n path: string,\n options: DatabaseStorageOptions = {},\n ): DatabaseStorage {\n // SQLite is used for ephemeral storage (i.e. similar to RAM) that can spill to\n // disk to avoid consuming too much memory. Each worker thread gets its own\n // database (file) and acts as the single reader/writer of the DB, so\n // `locking_mode` is set to `EXCLUSIVE` for performance. Similarly, since\n // durability is not important, `synchronous` is set to `OFF` for performance.\n const db = new Database(lc, path);\n db.unsafeMode(true); // Allows journal_mode = OFF\n db.pragma('locking_mode = EXCLUSIVE');\n db.pragma('foreign_keys = OFF');\n db.pragma('journal_mode = OFF');\n db.pragma('synchronous = OFF');\n db.pragma('auto_vacuum = INCREMENTAL');\n\n db.prepare(CREATE_STORAGE_TABLE).run();\n lc.debug?.(`Created DatabaseStorage backed by ${path}`);\n return new DatabaseStorage(db, options);\n }\n\n readonly #stmts: Statements;\n readonly #options: typeof defaultOptions;\n readonly #db: Database;\n #numWrites = 0;\n\n /** The operators whose values are in memory. */\n readonly #inMemory = new Set<OpStorage>();\n /** The {@link getSizeOfEntry} of the values of the operators in `#inMemory`. */\n #size = 0;\n /** `maxMemoryBytes` in units of {@link getSizeOfEntry}. */\n readonly #maxSize: number;\n /** Orders the operators by last use. */\n #clock = 0;\n\n constructor(db: Database, options: DatabaseStorageOptions = {}) {\n this.#stmts = {\n get: db\n .prepare(\n `\n SELECT val FROM storage WHERE\n clientGroupID = ? AND op = ? AND key = ?\n `,\n )\n .pluck(true),\n set: db.prepare(`\n INSERT INTO storage (clientGroupID, op, key, val)\n VALUES(?, ?, ?, ?)\n ON CONFLICT(clientGroupID, op, key) \n DO \n UPDATE SET val = excluded.val\n `),\n del: db.prepare(`\n DELETE FROM storage WHERE\n clientGroupID = ? AND op = ? AND key = ?\n `),\n scan: db\n .prepare(\n `\n SELECT key, val FROM storage WHERE\n clientGroupID = ? AND op = ? AND key >= ?\n `,\n )\n .raw(true),\n clear: db.prepare(`\n DELETE FROM storage WHERE clientGroupID = ?\n `),\n clearOp: db.prepare(`\n DELETE FROM storage WHERE clientGroupID = ? AND op = ?\n `),\n commit: db.prepare('COMMIT'),\n begin: db.prepare('BEGIN'),\n };\n this.#stmts.begin.run();\n this.#options = {\n commitInterval: options.commitInterval ?? defaultOptions.commitInterval,\n compactionThresholdBytes:\n options.compactionThresholdBytes ??\n defaultOptions.compactionThresholdBytes,\n maxMemoryBytes: options.maxMemoryBytes ?? defaultOptions.maxMemoryBytes,\n };\n this.#maxSize = this.#options.maxMemoryBytes / HEAP_BYTES_PER_SIZE;\n this.#db = db;\n }\n\n close() {\n this.#checkpoint();\n this.#db.close();\n }\n\n /** The estimated size of the values that operators keep in memory. */\n get memoryBytes(): number {\n return Math.round(this.#size * HEAP_BYTES_PER_SIZE);\n }\n\n #get(op: OpStorage, key: string, def?: JSONValue): JSONValue | undefined {\n op.lastUsed = ++this.#clock;\n const {values} = op;\n if (values) {\n const val = values.get(key);\n return val === undefined ? def : val;\n }\n let val = op.cache.get(key);\n if (val === undefined && !op.cache.has(key)) {\n this.#maybeCheckpoint();\n const json = this.#stmts.get.get<string | undefined>(\n op.cgID,\n op.opID,\n key,\n );\n val = json === undefined ? undefined : JSON.parse(json);\n op.cacheSet(key, val);\n }\n return val === undefined ? def : val;\n }\n\n #set(op: OpStorage, key: string, val: JSONValue) {\n op.lastUsed = ++this.#clock;\n const {values} = op;\n if (values) {\n if (values.size === 0) {\n // The operator may have been released by destroy().\n this.#inMemory.add(op);\n }\n const old = values.get(key);\n const delta =\n getSizeOfEntry(key, val) -\n (old === undefined ? 0 : getSizeOfEntry(key, old));\n values.set(key, val);\n op.size += delta;\n this.#size += delta;\n if (this.#size > this.#maxSize) {\n this.#spillLeastRecentlyUsed();\n }\n return;\n }\n this.#write(op, key, val);\n // The cache is updated only once the database is, so a failed write\n // leaves it consistent with the database.\n op.cacheSet(key, val);\n }\n\n #del(op: OpStorage, key: string) {\n op.lastUsed = ++this.#clock;\n const {values} = op;\n if (values) {\n const old = values.get(key);\n if (old !== undefined) {\n values.delete(key);\n const size = getSizeOfEntry(key, old);\n op.size -= size;\n this.#size -= size;\n }\n return;\n }\n this.#maybeCheckpoint();\n this.#stmts.del.run(op.cgID, op.opID, key);\n op.cacheSet(key, undefined);\n }\n\n #write(op: OpStorage, key: string, val: JSONValue) {\n this.#maybeCheckpoint();\n this.#stmts.set.run(op.cgID, op.opID, key, JSON.stringify(val));\n }\n\n /**\n * Spills the least recently used operators until the values in memory are\n * under {@link SPILL_TARGET_PROPORTION} of the budget.\n */\n #spillLeastRecentlyUsed() {\n const target = this.#maxSize * SPILL_TARGET_PROPORTION;\n const ops: OpStorage[] = [];\n for (const op of this.#inMemory) {\n ops.push(op);\n }\n ops.sort((a, b) => a.lastUsed - b.lastUsed);\n for (const op of ops) {\n if (this.#size <= target) {\n break;\n }\n this.#spill(op);\n }\n }\n\n #spill(op: OpStorage) {\n const {values} = op;\n if (!values) {\n return;\n }\n for (const [key, val] of values) {\n this.#write(op, key, val);\n }\n this.#release(op);\n op.values = undefined;\n }\n\n /** Drops the values that `op` keeps in memory. */\n #release(op: OpStorage) {\n this.#size -= op.size;\n op.size = 0;\n op.values?.clear();\n op.cache.clear();\n this.#inMemory.delete(op);\n }\n\n #destroy(op: OpStorage) {\n if (!op.values) {\n this.#maybeCheckpoint();\n this.#stmts.clearOp.run(op.cgID, op.opID);\n }\n this.#release(op);\n }\n\n /**\n * We don't need to commit every single write to the DB\n * since we're not concerned with durability.\n * Waiting on commits can be expensive, so we commit\n * every `COMMIT_INTERVAL` writes.\n */\n #maybeCheckpoint() {\n if (++this.#numWrites >= this.#options.commitInterval) {\n this.#checkpoint();\n }\n }\n\n #checkpoint() {\n this.#stmts.commit.run();\n this.#stmts.begin.run();\n this.#numWrites = 0;\n }\n\n *#scan(\n op: OpStorage,\n opts: {prefix: string} = {prefix: ''},\n ): Stream<[string, JSONValue]> {\n const {prefix} = opts;\n const {values} = op;\n if (values) {\n const keys: string[] = [];\n for (const key of values.keys()) {\n if (key.startsWith(prefix)) {\n keys.push(key);\n }\n }\n // Sorted like SQLite's BINARY collation, which compares UTF-8 bytes.\n keys.sort(compareValues);\n for (const key of keys) {\n // Read through #get, which skips keys deleted since and still works\n // if the operator spills while the scan is suspended.\n const val = this.#get(op, key);\n if (val !== undefined) {\n yield [key, val];\n }\n }\n return;\n }\n for (const [key, val] of this.#stmts.scan.iterate<[string, string]>(\n op.cgID,\n op.opID,\n prefix,\n )) {\n if (!key.startsWith(prefix)) {\n return;\n }\n yield [key, JSON.parse(val)];\n }\n }\n\n createClientGroupStorage(cgID: string): ClientGroupStorage {\n // The group's live operator storages.\n const ops = new Set<OpStorage>();\n const destroy = () => {\n this.#stmts.clear.run(cgID);\n for (const op of ops) {\n this.#release(op);\n }\n this.#checkpoint();\n this.#db.compact(this.#options.compactionThresholdBytes);\n };\n this.#stmts.clear.run(cgID);\n\n let nextOpID = 1;\n return {\n createStorage: () => {\n const op = new OpStorage(\n cgID,\n nextOpID++,\n this.#options.maxMemoryBytes > 0,\n );\n ops.add(op);\n return {\n get: (key, def?) => this.#get(op, key, def),\n set: (key, val) => this.#set(op, key, val),\n del: key => this.#del(op, key),\n scan: opts => this.#scan(op, opts),\n destroy: () => {\n this.#destroy(op);\n ops.delete(op);\n },\n };\n },\n\n destroy,\n };\n }\n}\n"],"mappings":"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"}
|
package/out/zqlite/src/db.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Attributes } from '@opentelemetry/api';
|
|
2
2
|
import type { LogContext } from '@rocicorp/logger';
|
|
3
|
-
import SQLite3Database, { type RunResult, type Statement as SQLite3Statement } from '@rocicorp/zero-sqlite3';
|
|
3
|
+
import SQLite3Database, { type ColumnDefinition, type RunResult, type Statement as SQLite3Statement, type StatementIterator as SQLite3StatementIterator } from '@rocicorp/zero-sqlite3';
|
|
4
4
|
export declare class Database implements Disposable {
|
|
5
5
|
#private;
|
|
6
6
|
constructor(lc: LogContext, path: string, options?: SQLite3Database.Options, slowQueryThreshold?: number);
|
|
@@ -37,10 +37,55 @@ export declare class Statement {
|
|
|
37
37
|
readonly scanStatusReset: SQLite3Statement['scanStatusReset'];
|
|
38
38
|
constructor(lc: LogContext, attrs: Attributes, stmt: SQLite3Statement, threshold: number);
|
|
39
39
|
safeIntegers(useBigInt: boolean): this;
|
|
40
|
+
/**
|
|
41
|
+
* Return rows as arrays of column values instead of objects. Turning it
|
|
42
|
+
* off has no effect in pluck mode, as in better-sqlite3.
|
|
43
|
+
*/
|
|
44
|
+
raw(enabled: boolean): this;
|
|
45
|
+
/**
|
|
46
|
+
* Return the first column of each row instead of the row. Turning it off
|
|
47
|
+
* has no effect in raw mode, as in better-sqlite3.
|
|
48
|
+
*/
|
|
49
|
+
pluck(enabled: boolean): this;
|
|
50
|
+
/** The result columns, in the order of the values in a raw row. */
|
|
51
|
+
columns(): ColumnDefinition[];
|
|
40
52
|
run(...params: unknown[]): RunResult;
|
|
41
53
|
get<T>(...params: unknown[]): T;
|
|
42
54
|
all<T>(...params: unknown[]): T[];
|
|
43
55
|
iterate<T>(...params: unknown[]): IterableIterator<T>;
|
|
56
|
+
/**
|
|
57
|
+
* Reads the statement's rows in batches. Integers are read as with
|
|
58
|
+
* `safeIntegers(true)`. The cursor must be {@link BatchCursor.close closed}.
|
|
59
|
+
*/
|
|
60
|
+
batches(params: readonly unknown[]): BatchCursor;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Reads a statement's rows a batch at a time with one native call per batch
|
|
64
|
+
* (`nextBatch`), instead of one per row as `next()` does.
|
|
65
|
+
*/
|
|
66
|
+
export declare class BatchCursor {
|
|
67
|
+
#private;
|
|
68
|
+
constructor(log: IterationLog, it: SQLite3StatementIterator, columns: number);
|
|
69
|
+
/**
|
|
70
|
+
* Reads up to `capacity` rows and returns their values in one row-major
|
|
71
|
+
* array, empty once the rows are exhausted.
|
|
72
|
+
*/
|
|
73
|
+
next(capacity: number): (bigint | number | string | null)[];
|
|
74
|
+
/**
|
|
75
|
+
* Ends the cursor, abandoning any rows that were not read, and logs if the
|
|
76
|
+
* iteration was slow. Must be called once the rows are consumed.
|
|
77
|
+
*/
|
|
78
|
+
close(): void;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Logs slow iterations: once the time spent in SQLite, or the total time
|
|
82
|
+
* including the consumer's work between rows, reaches the threshold.
|
|
83
|
+
*/
|
|
84
|
+
declare class IterationLog {
|
|
85
|
+
#private;
|
|
86
|
+
constructor(lc: LogContext, attrs: Attributes, slowQueryThreshold: number);
|
|
87
|
+
addSQLiteTime(elapsed: number): void;
|
|
88
|
+
log(): void;
|
|
44
89
|
}
|
|
45
90
|
/**
|
|
46
91
|
* An error indicating that the Database failed to open. This essentially
|
|
@@ -49,4 +94,5 @@ export declare class Statement {
|
|
|
49
94
|
*/
|
|
50
95
|
export declare class DatabaseInitError extends Error {
|
|
51
96
|
}
|
|
97
|
+
export {};
|
|
52
98
|
//# sourceMappingURL=db.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../../zqlite/src/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,eAAe,EAAE,EAEtB,KAAK,SAAS,EACd,KAAK,SAAS,IAAI,gBAAgB,
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../../zqlite/src/db.ts"],"names":[],"mappings":"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"}
|
package/out/zqlite/src/db.js
CHANGED
|
@@ -5,7 +5,7 @@ import SQLite3Database, { SqliteError } from "@rocicorp/zero-sqlite3";
|
|
|
5
5
|
//#region ../zqlite/src/db.ts
|
|
6
6
|
var tracer = trace.getTracer("view-syncer", version);
|
|
7
7
|
var AUTO_VACUUM_INCREMENTAL = 2;
|
|
8
|
-
var MB =
|
|
8
|
+
var MB = 1048576;
|
|
9
9
|
function mb(bytes) {
|
|
10
10
|
return (bytes / MB).toFixed(2);
|
|
11
11
|
}
|
|
@@ -120,8 +120,12 @@ var Statement = class {
|
|
|
120
120
|
#lc;
|
|
121
121
|
#threshold;
|
|
122
122
|
#attrs;
|
|
123
|
+
#mode = "object";
|
|
123
124
|
scanStatus;
|
|
124
125
|
scanStatusReset;
|
|
126
|
+
#columnCount;
|
|
127
|
+
#safeIntegers;
|
|
128
|
+
#iterator;
|
|
125
129
|
constructor(lc, attrs, stmt, threshold) {
|
|
126
130
|
this.#lc = lc.withContext("class", "Statement");
|
|
127
131
|
this.#attrs = attrs;
|
|
@@ -131,9 +135,38 @@ var Statement = class {
|
|
|
131
135
|
this.scanStatusReset = this.#stmt.scanStatusReset.bind(this.#stmt);
|
|
132
136
|
}
|
|
133
137
|
safeIntegers(useBigInt) {
|
|
134
|
-
this.#
|
|
138
|
+
if (this.#safeIntegers !== useBigInt) {
|
|
139
|
+
this.#stmt.safeIntegers(useBigInt);
|
|
140
|
+
this.#safeIntegers = useBigInt;
|
|
141
|
+
}
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Return rows as arrays of column values instead of objects. Turning it
|
|
146
|
+
* off has no effect in pluck mode, as in better-sqlite3.
|
|
147
|
+
*/
|
|
148
|
+
raw(enabled) {
|
|
149
|
+
if (enabled ? this.#mode !== "raw" : this.#mode === "raw") {
|
|
150
|
+
this.#stmt.raw(enabled);
|
|
151
|
+
this.#mode = enabled ? "raw" : "object";
|
|
152
|
+
}
|
|
153
|
+
return this;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Return the first column of each row instead of the row. Turning it off
|
|
157
|
+
* has no effect in raw mode, as in better-sqlite3.
|
|
158
|
+
*/
|
|
159
|
+
pluck(enabled) {
|
|
160
|
+
if (enabled ? this.#mode !== "pluck" : this.#mode === "pluck") {
|
|
161
|
+
this.#stmt.pluck(enabled);
|
|
162
|
+
this.#mode = enabled ? "pluck" : "object";
|
|
163
|
+
}
|
|
135
164
|
return this;
|
|
136
165
|
}
|
|
166
|
+
/** The result columns, in the order of the values in a raw row. */
|
|
167
|
+
columns() {
|
|
168
|
+
return this.#stmt.columns();
|
|
169
|
+
}
|
|
137
170
|
run(...params) {
|
|
138
171
|
const start = performance.now();
|
|
139
172
|
const ret = this.#stmt.run(...params);
|
|
@@ -161,6 +194,62 @@ var Statement = class {
|
|
|
161
194
|
iterate(...params) {
|
|
162
195
|
return new LoggingIterableIterator(this.#lc, this.#attrs, this.#stmt.iterate(...params), this.#threshold);
|
|
163
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Reads the statement's rows in batches. Integers are read as with
|
|
199
|
+
* `safeIntegers(true)`. The cursor must be {@link BatchCursor.close closed}.
|
|
200
|
+
*/
|
|
201
|
+
batches(params) {
|
|
202
|
+
this.#columnCount ??= this.#stmt.columns().length;
|
|
203
|
+
const log = new IterationLog(this.#lc, this.#attrs, this.#threshold);
|
|
204
|
+
this.safeIntegers(true).raw(true);
|
|
205
|
+
return new BatchCursor(log, this.#iterator === void 0 ? this.#iterator = this.#stmt.iterate(...params) : this.#iterator.restart(...params), this.#columnCount);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Reads a statement's rows a batch at a time with one native call per batch
|
|
210
|
+
* (`nextBatch`), instead of one per row as `next()` does.
|
|
211
|
+
*/
|
|
212
|
+
var BatchCursor = class {
|
|
213
|
+
#log;
|
|
214
|
+
#it;
|
|
215
|
+
#columns;
|
|
216
|
+
#done = false;
|
|
217
|
+
constructor(log, it, columns) {
|
|
218
|
+
this.#log = log;
|
|
219
|
+
this.#it = it;
|
|
220
|
+
this.#columns = columns;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Reads up to `capacity` rows and returns their values in one row-major
|
|
224
|
+
* array, empty once the rows are exhausted.
|
|
225
|
+
*/
|
|
226
|
+
next(capacity) {
|
|
227
|
+
if (this.#done) return [];
|
|
228
|
+
const start = performance.now();
|
|
229
|
+
let values;
|
|
230
|
+
try {
|
|
231
|
+
values = this.#it.nextBatch(capacity);
|
|
232
|
+
} catch (e) {
|
|
233
|
+
this.#done = true;
|
|
234
|
+
this.#log.log();
|
|
235
|
+
throw e;
|
|
236
|
+
} finally {
|
|
237
|
+
this.#log.addSQLiteTime(performance.now() - start);
|
|
238
|
+
}
|
|
239
|
+
if (values.length < capacity * this.#columns) this.#done = true;
|
|
240
|
+
return values;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Ends the cursor, abandoning any rows that were not read, and logs if the
|
|
244
|
+
* iteration was slow. Must be called once the rows are consumed.
|
|
245
|
+
*/
|
|
246
|
+
close() {
|
|
247
|
+
if (!this.#done) {
|
|
248
|
+
this.#done = true;
|
|
249
|
+
this.#it.return?.();
|
|
250
|
+
}
|
|
251
|
+
this.#log.log();
|
|
252
|
+
}
|
|
164
253
|
};
|
|
165
254
|
var ITERATOR_TOTAL_LOG_WINDOW_MS = 6e4;
|
|
166
255
|
var ITERATOR_TOTAL_LOG_LIMIT = 10;
|
|
@@ -181,31 +270,27 @@ function admitIteratorTotalLog(now) {
|
|
|
181
270
|
suppressedIteratorTotalLogs = 0;
|
|
182
271
|
return suppressedCount;
|
|
183
272
|
}
|
|
184
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Logs slow iterations: once the time spent in SQLite, or the total time
|
|
275
|
+
* including the consumer's work between rows, reaches the threshold.
|
|
276
|
+
*/
|
|
277
|
+
var IterationLog = class {
|
|
185
278
|
#lc;
|
|
186
|
-
#it;
|
|
187
279
|
#threshold;
|
|
188
280
|
#attrs;
|
|
189
281
|
#start;
|
|
190
|
-
#
|
|
282
|
+
#sqliteTimeSum = 0;
|
|
191
283
|
#logged = false;
|
|
192
|
-
constructor(lc, attrs,
|
|
284
|
+
constructor(lc, attrs, slowQueryThreshold) {
|
|
193
285
|
this.#lc = lc;
|
|
194
286
|
this.#attrs = attrs;
|
|
195
|
-
this.#it = it;
|
|
196
287
|
this.#start = performance.now();
|
|
197
288
|
this.#threshold = slowQueryThreshold;
|
|
198
|
-
this.#sqliteRowTimeSum = 0;
|
|
199
289
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const ret = this.#it.next();
|
|
203
|
-
const elapsed = performance.now() - start;
|
|
204
|
-
this.#sqliteRowTimeSum += elapsed;
|
|
205
|
-
if (ret.done) this.#log();
|
|
206
|
-
return ret;
|
|
290
|
+
addSQLiteTime(elapsed) {
|
|
291
|
+
this.#sqliteTimeSum += elapsed;
|
|
207
292
|
}
|
|
208
|
-
|
|
293
|
+
log() {
|
|
209
294
|
if (this.#logged) return;
|
|
210
295
|
this.#logged = true;
|
|
211
296
|
const now = performance.now();
|
|
@@ -216,26 +301,41 @@ var LoggingIterableIterator = class {
|
|
|
216
301
|
...this.#attrs,
|
|
217
302
|
type: "total",
|
|
218
303
|
method: "iterate",
|
|
219
|
-
sqliteMs: this.#
|
|
304
|
+
sqliteMs: this.#sqliteTimeSum,
|
|
220
305
|
...suppressedCount > 0 ? { suppressedCount } : void 0
|
|
221
306
|
}, "Slow SQLite iterator total time (including consumer work and waits between rows)");
|
|
222
307
|
}
|
|
223
|
-
if (this.#
|
|
308
|
+
if (this.#sqliteTimeSum >= this.#threshold) logSlow(this.#lc.withContext("method", "iterate").withContext("type", "sqlite"), this.#sqliteTimeSum, {
|
|
224
309
|
...this.#attrs,
|
|
225
310
|
type: "sqlite",
|
|
226
311
|
method: "iterate",
|
|
227
312
|
totalMs
|
|
228
313
|
});
|
|
229
314
|
}
|
|
315
|
+
};
|
|
316
|
+
var LoggingIterableIterator = class {
|
|
317
|
+
#it;
|
|
318
|
+
#log;
|
|
319
|
+
constructor(lc, attrs, it, slowQueryThreshold) {
|
|
320
|
+
this.#it = it;
|
|
321
|
+
this.#log = new IterationLog(lc, attrs, slowQueryThreshold);
|
|
322
|
+
}
|
|
323
|
+
next() {
|
|
324
|
+
const start = performance.now();
|
|
325
|
+
const ret = this.#it.next();
|
|
326
|
+
this.#log.addSQLiteTime(performance.now() - start);
|
|
327
|
+
if (ret.done) this.#log.log();
|
|
328
|
+
return ret;
|
|
329
|
+
}
|
|
230
330
|
[Symbol.iterator]() {
|
|
231
331
|
return this;
|
|
232
332
|
}
|
|
233
333
|
return() {
|
|
234
|
-
this.#log();
|
|
334
|
+
this.#log.log();
|
|
235
335
|
return this.#it.return?.();
|
|
236
336
|
}
|
|
237
337
|
throw(e) {
|
|
238
|
-
this.#log();
|
|
338
|
+
this.#log.log();
|
|
239
339
|
return this.#it.throw?.(e);
|
|
240
340
|
}
|
|
241
341
|
};
|
|
@@ -251,6 +351,6 @@ function logSlow(lc, elapsed, attrs, message = "Slow SQLite query") {
|
|
|
251
351
|
*/
|
|
252
352
|
var DatabaseInitError = class extends Error {};
|
|
253
353
|
//#endregion
|
|
254
|
-
export { Database, DatabaseInitError };
|
|
354
|
+
export { BatchCursor, Database, DatabaseInitError, Statement };
|
|
255
355
|
|
|
256
356
|
//# sourceMappingURL=db.js.map
|
package/out/zqlite/src/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","names":["#db","#threshold","#lc","#pageSize","#run","#bytes","#stmt","#attrs","#logIfSlow","#it","#start","#sqliteRowTimeSum","#log","#logged"],"sources":["../../../../zqlite/src/db.ts"],"sourcesContent":["import {trace, type Attributes} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\nimport SQLite3Database, {\n SqliteError,\n type RunResult,\n type Statement as SQLite3Statement,\n} from '@rocicorp/zero-sqlite3';\nimport {manualSpan} from '../../otel/src/span.ts';\nimport {version} from '../../otel/src/version.ts';\n\nconst tracer = trace.getTracer('view-syncer', version);\n\n// https://www.sqlite.org/pragma.html#pragma_auto_vacuum\nconst AUTO_VACUUM_INCREMENTAL = 2;\n\nconst MB = 1024 * 1024;\n\nfunction mb(bytes: number): string {\n return (bytes / MB).toFixed(2);\n}\n\nexport class Database implements Disposable {\n readonly #db: SQLite3Database.Database;\n readonly #threshold: number;\n readonly #lc: LogContext;\n readonly #pageSize: number;\n\n constructor(\n lc: LogContext,\n path: string,\n options?: SQLite3Database.Options,\n slowQueryThreshold = 100,\n ) {\n try {\n this.#lc = lc.withContext('class', 'Database').withContext('path', path);\n this.#db = new SQLite3Database(path, options);\n this.#threshold = slowQueryThreshold;\n\n // Keep the WAL when this is the last connection to close the database,\n // which would otherwise checkpoint and delete it. Deleting it discards\n // the WAL that a litestream backup continues from, forcing a new\n // snapshot. See persistWal() for switching out of WAL mode.\n this.#db.persistWal();\n\n // Match Postgres LIKE/ILIKE semantics. Postgres LIKE is case-sensitive,\n // but SQLite's LIKE operator is case-insensitive by default; enable\n // case-sensitive LIKE so the bare operator matches Postgres. Case-\n // insensitive ILIKE is handled in query-builder.ts by lower()-ing both\n // operands (using the Unicode-aware lower() that @rocicorp/zero-sqlite3\n // provides via ICU).\n this.pragma('case_sensitive_like = ON');\n\n const [{page_size: pageSize}] = this.pragma<{page_size: number}>(\n 'page_size',\n );\n this.#pageSize = pageSize;\n } catch (cause) {\n throw new DatabaseInitError(String(cause), {cause});\n }\n }\n\n prepare(sql: string): Statement {\n return this.#run(\n 'prepare',\n sql,\n () =>\n new Statement(\n this.#lc.withContext('sql', sql),\n {class: 'Statement', sql},\n this.#db.prepare(sql),\n this.#threshold,\n ),\n );\n }\n\n exec(sql: string): void {\n this.#run('exec', sql, () => this.#db.exec(sql));\n }\n\n pragma<T = unknown>(sql: string): T[] {\n return this.#run<T[]>('pragma', sql, () => this.#db.pragma(sql) as T[]);\n }\n\n #bytes(pages: number) {\n return pages * this.#pageSize;\n }\n\n compact(freeableBytesThreshold: number) {\n const [{freelist_count: freelistCount}] = this.pragma<{\n freelist_count: number;\n }>('freelist_count');\n\n const freeable = this.#bytes(freelistCount);\n if (freeable < freeableBytesThreshold) {\n this.#lc.debug?.(\n `Not compacting ${this.#db.name}: ${mb(freeable)} freeable MB`,\n );\n return;\n }\n const [{auto_vacuum: autoVacuumMode}] = this.pragma<{auto_vacuum: number}>(\n 'auto_vacuum',\n );\n if (autoVacuumMode !== AUTO_VACUUM_INCREMENTAL) {\n this.#lc.warn?.(\n `Cannot compact ${mb(freeable)} MB of ` +\n `${this.#db.name} because AUTO_VACUUM mode is ${autoVacuumMode}.`,\n );\n return;\n }\n const start = Date.now();\n const [{page_count: pageCountBefore}] = this.pragma<{page_count: number}>(\n 'page_count',\n );\n\n this.pragma('incremental_vacuum');\n\n const [{page_count: pageCountAfter}] = this.pragma<{page_count: number}>(\n 'page_count',\n );\n\n this.#lc.info?.(\n `Compacted ${this.#db.name} from ` +\n `${mb(this.#bytes(pageCountBefore))} MB to ` +\n `${mb(this.#bytes(pageCountAfter))} MB ` +\n `(${Date.now() - start} ms)`,\n );\n }\n\n unsafeMode(unsafe: boolean) {\n this.#db.unsafeMode(unsafe);\n }\n\n /**\n * Toggles whether the WAL is kept when this is the last connection to close\n * the database (on by default). Turn it off before switching the database\n * out of WAL mode (e.g. `journal_mode = DELETE` or `OFF`): with it on, the\n * WAL file is left behind and reopened by the next transaction, so the\n * database effectively stays in WAL mode.\n */\n persistWal(persist: boolean) {\n this.#db.persistWal(persist);\n }\n\n #run<T>(method: string, sql: string, fn: () => T): T {\n const start = performance.now();\n try {\n return fn();\n } catch (e) {\n if (e instanceof SqliteError) {\n e.message += `: ${sql}`;\n }\n throw e;\n } finally {\n const elapsed = performance.now() - start;\n if (elapsed >= this.#threshold) {\n logSlow(this.#lc.withContext('method', method), elapsed, {method});\n }\n }\n }\n\n /**\n * Closes the database. For writable connections, `PRAGMA optimize` is run\n * first (as recommended by SQLite) unless `optimize` is `false`, which is\n * appropriate for short-lived handles on a database whose statistics are\n * maintained by a longer-lived writer.\n */\n close({optimize = true}: {optimize?: boolean | undefined} = {}): void {\n const start = Date.now();\n if (optimize && !this.#db.readonly) {\n try {\n this.#db.pragma('optimize');\n const elapsed = Date.now() - start;\n if (elapsed > 2) {\n this.#lc.debug?.(`PRAGMA optimized (${elapsed} ms)`);\n }\n } catch (e) {\n this.#lc.warn?.('error running PRAGMA optimize', e);\n }\n }\n this.#db.close();\n }\n\n transaction<T>(fn: () => T): T {\n return this.#db.transaction(fn)();\n }\n\n get name() {\n return this.#db.name;\n }\n\n get inTransaction() {\n return this.#db.inTransaction;\n }\n\n [Symbol.dispose](): void {\n this.close();\n }\n}\n\nexport class Statement {\n readonly #stmt: SQLite3Statement;\n readonly #lc: LogContext;\n readonly #threshold: number;\n readonly #attrs: Attributes;\n readonly scanStatus: SQLite3Statement['scanStatusV2'];\n readonly scanStatusReset: SQLite3Statement['scanStatusReset'];\n\n constructor(\n lc: LogContext,\n attrs: Attributes,\n stmt: SQLite3Statement,\n threshold: number,\n ) {\n this.#lc = lc.withContext('class', 'Statement');\n this.#attrs = attrs;\n this.#stmt = stmt;\n this.#threshold = threshold;\n this.scanStatus = this.#stmt.scanStatusV2.bind(this.#stmt);\n this.scanStatusReset = this.#stmt.scanStatusReset.bind(this.#stmt);\n }\n\n safeIntegers(useBigInt: boolean): this {\n this.#stmt.safeIntegers(useBigInt);\n return this;\n }\n\n run(...params: unknown[]): RunResult {\n const start = performance.now();\n const ret = this.#stmt.run(...params);\n this.#logIfSlow('run', performance.now() - start);\n return ret;\n }\n\n get<T>(...params: unknown[]): T {\n const start = performance.now();\n const ret = this.#stmt.get(...params);\n this.#logIfSlow('get', performance.now() - start);\n return ret as T;\n }\n\n all<T>(...params: unknown[]): T[] {\n const start = performance.now();\n const ret = this.#stmt.all(...params);\n this.#logIfSlow('all', performance.now() - start);\n return ret as T[];\n }\n\n #logIfSlow(method: string, elapsed: number): void {\n if (elapsed >= this.#threshold) {\n logSlow(this.#lc.withContext('method', method), elapsed, {\n ...this.#attrs,\n method,\n });\n }\n }\n\n iterate<T>(...params: unknown[]): IterableIterator<T> {\n return new LoggingIterableIterator(\n this.#lc,\n this.#attrs,\n this.#stmt.iterate(...params),\n this.#threshold,\n ) as IterableIterator<T>;\n }\n}\n\n// Bound consumer-time warnings across all databases and SQL statements in this\n// process. Nested iterators can all outlive the threshold during the same stall.\nconst ITERATOR_TOTAL_LOG_WINDOW_MS = 60_000;\nconst ITERATOR_TOTAL_LOG_LIMIT = 10;\nlet iteratorTotalLogWindowStart = -Infinity;\nlet iteratorTotalLogsInWindow = 0;\nlet suppressedIteratorTotalLogs = 0;\n\nfunction admitIteratorTotalLog(now: number): number | undefined {\n if (now - iteratorTotalLogWindowStart >= ITERATOR_TOTAL_LOG_WINDOW_MS) {\n iteratorTotalLogWindowStart = now;\n iteratorTotalLogsInWindow = 0;\n }\n if (iteratorTotalLogsInWindow >= ITERATOR_TOTAL_LOG_LIMIT) {\n suppressedIteratorTotalLogs++;\n return undefined;\n }\n iteratorTotalLogsInWindow++;\n const suppressedCount = suppressedIteratorTotalLogs;\n suppressedIteratorTotalLogs = 0;\n return suppressedCount;\n}\n\nclass LoggingIterableIterator<T> implements IterableIterator<T> {\n readonly #lc: LogContext;\n readonly #it: IterableIterator<T>;\n readonly #threshold: number;\n readonly #attrs: Attributes;\n #start: number;\n #sqliteRowTimeSum: number;\n #logged = false;\n\n constructor(\n lc: LogContext,\n attrs: Attributes,\n it: IterableIterator<T>,\n slowQueryThreshold: number,\n ) {\n this.#lc = lc;\n this.#attrs = attrs;\n this.#it = it;\n this.#start = performance.now();\n this.#threshold = slowQueryThreshold;\n this.#sqliteRowTimeSum = 0;\n }\n\n next(): IteratorResult<T> {\n const start = performance.now();\n const ret = this.#it.next();\n const elapsed = performance.now() - start;\n this.#sqliteRowTimeSum += elapsed;\n if (ret.done) {\n this.#log();\n }\n return ret;\n }\n\n #log() {\n // TableSource closes iterators in finally, including after next() is done.\n if (this.#logged) {\n return;\n }\n this.#logged = true;\n\n // Total time includes downstream consumer work and waits between rows.\n // Check it independently of the time spent stepping SQLite.\n const now = performance.now();\n const totalMs = now - this.#start;\n if (totalMs >= this.#threshold) {\n const suppressedCount = admitIteratorTotalLog(now);\n if (suppressedCount !== undefined) {\n logSlow(\n this.#lc,\n totalMs,\n {\n ...this.#attrs,\n type: 'total',\n method: 'iterate',\n sqliteMs: this.#sqliteRowTimeSum,\n ...(suppressedCount > 0 ? {suppressedCount} : undefined),\n },\n 'Slow SQLite iterator total time (including consumer work and waits between rows)',\n );\n }\n }\n if (this.#sqliteRowTimeSum >= this.#threshold) {\n logSlow(\n this.#lc.withContext('method', 'iterate').withContext('type', 'sqlite'),\n this.#sqliteRowTimeSum,\n {\n ...this.#attrs,\n type: 'sqlite',\n method: 'iterate',\n totalMs,\n },\n );\n }\n }\n\n [Symbol.iterator](): IterableIterator<T> {\n return this;\n }\n\n return(): IteratorResult<T> {\n this.#log();\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return this.#it.return?.() as any;\n }\n\n throw(e: unknown): IteratorResult<T> {\n this.#log();\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return this.#it.throw?.(e) as any;\n }\n}\n\nfunction logSlow(\n lc: LogContext,\n elapsed: number,\n attrs: Attributes,\n message = 'Slow SQLite query',\n): void {\n for (const [key, value] of Object.entries(attrs)) {\n lc = lc.withContext(key, value);\n }\n lc.warn?.(message, elapsed);\n manualSpan(tracer, 'db.slow-query', elapsed, attrs);\n}\n\n/**\n * An error indicating that the Database failed to open. This essentially\n * wraps the TypeError thrown by the better-sqlite3 package with something\n * more specific.\n */\nexport class DatabaseInitError extends Error {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"db.js","names":[],"sources":["../../../../zqlite/src/db.ts"],"sourcesContent":["import {trace, type Attributes} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\nimport SQLite3Database, {\n SqliteError,\n type ColumnDefinition,\n type RunResult,\n type Statement as SQLite3Statement,\n type StatementIterator as SQLite3StatementIterator,\n} from '@rocicorp/zero-sqlite3';\nimport {manualSpan} from '../../otel/src/span.ts';\nimport {version} from '../../otel/src/version.ts';\n\nconst tracer = trace.getTracer('view-syncer', version);\n\n// https://www.sqlite.org/pragma.html#pragma_auto_vacuum\nconst AUTO_VACUUM_INCREMENTAL = 2;\n\nconst MB = 1024 * 1024;\n\nfunction mb(bytes: number): string {\n return (bytes / MB).toFixed(2);\n}\n\nexport class Database implements Disposable {\n readonly #db: SQLite3Database.Database;\n readonly #threshold: number;\n readonly #lc: LogContext;\n readonly #pageSize: number;\n\n constructor(\n lc: LogContext,\n path: string,\n options?: SQLite3Database.Options,\n slowQueryThreshold = 100,\n ) {\n try {\n this.#lc = lc.withContext('class', 'Database').withContext('path', path);\n this.#db = new SQLite3Database(path, options);\n this.#threshold = slowQueryThreshold;\n\n // Keep the WAL when this is the last connection to close the database,\n // which would otherwise checkpoint and delete it. Deleting it discards\n // the WAL that a litestream backup continues from, forcing a new\n // snapshot. See persistWal() for switching out of WAL mode.\n this.#db.persistWal();\n\n // Match Postgres LIKE/ILIKE semantics. Postgres LIKE is case-sensitive,\n // but SQLite's LIKE operator is case-insensitive by default; enable\n // case-sensitive LIKE so the bare operator matches Postgres. Case-\n // insensitive ILIKE is handled in query-builder.ts by lower()-ing both\n // operands (using the Unicode-aware lower() that @rocicorp/zero-sqlite3\n // provides via ICU).\n this.pragma('case_sensitive_like = ON');\n\n const [{page_size: pageSize}] = this.pragma<{page_size: number}>(\n 'page_size',\n );\n this.#pageSize = pageSize;\n } catch (cause) {\n throw new DatabaseInitError(String(cause), {cause});\n }\n }\n\n prepare(sql: string): Statement {\n return this.#run(\n 'prepare',\n sql,\n () =>\n new Statement(\n this.#lc.withContext('sql', sql),\n {class: 'Statement', sql},\n this.#db.prepare(sql),\n this.#threshold,\n ),\n );\n }\n\n exec(sql: string): void {\n this.#run('exec', sql, () => this.#db.exec(sql));\n }\n\n pragma<T = unknown>(sql: string): T[] {\n return this.#run<T[]>('pragma', sql, () => this.#db.pragma(sql) as T[]);\n }\n\n #bytes(pages: number) {\n return pages * this.#pageSize;\n }\n\n compact(freeableBytesThreshold: number) {\n const [{freelist_count: freelistCount}] = this.pragma<{\n freelist_count: number;\n }>('freelist_count');\n\n const freeable = this.#bytes(freelistCount);\n if (freeable < freeableBytesThreshold) {\n this.#lc.debug?.(\n `Not compacting ${this.#db.name}: ${mb(freeable)} freeable MB`,\n );\n return;\n }\n const [{auto_vacuum: autoVacuumMode}] = this.pragma<{auto_vacuum: number}>(\n 'auto_vacuum',\n );\n if (autoVacuumMode !== AUTO_VACUUM_INCREMENTAL) {\n this.#lc.warn?.(\n `Cannot compact ${mb(freeable)} MB of ` +\n `${this.#db.name} because AUTO_VACUUM mode is ${autoVacuumMode}.`,\n );\n return;\n }\n const start = Date.now();\n const [{page_count: pageCountBefore}] = this.pragma<{page_count: number}>(\n 'page_count',\n );\n\n this.pragma('incremental_vacuum');\n\n const [{page_count: pageCountAfter}] = this.pragma<{page_count: number}>(\n 'page_count',\n );\n\n this.#lc.info?.(\n `Compacted ${this.#db.name} from ` +\n `${mb(this.#bytes(pageCountBefore))} MB to ` +\n `${mb(this.#bytes(pageCountAfter))} MB ` +\n `(${Date.now() - start} ms)`,\n );\n }\n\n unsafeMode(unsafe: boolean) {\n this.#db.unsafeMode(unsafe);\n }\n\n /**\n * Toggles whether the WAL is kept when this is the last connection to close\n * the database (on by default). Turn it off before switching the database\n * out of WAL mode (e.g. `journal_mode = DELETE` or `OFF`): with it on, the\n * WAL file is left behind and reopened by the next transaction, so the\n * database effectively stays in WAL mode.\n */\n persistWal(persist: boolean) {\n this.#db.persistWal(persist);\n }\n\n #run<T>(method: string, sql: string, fn: () => T): T {\n const start = performance.now();\n try {\n return fn();\n } catch (e) {\n if (e instanceof SqliteError) {\n e.message += `: ${sql}`;\n }\n throw e;\n } finally {\n const elapsed = performance.now() - start;\n if (elapsed >= this.#threshold) {\n logSlow(this.#lc.withContext('method', method), elapsed, {method});\n }\n }\n }\n\n /**\n * Closes the database. For writable connections, `PRAGMA optimize` is run\n * first (as recommended by SQLite) unless `optimize` is `false`, which is\n * appropriate for short-lived handles on a database whose statistics are\n * maintained by a longer-lived writer.\n */\n close({optimize = true}: {optimize?: boolean | undefined} = {}): void {\n const start = Date.now();\n if (optimize && !this.#db.readonly) {\n try {\n this.#db.pragma('optimize');\n const elapsed = Date.now() - start;\n if (elapsed > 2) {\n this.#lc.debug?.(`PRAGMA optimized (${elapsed} ms)`);\n }\n } catch (e) {\n this.#lc.warn?.('error running PRAGMA optimize', e);\n }\n }\n this.#db.close();\n }\n\n transaction<T>(fn: () => T): T {\n return this.#db.transaction(fn)();\n }\n\n get name() {\n return this.#db.name;\n }\n\n get inTransaction() {\n return this.#db.inTransaction;\n }\n\n [Symbol.dispose](): void {\n this.close();\n }\n}\n\nexport class Statement {\n readonly #stmt: SQLite3Statement;\n readonly #lc: LogContext;\n readonly #threshold: number;\n readonly #attrs: Attributes;\n // Mirrors the native statement's mode, so that setting the mode it is\n // already in, as callers sharing a cached statement do, stays in JS.\n #mode: 'object' | 'raw' | 'pluck' = 'object';\n readonly scanStatus: SQLite3Statement['scanStatusV2'];\n readonly scanStatusReset: SQLite3Statement['scanStatusReset'];\n #columnCount: number | undefined;\n #safeIntegers: boolean | undefined;\n #iterator: SQLite3StatementIterator | undefined;\n\n constructor(\n lc: LogContext,\n attrs: Attributes,\n stmt: SQLite3Statement,\n threshold: number,\n ) {\n this.#lc = lc.withContext('class', 'Statement');\n this.#attrs = attrs;\n this.#stmt = stmt;\n this.#threshold = threshold;\n this.scanStatus = this.#stmt.scanStatusV2.bind(this.#stmt);\n this.scanStatusReset = this.#stmt.scanStatusReset.bind(this.#stmt);\n }\n\n safeIntegers(useBigInt: boolean): this {\n // Tracked here, like the row mode, to skip a native call per fetch.\n if (this.#safeIntegers !== useBigInt) {\n this.#stmt.safeIntegers(useBigInt);\n this.#safeIntegers = useBigInt;\n }\n return this;\n }\n\n /**\n * Return rows as arrays of column values instead of objects. Turning it\n * off has no effect in pluck mode, as in better-sqlite3.\n */\n raw(enabled: boolean): this {\n if (enabled ? this.#mode !== 'raw' : this.#mode === 'raw') {\n this.#stmt.raw(enabled);\n this.#mode = enabled ? 'raw' : 'object';\n }\n return this;\n }\n\n /**\n * Return the first column of each row instead of the row. Turning it off\n * has no effect in raw mode, as in better-sqlite3.\n */\n pluck(enabled: boolean): this {\n if (enabled ? this.#mode !== 'pluck' : this.#mode === 'pluck') {\n this.#stmt.pluck(enabled);\n this.#mode = enabled ? 'pluck' : 'object';\n }\n return this;\n }\n\n /** The result columns, in the order of the values in a raw row. */\n columns(): ColumnDefinition[] {\n return this.#stmt.columns();\n }\n\n run(...params: unknown[]): RunResult {\n const start = performance.now();\n const ret = this.#stmt.run(...params);\n this.#logIfSlow('run', performance.now() - start);\n return ret;\n }\n\n get<T>(...params: unknown[]): T {\n const start = performance.now();\n const ret = this.#stmt.get(...params);\n this.#logIfSlow('get', performance.now() - start);\n return ret as T;\n }\n\n all<T>(...params: unknown[]): T[] {\n const start = performance.now();\n const ret = this.#stmt.all(...params);\n this.#logIfSlow('all', performance.now() - start);\n return ret as T[];\n }\n\n #logIfSlow(method: string, elapsed: number): void {\n if (elapsed >= this.#threshold) {\n logSlow(this.#lc.withContext('method', method), elapsed, {\n ...this.#attrs,\n method,\n });\n }\n }\n\n iterate<T>(...params: unknown[]): IterableIterator<T> {\n return new LoggingIterableIterator(\n this.#lc,\n this.#attrs,\n this.#stmt.iterate(...params),\n this.#threshold,\n ) as IterableIterator<T>;\n }\n\n /**\n * Reads the statement's rows in batches. Integers are read as with\n * `safeIntegers(true)`. The cursor must be {@link BatchCursor.close closed}.\n */\n batches(params: readonly unknown[]): BatchCursor {\n this.#columnCount ??= this.#stmt.columns().length;\n const log = new IterationLog(this.#lc, this.#attrs, this.#threshold);\n this.safeIntegers(true).raw(true);\n // Reuse the iterator of this statement's previous cursor, which is closed\n // by then: creating one per fetch is a noticeable part of short fetches.\n const it =\n this.#iterator === undefined\n ? (this.#iterator = this.#stmt.iterate(...params))\n : this.#iterator.restart(...params);\n return new BatchCursor(log, it, this.#columnCount);\n }\n}\n\n/**\n * Reads a statement's rows a batch at a time with one native call per batch\n * (`nextBatch`), instead of one per row as `next()` does.\n */\nexport class BatchCursor {\n readonly #log: IterationLog;\n readonly #it: SQLite3StatementIterator;\n readonly #columns: number;\n #done = false;\n\n constructor(\n log: IterationLog,\n it: SQLite3StatementIterator,\n columns: number,\n ) {\n this.#log = log;\n this.#it = it;\n this.#columns = columns;\n }\n\n /**\n * Reads up to `capacity` rows and returns their values in one row-major\n * array, empty once the rows are exhausted.\n */\n next(capacity: number): (bigint | number | string | null)[] {\n if (this.#done) {\n return [];\n }\n const start = performance.now();\n let values: (bigint | number | string | null)[];\n try {\n values = this.#it.nextBatch(capacity) as (\n | bigint\n | number\n | string\n | null\n )[];\n } catch (e) {\n this.#done = true;\n this.#log.log();\n throw e;\n } finally {\n this.#log.addSQLiteTime(performance.now() - start);\n }\n if (values.length < capacity * this.#columns) {\n // The iterator is finished, but the caller is still to consume this\n // batch: close() logs, so that the total time includes that work.\n this.#done = true;\n }\n return values;\n }\n\n /**\n * Ends the cursor, abandoning any rows that were not read, and logs if the\n * iteration was slow. Must be called once the rows are consumed.\n */\n close(): void {\n if (!this.#done) {\n this.#done = true;\n this.#it.return?.();\n }\n this.#log.log();\n }\n}\n\n// Bound consumer-time warnings across all databases and SQL statements in this\n// process. Nested iterators can all outlive the threshold during the same stall.\nconst ITERATOR_TOTAL_LOG_WINDOW_MS = 60_000;\nconst ITERATOR_TOTAL_LOG_LIMIT = 10;\nlet iteratorTotalLogWindowStart = -Infinity;\nlet iteratorTotalLogsInWindow = 0;\nlet suppressedIteratorTotalLogs = 0;\n\nfunction admitIteratorTotalLog(now: number): number | undefined {\n if (now - iteratorTotalLogWindowStart >= ITERATOR_TOTAL_LOG_WINDOW_MS) {\n iteratorTotalLogWindowStart = now;\n iteratorTotalLogsInWindow = 0;\n }\n if (iteratorTotalLogsInWindow >= ITERATOR_TOTAL_LOG_LIMIT) {\n suppressedIteratorTotalLogs++;\n return undefined;\n }\n iteratorTotalLogsInWindow++;\n const suppressedCount = suppressedIteratorTotalLogs;\n suppressedIteratorTotalLogs = 0;\n return suppressedCount;\n}\n\n/**\n * Logs slow iterations: once the time spent in SQLite, or the total time\n * including the consumer's work between rows, reaches the threshold.\n */\nclass IterationLog {\n readonly #lc: LogContext;\n readonly #threshold: number;\n readonly #attrs: Attributes;\n readonly #start: number;\n #sqliteTimeSum = 0;\n #logged = false;\n\n constructor(lc: LogContext, attrs: Attributes, slowQueryThreshold: number) {\n this.#lc = lc;\n this.#attrs = attrs;\n this.#start = performance.now();\n this.#threshold = slowQueryThreshold;\n }\n\n addSQLiteTime(elapsed: number): void {\n this.#sqliteTimeSum += elapsed;\n }\n\n log() {\n // TableSource closes iterators in finally, including after next() is done.\n if (this.#logged) {\n return;\n }\n this.#logged = true;\n\n // Total time includes downstream consumer work and waits between rows.\n // Check it independently of the time spent stepping SQLite.\n const now = performance.now();\n const totalMs = now - this.#start;\n if (totalMs >= this.#threshold) {\n const suppressedCount = admitIteratorTotalLog(now);\n if (suppressedCount !== undefined) {\n logSlow(\n this.#lc,\n totalMs,\n {\n ...this.#attrs,\n type: 'total',\n method: 'iterate',\n sqliteMs: this.#sqliteTimeSum,\n ...(suppressedCount > 0 ? {suppressedCount} : undefined),\n },\n 'Slow SQLite iterator total time (including consumer work and waits between rows)',\n );\n }\n }\n if (this.#sqliteTimeSum >= this.#threshold) {\n logSlow(\n this.#lc.withContext('method', 'iterate').withContext('type', 'sqlite'),\n this.#sqliteTimeSum,\n {\n ...this.#attrs,\n type: 'sqlite',\n method: 'iterate',\n totalMs,\n },\n );\n }\n }\n}\n\nclass LoggingIterableIterator<T> implements IterableIterator<T> {\n readonly #it: IterableIterator<T>;\n readonly #log: IterationLog;\n\n constructor(\n lc: LogContext,\n attrs: Attributes,\n it: IterableIterator<T>,\n slowQueryThreshold: number,\n ) {\n this.#it = it;\n this.#log = new IterationLog(lc, attrs, slowQueryThreshold);\n }\n\n next(): IteratorResult<T> {\n const start = performance.now();\n const ret = this.#it.next();\n this.#log.addSQLiteTime(performance.now() - start);\n if (ret.done) {\n this.#log.log();\n }\n return ret;\n }\n\n [Symbol.iterator](): IterableIterator<T> {\n return this;\n }\n\n return(): IteratorResult<T> {\n this.#log.log();\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return this.#it.return?.() as any;\n }\n\n throw(e: unknown): IteratorResult<T> {\n this.#log.log();\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n return this.#it.throw?.(e) as any;\n }\n}\n\nfunction logSlow(\n lc: LogContext,\n elapsed: number,\n attrs: Attributes,\n message = 'Slow SQLite query',\n): void {\n for (const [key, value] of Object.entries(attrs)) {\n lc = lc.withContext(key, value);\n }\n lc.warn?.(message, elapsed);\n manualSpan(tracer, 'db.slow-query', elapsed, attrs);\n}\n\n/**\n * An error indicating that the Database failed to open. This essentially\n * wraps the TypeError thrown by the better-sqlite3 package with something\n * more specific.\n */\nexport class DatabaseInitError extends Error {}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain-queries.js","names":[],"sources":["../../../../zqlite/src/explain-queries.ts"],"sourcesContent":["import type {RowCountsBySource} from '../../zero-protocol/src/analyze-query-result.ts';\nimport type {Database} from './db.ts';\n\nexport function explainQueries(counts: RowCountsBySource, db: Database) {\n const plans: Record<string, string[]> = {};\n for (const querySet of Object.values(counts)) {\n const queries = Object.keys(querySet);\n for (const query of queries) {\n const plan = db\n // we should be more intelligent about value replacement.\n // Different values result in different plans. E.g., picking a value at the start\n // of an index will result in `scan` vs `search`. The scan is fine in that case.\n .prepare(`EXPLAIN QUERY PLAN ${query.replaceAll('?', \"'sdfse'\")}`)\n .all<{detail: string}>()\n .map(r => r.detail);\n plans[query] = plan;\n }\n }\n\n return plans;\n}\n"],"mappings":";AAGA,SAAgB,eAAe,QAA2B,IAAc;CACtE,MAAM,QAAkC,CAAC;CACzC,KAAK,MAAM,YAAY,OAAO,OAAO,MAAM,GAAG;EAC5C,MAAM,UAAU,OAAO,KAAK,QAAQ;EACpC,KAAK,MAAM,SAAS,SAQlB,MAAM,SAPO,GAIV,QAAQ,sBAAsB,MAAM,WAAW,KAAK,SAAS,GAAG,
|
|
1
|
+
{"version":3,"file":"explain-queries.js","names":[],"sources":["../../../../zqlite/src/explain-queries.ts"],"sourcesContent":["import type {RowCountsBySource} from '../../zero-protocol/src/analyze-query-result.ts';\nimport type {Database} from './db.ts';\n\nexport function explainQueries(counts: RowCountsBySource, db: Database) {\n const plans: Record<string, string[]> = {};\n for (const querySet of Object.values(counts)) {\n const queries = Object.keys(querySet);\n for (const query of queries) {\n const plan = db\n // we should be more intelligent about value replacement.\n // Different values result in different plans. E.g., picking a value at the start\n // of an index will result in `scan` vs `search`. The scan is fine in that case.\n .prepare(`EXPLAIN QUERY PLAN ${query.replaceAll('?', \"'sdfse'\")}`)\n .all<{detail: string}>()\n .map(r => r.detail);\n plans[query] = plan;\n }\n }\n\n return plans;\n}\n"],"mappings":";AAGA,SAAgB,eAAe,QAA2B,IAAc;CACtE,MAAM,QAAkC,CAAC;CACzC,KAAK,MAAM,YAAY,OAAO,OAAO,MAAM,GAAG;EAC5C,MAAM,UAAU,OAAO,KAAK,QAAQ;EACpC,KAAK,MAAM,SAAS,SAQlB,MAAM,SAPO,GAIV,QAAQ,sBAAsB,MAAM,WAAW,KAAK,SAAS,GAAG,CAAC,CACjE,IAAsB,CAAC,CACvB,KAAI,MAAK,EAAE,MACC;CAEnB;CAEA,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-sql.js","names":[
|
|
1
|
+
{"version":3,"file":"fetch-sql.js","names":[],"sources":["../../../../zqlite/src/fetch-sql.ts"],"sourcesContent":["import {assignProperty} from '../../shared/src/objects.ts';\nimport type {Ordering} from '../../zero-protocol/src/ast.ts';\nimport type {Row} from '../../zero-protocol/src/data.ts';\nimport type {SchemaValue} from '../../zero-schema/src/table-schema.ts';\nimport type {Constraint} from '../../zql/src/ivm/constraint.ts';\nimport type {\n FetchRequest,\n MultiConstraint,\n} from '../../zql/src/ivm/operator.ts';\nimport {format} from './internal/sql.ts';\nimport {\n Binding,\n buildSelectQueries,\n toSQLiteType,\n type NoSubqueryCondition,\n} from './query-builder.ts';\n\nexport type FetchSQL = {\n readonly text: string;\n readonly values: readonly unknown[];\n};\n\n/**\n * More shapes than a connection is expected to fetch. Past it the cache is\n * cleared, which bounds it if some fetch parameter that is part of the shape\n * (a `req.filter` that is not the same object every time, say) never repeats.\n */\nconst MAX_SHAPES = 256;\n\nconst filterIDs = new WeakMap<NoSubqueryCondition, number>();\nlet nextFilterID = 0;\n\n/**\n * Builds the SELECTs of {@link buildSelectQueries} for the fetches of one\n * connection, formatting the SQL text only once per fetch shape.\n *\n * Building and formatting the SQL is a fixed cost of every fetch that is\n * comparable to running the statement for the small fetches IVM does most.\n * The text depends only on the fetch's shape, though: which columns it\n * constrains, how many entries each multi-constraint has, its direction,\n * which columns of its start row are NULL, and its `req.filter`. The values\n * are bound to `?` placeholders, so a shape's text is built once with a\n * {@link Binding} in place of each value, and each fetch only reads its values\n * from those.\n */\nexport class FetchSQLCache {\n readonly #tableName: string;\n readonly #columns: Record<string, SchemaValue>;\n readonly #filters: NoSubqueryCondition | undefined;\n readonly #order: Ordering | undefined;\n readonly #templates = new Map<string, readonly FetchSQL[]>();\n\n constructor(\n tableName: string,\n columns: Record<string, SchemaValue>,\n filters: NoSubqueryCondition | undefined,\n order: Ordering | undefined,\n ) {\n this.#tableName = tableName;\n this.#columns = columns;\n this.#filters = filters;\n this.#order = order;\n }\n\n get(req: FetchRequest): FetchSQL[] {\n const key = this.#shapeKey(req);\n let templates = this.#templates.get(key);\n if (templates === undefined) {\n templates = this.#buildTemplates(req);\n if (this.#templates.size >= MAX_SHAPES) {\n this.#templates.clear();\n }\n this.#templates.set(key, templates);\n }\n return templates.map(({text, values}) => ({\n text,\n values: values.map(v => (v instanceof Binding ? v.get(req) : v)),\n }));\n }\n\n // Column names are never empty and never contain NUL, so terminating each\n // with NUL and each list with an extra NUL keeps distinct shapes distinct.\n #shapeKey(req: FetchRequest): string {\n const {constraint, multiConstraints, start, filter} = req;\n let key = req.reverse ? 'r' : 'f';\n if (constraint) {\n for (const k in constraint) {\n key += k + '\\0';\n }\n }\n key += '\\0';\n if (multiConstraints) {\n for (const mc of multiConstraints) {\n key += mc.length + '\\0';\n if (mc.length > 0) {\n for (const k in mc[0]) {\n key += k + '\\0';\n }\n }\n key += '\\0';\n }\n }\n key += '\\0';\n if (start) {\n key += start.basis;\n // Only the order's columns of the start row are read.\n for (const [field] of this.#order ?? []) {\n key += isNullish(start.row[field]) ? '0' : '1';\n }\n }\n key += '\\0';\n if (filter) {\n let id = filterIDs.get(filter);\n if (id === undefined) {\n id = nextFilterID++;\n filterIDs.set(filter, id);\n }\n key += id;\n }\n return key;\n }\n\n #buildTemplates(req: FetchRequest): FetchSQL[] {\n const columns = this.#columns;\n const binding = (\n get: (req: FetchRequest) => unknown,\n field: string,\n ): Binding => {\n const {type} = columns[field];\n return new Binding(req => toSQLiteType(get(req), type));\n };\n\n let constraint: Constraint | undefined;\n if (req.constraint) {\n const probe: Record<string, unknown> = {};\n for (const k in req.constraint) {\n assignProperty(\n probe,\n k,\n binding(req => req.constraint![k], k),\n );\n }\n constraint = probe as Constraint;\n }\n const multiConstraints = req.multiConstraints?.map(\n (mc, i): MultiConstraint =>\n mc.map((entry, j) => {\n const probe: Record<string, unknown> = {};\n for (const k in entry) {\n assignProperty(\n probe,\n k,\n binding(req => req.multiConstraints![i][j][k], k),\n );\n }\n return probe as Row;\n }),\n );\n let start: FetchRequest['start'];\n if (req.start) {\n const row: Record<string, unknown> = {};\n for (const [field] of this.#order ?? []) {\n assignProperty(\n row,\n field,\n isNullish(req.start.row[field])\n ? null\n : binding(req => req.start!.row[field], field),\n );\n }\n start = {basis: req.start.basis, row: row as Row};\n }\n\n return buildSelectQueries(\n this.#tableName,\n columns,\n constraint,\n this.#filters,\n this.#order,\n req.reverse,\n start,\n multiConstraints,\n req.filter,\n ).map(query => format(query));\n }\n}\n\nfunction isNullish(v: unknown): boolean {\n return v === null || v === undefined;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-usage.js","names":[],"sources":["../../../../zqlite/src/index-usage.ts"],"sourcesContent":["import SQLite3Database from '@rocicorp/zero-sqlite3';\nimport type {Statement} from './db.ts';\n\nlet uses = new Map<string, number>();\n\n/**\n * The table-valued function that the SQL of `IN` and `NOT IN` conditions reads\n * its values from (see `simpleConditionToSQL()` in `query-builder.ts`).\n */\nconst JSON_EACH = 'json_each';\n\n/**\n * Counts a run of `stmt`, a read of `table`, against each index of the table\n * that SQLite's plan for it read. Loops that read the table itself (a scan,\n * or a lookup by rowid), or the values of an `IN` (from `json_each`), are not\n * counted, and an index that more than one loop of the plan reads (e.g. for\n * an `OR` of two of its ranges) is counted once.\n *\n * The plan is read after every run rather than once per statement: SQLite\n * plans a statement again when a new binding can change the best plan, as it\n * can with `sqlite_stat4` statistics or for `LIKE`.\n */\nexport function recordIndexUsage(stmt: Statement, table: string): void {\n let counted: string[] | undefined;\n // Without SQLITE_SCANSTAT_COMPLEX, scanstatus lists only the loops, each of\n // which has the name of the index or table it reads, so the first missing\n // name is the end of the list.\n for (let i = 0; ; i++) {\n const name = stmt.scanStatus(i, SQLite3Database.SQLITE_SCANSTAT_NAME, 0);\n if (name === undefined) {\n return;\n }\n if (\n name === table ||\n counted?.includes(name) ||\n (name === JSON_EACH && readsJsonEach(stmt, i))\n ) {\n continue;\n }\n (counted ??= []).push(name);\n uses.set(name, (uses.get(name) ?? 0) + 1);\n }\n}\n\n/**\n * Whether loop `i` of `stmt` reads the values of `json_each`, rather than an\n * index that happens to have the same name.\n */\nfunction readsJsonEach(stmt: Statement, i: number): boolean {\n const explain = stmt.scanStatus(\n i,\n SQLite3Database.SQLITE_SCANSTAT_EXPLAIN,\n 0,\n );\n return explain?.startsWith(`SCAN ${JSON_EACH} VIRTUAL TABLE`) ?? false;\n}\n\n/**\n * Returns the runs recorded by {@link recordIndexUsage} in this process since\n * the last call, by the name of the index they read.\n */\nexport function takeIndexUsage(): Map<string, number> {\n const taken = uses;\n uses = new Map();\n return taken;\n}\n"],"mappings":";;AAGA,IAAI,uBAAO,IAAI,IAAoB;;;;;AAMnC,IAAM,YAAY;;;;;;;;;;;;AAalB,SAAgB,iBAAiB,MAAiB,OAAqB;CACrE,IAAI;CAIJ,KAAK,IAAI,IAAI,IAAK,KAAK;EACrB,MAAM,OAAO,KAAK,WAAW,GAAG,gBAAgB,sBAAsB,CAAC;EACvE,IAAI,SAAS,KAAA,GACX;EAEF,IACE,SAAS,SACT,SAAS,SAAS,IAAI,KACrB,SAAS,aAAa,cAAc,MAAM,CAAC,GAE5C;EAEF,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"index-usage.js","names":[],"sources":["../../../../zqlite/src/index-usage.ts"],"sourcesContent":["import SQLite3Database from '@rocicorp/zero-sqlite3';\nimport type {Statement} from './db.ts';\n\nlet uses = new Map<string, number>();\n\n/**\n * The table-valued function that the SQL of `IN` and `NOT IN` conditions reads\n * its values from (see `simpleConditionToSQL()` in `query-builder.ts`).\n */\nconst JSON_EACH = 'json_each';\n\n/**\n * Counts a run of `stmt`, a read of `table`, against each index of the table\n * that SQLite's plan for it read. Loops that read the table itself (a scan,\n * or a lookup by rowid), or the values of an `IN` (from `json_each`), are not\n * counted, and an index that more than one loop of the plan reads (e.g. for\n * an `OR` of two of its ranges) is counted once.\n *\n * The plan is read after every run rather than once per statement: SQLite\n * plans a statement again when a new binding can change the best plan, as it\n * can with `sqlite_stat4` statistics or for `LIKE`.\n */\nexport function recordIndexUsage(stmt: Statement, table: string): void {\n let counted: string[] | undefined;\n // Without SQLITE_SCANSTAT_COMPLEX, scanstatus lists only the loops, each of\n // which has the name of the index or table it reads, so the first missing\n // name is the end of the list.\n for (let i = 0; ; i++) {\n const name = stmt.scanStatus(i, SQLite3Database.SQLITE_SCANSTAT_NAME, 0);\n if (name === undefined) {\n return;\n }\n if (\n name === table ||\n counted?.includes(name) ||\n (name === JSON_EACH && readsJsonEach(stmt, i))\n ) {\n continue;\n }\n (counted ??= []).push(name);\n uses.set(name, (uses.get(name) ?? 0) + 1);\n }\n}\n\n/**\n * Whether loop `i` of `stmt` reads the values of `json_each`, rather than an\n * index that happens to have the same name.\n */\nfunction readsJsonEach(stmt: Statement, i: number): boolean {\n const explain = stmt.scanStatus(\n i,\n SQLite3Database.SQLITE_SCANSTAT_EXPLAIN,\n 0,\n );\n return explain?.startsWith(`SCAN ${JSON_EACH} VIRTUAL TABLE`) ?? false;\n}\n\n/**\n * Returns the runs recorded by {@link recordIndexUsage} in this process since\n * the last call, by the name of the index they read.\n */\nexport function takeIndexUsage(): Map<string, number> {\n const taken = uses;\n uses = new Map();\n return taken;\n}\n"],"mappings":";;AAGA,IAAI,uBAAO,IAAI,IAAoB;;;;;AAMnC,IAAM,YAAY;;;;;;;;;;;;AAalB,SAAgB,iBAAiB,MAAiB,OAAqB;CACrE,IAAI;CAIJ,KAAK,IAAI,IAAI,IAAK,KAAK;EACrB,MAAM,OAAO,KAAK,WAAW,GAAG,gBAAgB,sBAAsB,CAAC;EACvE,IAAI,SAAS,KAAA,GACX;EAEF,IACE,SAAS,SACT,SAAS,SAAS,IAAI,KACrB,SAAS,aAAa,cAAc,MAAM,CAAC,GAE5C;EAEF,CAAC,YAAY,CAAC,EAAA,CAAG,KAAK,IAAI;EAC1B,KAAK,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,KAAK,CAAC;CAC1C;AACF;;;;;AAMA,SAAS,cAAc,MAAiB,GAAoB;CAM1D,OALgB,KAAK,WACnB,GACA,gBAAgB,yBAChB,CAEK,CAAA,EAAS,WAAW,QAAQ,UAAU,eAAe,KAAK;AACnE;;;;;AAMA,SAAgB,iBAAsC;CACpD,MAAM,QAAQ;CACd,uBAAO,IAAI,IAAI;CACf,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-inline.js","names":[],"sources":["../../../../../zqlite/src/internal/sql-inline.ts"],"sourcesContent":["import {escapeSQLiteIdentifier} from '@databases/escape-identifier';\nimport type {FormatConfig} from '@databases/sql';\nimport type {SQLQuery} from '@databases/sql';\n\n/**\n * Escapes a SQLite string value by doubling single quotes.\n * SQLite uses single quotes for string literals and doubles them for escaping.\n */\nfunction escapeSQLiteString(str: string): string {\n return `'${str.replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Formats a value for inline inclusion in SQL (not as a placeholder).\n *\n * WARNING: This should ONLY be used for cost estimation in the query planner,\n * not for user-facing queries. All production queries must use parameterized\n * statements to prevent SQL injection.\n *\n * @param value The value to inline into SQL\n * @returns SQL literal representation of the value\n */\nfunction inlineValue(value: unknown): string {\n if (value === null) {\n return 'NULL';\n }\n if (typeof value === 'string') {\n return escapeSQLiteString(value);\n }\n if (typeof value === 'number') {\n return String(value);\n }\n if (typeof value === 'boolean') {\n // SQLite uses 1 and 0 for booleans\n return value ? '1' : '0';\n }\n if (Array.isArray(value)) {\n // For arrays, use JSON representation (same as query-builder.ts does for IN clauses)\n return escapeSQLiteString(JSON.stringify(value));\n }\n // For objects/other JSON types\n return escapeSQLiteString(JSON.stringify(value));\n}\n\n/**\n * Format configuration that inlines values directly into SQL instead of using placeholders.\n *\n * This is used ONLY for cost estimation in the SQLite cost model, where we want SQLite's\n * query planner to see actual values to make better decisions about index usage and query plans.\n *\n * Production code must use the standard parameterized format from sql.ts.\n */\nconst sqliteInlineFormat: FormatConfig = {\n escapeIdentifier: str => escapeSQLiteIdentifier(str),\n formatValue: value =>\n // undefined is our signal to use a placeholder\n // IMPORTANT. Changing this will break the planner as it will assume `NULL`\n // for constraints!\n value === undefined\n ? {\n placeholder: '?',\n value,\n }\n : {\n placeholder: inlineValue(value),\n value: undefined, // No binding needed since value is inlined\n },\n};\n\n/**\n * Compiles a SQL query with values inlined directly into the SQL string.\n *\n * WARNING: This should ONLY be used for cost estimation in the query planner.\n * Never use this for user-facing queries - always use the standard `compile()`\n * function from sql.ts which uses parameterized queries.\n *\n * @param sql The SQL query to compile\n * @returns SQL string with values inlined\n */\nexport function compileInline(sql: SQLQuery): string {\n return sql.format(sqliteInlineFormat).text;\n}\n"],"mappings":";;;;;;AAQA,SAAS,mBAAmB,KAAqB;CAC/C,OAAO,IAAI,IAAI,QAAQ,MAAM,IAAI,EAAE;AACrC;;;;;;;;;;;AAYA,SAAS,YAAY,OAAwB;CAC3C,IAAI,UAAU,MACZ,OAAO;CAET,IAAI,OAAO,UAAU,UACnB,OAAO,mBAAmB,KAAK;CAEjC,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,KAAK;CAErB,IAAI,OAAO,UAAU,WAEnB,OAAO,QAAQ,MAAM;CAEvB,IAAI,MAAM,QAAQ,KAAK,GAErB,OAAO,mBAAmB,KAAK,UAAU,KAAK,CAAC;CAGjD,OAAO,mBAAmB,KAAK,UAAU,KAAK,CAAC;AACjD;;;;;;;;;AAUA,IAAM,qBAAmC;CACvC,mBAAkB,QAAO,uBAAuB,GAAG;CACnD,cAAa,UAIX,UAAU,KAAA,IACN;EACE,aAAa;EACb;CACF,IACA;EACE,aAAa,YAAY,KAAK;EAC9B,OAAO,KAAA;CACT;AACR;;;;;;;;;;;AAYA,SAAgB,cAAc,KAAuB;CACnD,OAAO,IAAI,OAAO,kBAAkB,
|
|
1
|
+
{"version":3,"file":"sql-inline.js","names":[],"sources":["../../../../../zqlite/src/internal/sql-inline.ts"],"sourcesContent":["import {escapeSQLiteIdentifier} from '@databases/escape-identifier';\nimport type {FormatConfig} from '@databases/sql';\nimport type {SQLQuery} from '@databases/sql';\n\n/**\n * Escapes a SQLite string value by doubling single quotes.\n * SQLite uses single quotes for string literals and doubles them for escaping.\n */\nfunction escapeSQLiteString(str: string): string {\n return `'${str.replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Formats a value for inline inclusion in SQL (not as a placeholder).\n *\n * WARNING: This should ONLY be used for cost estimation in the query planner,\n * not for user-facing queries. All production queries must use parameterized\n * statements to prevent SQL injection.\n *\n * @param value The value to inline into SQL\n * @returns SQL literal representation of the value\n */\nfunction inlineValue(value: unknown): string {\n if (value === null) {\n return 'NULL';\n }\n if (typeof value === 'string') {\n return escapeSQLiteString(value);\n }\n if (typeof value === 'number') {\n return String(value);\n }\n if (typeof value === 'boolean') {\n // SQLite uses 1 and 0 for booleans\n return value ? '1' : '0';\n }\n if (Array.isArray(value)) {\n // For arrays, use JSON representation (same as query-builder.ts does for IN clauses)\n return escapeSQLiteString(JSON.stringify(value));\n }\n // For objects/other JSON types\n return escapeSQLiteString(JSON.stringify(value));\n}\n\n/**\n * Format configuration that inlines values directly into SQL instead of using placeholders.\n *\n * This is used ONLY for cost estimation in the SQLite cost model, where we want SQLite's\n * query planner to see actual values to make better decisions about index usage and query plans.\n *\n * Production code must use the standard parameterized format from sql.ts.\n */\nconst sqliteInlineFormat: FormatConfig = {\n escapeIdentifier: str => escapeSQLiteIdentifier(str),\n formatValue: value =>\n // undefined is our signal to use a placeholder\n // IMPORTANT. Changing this will break the planner as it will assume `NULL`\n // for constraints!\n value === undefined\n ? {\n placeholder: '?',\n value,\n }\n : {\n placeholder: inlineValue(value),\n value: undefined, // No binding needed since value is inlined\n },\n};\n\n/**\n * Compiles a SQL query with values inlined directly into the SQL string.\n *\n * WARNING: This should ONLY be used for cost estimation in the query planner.\n * Never use this for user-facing queries - always use the standard `compile()`\n * function from sql.ts which uses parameterized queries.\n *\n * @param sql The SQL query to compile\n * @returns SQL string with values inlined\n */\nexport function compileInline(sql: SQLQuery): string {\n return sql.format(sqliteInlineFormat).text;\n}\n"],"mappings":";;;;;;AAQA,SAAS,mBAAmB,KAAqB;CAC/C,OAAO,IAAI,IAAI,QAAQ,MAAM,IAAI,EAAE;AACrC;;;;;;;;;;;AAYA,SAAS,YAAY,OAAwB;CAC3C,IAAI,UAAU,MACZ,OAAO;CAET,IAAI,OAAO,UAAU,UACnB,OAAO,mBAAmB,KAAK;CAEjC,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,KAAK;CAErB,IAAI,OAAO,UAAU,WAEnB,OAAO,QAAQ,MAAM;CAEvB,IAAI,MAAM,QAAQ,KAAK,GAErB,OAAO,mBAAmB,KAAK,UAAU,KAAK,CAAC;CAGjD,OAAO,mBAAmB,KAAK,UAAU,KAAK,CAAC;AACjD;;;;;;;;;AAUA,IAAM,qBAAmC;CACvC,mBAAkB,QAAO,uBAAuB,GAAG;CACnD,cAAa,UAIX,UAAU,KAAA,IACN;EACE,aAAa;EACb;CACF,IACA;EACE,aAAa,YAAY,KAAK;EAC9B,OAAO,KAAA;CACT;AACR;;;;;;;;;;;AAYA,SAAgB,cAAc,KAAuB;CACnD,OAAO,IAAI,OAAO,kBAAkB,CAAC,CAAC;AACxC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.js","names":[],"sources":["../../../../../zqlite/src/internal/sql.ts"],"sourcesContent":["import {escapeSQLiteIdentifier} from '@databases/escape-identifier';\nimport type {FormatConfig, SQLQuery} from '@databases/sql';\nimport sql from '@databases/sql';\n\nconst sqliteFormat: FormatConfig = {\n escapeIdentifier: str => escapeSQLiteIdentifier(str),\n formatValue: value => ({placeholder: '?', value}),\n};\n\nexport function compile(sql: SQLQuery): string {\n return sql.format(sqliteFormat).text;\n}\n\nexport function format(sql: SQLQuery) {\n return sql.format(sqliteFormat);\n}\n\nexport {sql};\n"],"mappings":";;;AAIA,IAAM,eAA6B;CACjC,mBAAkB,QAAO,uBAAuB,GAAG;CACnD,cAAa,WAAU;EAAC,aAAa;EAAK;CAAK;AACjD;AAEA,SAAgB,QAAQ,KAAuB;CAC7C,OAAO,IAAI,OAAO,YAAY,
|
|
1
|
+
{"version":3,"file":"sql.js","names":[],"sources":["../../../../../zqlite/src/internal/sql.ts"],"sourcesContent":["import {escapeSQLiteIdentifier} from '@databases/escape-identifier';\nimport type {FormatConfig, SQLQuery} from '@databases/sql';\nimport sql from '@databases/sql';\n\nconst sqliteFormat: FormatConfig = {\n escapeIdentifier: str => escapeSQLiteIdentifier(str),\n formatValue: value => ({placeholder: '?', value}),\n};\n\nexport function compile(sql: SQLQuery): string {\n return sql.format(sqliteFormat).text;\n}\n\nexport function format(sql: SQLQuery) {\n return sql.format(sqliteFormat);\n}\n\nexport {sql};\n"],"mappings":";;;AAIA,IAAM,eAA6B;CACjC,mBAAkB,QAAO,uBAAuB,GAAG;CACnD,cAAa,WAAU;EAAC,aAAa;EAAK;CAAK;AACjD;AAEA,SAAgB,QAAQ,KAAuB;CAC7C,OAAO,IAAI,OAAO,YAAY,CAAC,CAAC;AAClC;AAEA,SAAgB,OAAO,KAAe;CACpC,OAAO,IAAI,OAAO,YAAY;AAChC"}
|
|
@@ -74,6 +74,13 @@ export declare class StatementCache {
|
|
|
74
74
|
* @returns
|
|
75
75
|
*/
|
|
76
76
|
get(sql: string): CachedStatement;
|
|
77
|
+
/**
|
|
78
|
+
* Like {@link get}, but keys the statement by `sql` exactly as given,
|
|
79
|
+
* without normalizing its whitespace. This is for callers that pass the
|
|
80
|
+
* same text for a statement every time, such as the SQL of a fetch shape,
|
|
81
|
+
* which then skip the normalization on every call.
|
|
82
|
+
*/
|
|
83
|
+
getExact(sql: string): CachedStatement;
|
|
77
84
|
/**
|
|
78
85
|
* Handles `get` and `return` for the caller by invoking them before
|
|
79
86
|
* and after the callback.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statement-cache.d.ts","sourceRoot":"","sources":["../../../../../zqlite/src/internal/statement-cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAE,SAAS,EAAC,MAAM,UAAU,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,cAAc;;IAUzB;;;;;OAKG;IACH,YAAY,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,MAAsC,EAIxE;IAGD,IAAI,IAAI,WAEP;IAGD,IAAI,OAAO,WAEV;IAED,IAAI,CAAC,CAAC,EAAE,MAAM,QAOb;IAED;;;;;;;;;;;;OAYG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"statement-cache.d.ts","sourceRoot":"","sources":["../../../../../zqlite/src/internal/statement-cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAE,SAAS,EAAC,MAAM,UAAU,CAAC;AAElD,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,cAAc;;IAUzB;;;;;OAKG;IACH,YAAY,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAE,MAAsC,EAIxE;IAGD,IAAI,IAAI,WAEP;IAGD,IAAI,OAAO,WAEV;IAED,IAAI,CAAC,CAAC,EAAE,MAAM,QAOb;IAED;;;;;;;;;;;;OAYG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAEhC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAerC;IAED;;;OAGG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,CAAC,KAOxD;IAED;;;;;;OAMG;IACH,MAAM,CAAC,SAAS,EAAE,eAAe,QAiBhC;CAYF"}
|
|
@@ -85,7 +85,15 @@ var StatementCache = class {
|
|
|
85
85
|
* @returns
|
|
86
86
|
*/
|
|
87
87
|
get(sql) {
|
|
88
|
-
|
|
88
|
+
return this.getExact(normalizeWhitespace(sql));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Like {@link get}, but keys the statement by `sql` exactly as given,
|
|
92
|
+
* without normalizing its whitespace. This is for callers that pass the
|
|
93
|
+
* same text for a statement every time, such as the SQL of a fetch shape,
|
|
94
|
+
* which then skip the normalization on every call.
|
|
95
|
+
*/
|
|
96
|
+
getExact(sql) {
|
|
89
97
|
const statements = this.#cache.get(sql);
|
|
90
98
|
if (statements && statements.length > 0) {
|
|
91
99
|
const statement = statements.pop();
|
|
@@ -97,10 +105,9 @@ var StatementCache = class {
|
|
|
97
105
|
statement
|
|
98
106
|
};
|
|
99
107
|
}
|
|
100
|
-
const statement = this.#db.prepare(sql);
|
|
101
108
|
return {
|
|
102
109
|
sql,
|
|
103
|
-
statement
|
|
110
|
+
statement: this.#db.prepare(sql)
|
|
104
111
|
};
|
|
105
112
|
}
|
|
106
113
|
/**
|
|
@@ -145,6 +152,6 @@ function normalizeWhitespace(sql) {
|
|
|
145
152
|
return sql.replaceAll(/\s+/g, " ");
|
|
146
153
|
}
|
|
147
154
|
//#endregion
|
|
148
|
-
export { StatementCache };
|
|
155
|
+
export { DEFAULT_MAX_CACHED_STATEMENTS, StatementCache };
|
|
149
156
|
|
|
150
157
|
//# sourceMappingURL=statement-cache.js.map
|