@rocicorp/zero 1.12.0-canary.2 → 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 +2 -1
- 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 +9 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +17 -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.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +2 -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 +1 -1
- 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.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +2 -2
- 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.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +10 -8
- 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.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +3 -3
- 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.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +8 -8
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +3 -2
- 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.d.ts +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +13 -10
- 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 +4 -2
- 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 +18 -0
- 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 +70 -23
- 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 +12 -4
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +11 -7
- 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 +2 -3
- 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 +2 -2
- 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.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.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.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 +2 -4
- 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 +3 -5
- 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 +195 -26
- 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.d.ts +27 -0
- package/out/zqlite/src/fetch-sql.d.ts.map +1 -0
- package/out/zqlite/src/fetch-sql.js +112 -0
- package/out/zqlite/src/fetch-sql.js.map +1 -0
- 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.d.ts +11 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +22 -7
- 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 +20 -2
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +73 -39
- 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
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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Ordering } from '../../zero-protocol/src/ast.ts';
|
|
2
|
+
import type { SchemaValue } from '../../zero-schema/src/table-schema.ts';
|
|
3
|
+
import type { FetchRequest } from '../../zql/src/ivm/operator.ts';
|
|
4
|
+
import { type NoSubqueryCondition } from './query-builder.ts';
|
|
5
|
+
export type FetchSQL = {
|
|
6
|
+
readonly text: string;
|
|
7
|
+
readonly values: readonly unknown[];
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Builds the SELECTs of {@link buildSelectQueries} for the fetches of one
|
|
11
|
+
* connection, formatting the SQL text only once per fetch shape.
|
|
12
|
+
*
|
|
13
|
+
* Building and formatting the SQL is a fixed cost of every fetch that is
|
|
14
|
+
* comparable to running the statement for the small fetches IVM does most.
|
|
15
|
+
* The text depends only on the fetch's shape, though: which columns it
|
|
16
|
+
* constrains, how many entries each multi-constraint has, its direction,
|
|
17
|
+
* which columns of its start row are NULL, and its `req.filter`. The values
|
|
18
|
+
* are bound to `?` placeholders, so a shape's text is built once with a
|
|
19
|
+
* {@link Binding} in place of each value, and each fetch only reads its values
|
|
20
|
+
* from those.
|
|
21
|
+
*/
|
|
22
|
+
export declare class FetchSQLCache {
|
|
23
|
+
#private;
|
|
24
|
+
constructor(tableName: string, columns: Record<string, SchemaValue>, filters: NoSubqueryCondition | undefined, order: Ordering | undefined);
|
|
25
|
+
get(req: FetchRequest): FetchSQL[];
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=fetch-sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-sql.d.ts","sourceRoot":"","sources":["../../../../zqlite/src/fetch-sql.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gCAAgC,CAAC;AAE7D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uCAAuC,CAAC;AAEvE,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC,CAAC;AAYF;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAa;;IAOxB,YACE,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACpC,OAAO,EAAE,mBAAmB,GAAG,SAAS,EACxC,KAAK,EAAE,QAAQ,GAAG,SAAS,EAM5B;IAED,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,QAAQ,EAAE,CAcjC;CA2GF"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { assignProperty } from "../../shared/src/objects.js";
|
|
2
|
+
import { format } from "./internal/sql.js";
|
|
3
|
+
import { Binding, buildSelectQueries, toSQLiteType } from "./query-builder.js";
|
|
4
|
+
//#region ../zqlite/src/fetch-sql.ts
|
|
5
|
+
/**
|
|
6
|
+
* More shapes than a connection is expected to fetch. Past it the cache is
|
|
7
|
+
* cleared, which bounds it if some fetch parameter that is part of the shape
|
|
8
|
+
* (a `req.filter` that is not the same object every time, say) never repeats.
|
|
9
|
+
*/
|
|
10
|
+
var MAX_SHAPES = 256;
|
|
11
|
+
var filterIDs = /* @__PURE__ */ new WeakMap();
|
|
12
|
+
var nextFilterID = 0;
|
|
13
|
+
/**
|
|
14
|
+
* Builds the SELECTs of {@link buildSelectQueries} for the fetches of one
|
|
15
|
+
* connection, formatting the SQL text only once per fetch shape.
|
|
16
|
+
*
|
|
17
|
+
* Building and formatting the SQL is a fixed cost of every fetch that is
|
|
18
|
+
* comparable to running the statement for the small fetches IVM does most.
|
|
19
|
+
* The text depends only on the fetch's shape, though: which columns it
|
|
20
|
+
* constrains, how many entries each multi-constraint has, its direction,
|
|
21
|
+
* which columns of its start row are NULL, and its `req.filter`. The values
|
|
22
|
+
* are bound to `?` placeholders, so a shape's text is built once with a
|
|
23
|
+
* {@link Binding} in place of each value, and each fetch only reads its values
|
|
24
|
+
* from those.
|
|
25
|
+
*/
|
|
26
|
+
var FetchSQLCache = class {
|
|
27
|
+
#tableName;
|
|
28
|
+
#columns;
|
|
29
|
+
#filters;
|
|
30
|
+
#order;
|
|
31
|
+
#templates = /* @__PURE__ */ new Map();
|
|
32
|
+
constructor(tableName, columns, filters, order) {
|
|
33
|
+
this.#tableName = tableName;
|
|
34
|
+
this.#columns = columns;
|
|
35
|
+
this.#filters = filters;
|
|
36
|
+
this.#order = order;
|
|
37
|
+
}
|
|
38
|
+
get(req) {
|
|
39
|
+
const key = this.#shapeKey(req);
|
|
40
|
+
let templates = this.#templates.get(key);
|
|
41
|
+
if (templates === void 0) {
|
|
42
|
+
templates = this.#buildTemplates(req);
|
|
43
|
+
if (this.#templates.size >= MAX_SHAPES) this.#templates.clear();
|
|
44
|
+
this.#templates.set(key, templates);
|
|
45
|
+
}
|
|
46
|
+
return templates.map(({ text, values }) => ({
|
|
47
|
+
text,
|
|
48
|
+
values: values.map((v) => v instanceof Binding ? v.get(req) : v)
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
#shapeKey(req) {
|
|
52
|
+
const { constraint, multiConstraints, start, filter } = req;
|
|
53
|
+
let key = req.reverse ? "r" : "f";
|
|
54
|
+
if (constraint) for (const k in constraint) key += k + "\0";
|
|
55
|
+
key += "\0";
|
|
56
|
+
if (multiConstraints) for (const mc of multiConstraints) {
|
|
57
|
+
key += mc.length + "\0";
|
|
58
|
+
if (mc.length > 0) for (const k in mc[0]) key += k + "\0";
|
|
59
|
+
key += "\0";
|
|
60
|
+
}
|
|
61
|
+
key += "\0";
|
|
62
|
+
if (start) {
|
|
63
|
+
key += start.basis;
|
|
64
|
+
for (const [field] of this.#order ?? []) key += isNullish(start.row[field]) ? "0" : "1";
|
|
65
|
+
}
|
|
66
|
+
key += "\0";
|
|
67
|
+
if (filter) {
|
|
68
|
+
let id = filterIDs.get(filter);
|
|
69
|
+
if (id === void 0) {
|
|
70
|
+
id = nextFilterID++;
|
|
71
|
+
filterIDs.set(filter, id);
|
|
72
|
+
}
|
|
73
|
+
key += id;
|
|
74
|
+
}
|
|
75
|
+
return key;
|
|
76
|
+
}
|
|
77
|
+
#buildTemplates(req) {
|
|
78
|
+
const columns = this.#columns;
|
|
79
|
+
const binding = (get, field) => {
|
|
80
|
+
const { type } = columns[field];
|
|
81
|
+
return new Binding((req) => toSQLiteType(get(req), type));
|
|
82
|
+
};
|
|
83
|
+
let constraint;
|
|
84
|
+
if (req.constraint) {
|
|
85
|
+
const probe = {};
|
|
86
|
+
for (const k in req.constraint) assignProperty(probe, k, binding((req) => req.constraint[k], k));
|
|
87
|
+
constraint = probe;
|
|
88
|
+
}
|
|
89
|
+
const multiConstraints = req.multiConstraints?.map((mc, i) => mc.map((entry, j) => {
|
|
90
|
+
const probe = {};
|
|
91
|
+
for (const k in entry) assignProperty(probe, k, binding((req) => req.multiConstraints[i][j][k], k));
|
|
92
|
+
return probe;
|
|
93
|
+
}));
|
|
94
|
+
let start;
|
|
95
|
+
if (req.start) {
|
|
96
|
+
const row = {};
|
|
97
|
+
for (const [field] of this.#order ?? []) assignProperty(row, field, isNullish(req.start.row[field]) ? null : binding((req) => req.start.row[field], field));
|
|
98
|
+
start = {
|
|
99
|
+
basis: req.start.basis,
|
|
100
|
+
row
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return buildSelectQueries(this.#tableName, columns, constraint, this.#filters, this.#order, req.reverse, start, multiConstraints, req.filter).map((query) => format(query));
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
function isNullish(v) {
|
|
107
|
+
return v === null || v === void 0;
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
export { FetchSQLCache };
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=fetch-sql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statement-cache.js","names":[
|
|
1
|
+
{"version":3,"file":"statement-cache.js","names":[],"sources":["../../../../../zqlite/src/internal/statement-cache.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Database, Statement} from '../db.ts';\n\nexport type CachedStatementMap = Map<string, Statement[]>;\nexport type CachedStatement = {\n sql: string;\n statement: Statement;\n};\n\n/**\n * The default maximum number of statements retained by a StatementCache.\n *\n * Each cached statement holds a native `sqlite3_stmt` handle (prepared\n * bytecode + SQLite-side memory), so the cache must be bounded. The bound\n * needs enough headroom for callers with a large working set of distinct\n * SQL — e.g. the replication change-processor prepares several statements\n * per table (with additional variants for partial-column updates) through\n * a single cache — while still capping growth from unbounded key spaces\n * such as client-influenced query shapes.\n */\nexport const DEFAULT_MAX_CACHED_STATEMENTS = 1_000;\n\n/**\n * SQLite statement preparation isn't cheap as it involves evaluating possible\n * query plans and picking the best one (in addition to parsing the SQL).\n *\n * This statement cache prevents the need to re-prepare the same statement\n * multiple times.\n *\n * One extra wrinkle is that a single statement cannot be used by multiple\n * callers at the same time. As in, we can't `iterate` the same statement\n * many times concurrently.\n *\n * Given that, statements are removed from the cache while in use.\n * - `get` removes the statement from the cache\n * - `return` adds it back.\n *\n * If a request for the same sql is made while a\n * statement is gotten, a new statement will be prepared.\n * Both statements can be returned to the cache even though they both\n * serve the same SQL. Having both copies returned to the cache allows\n * the cache to serve multiple callers concurrently in the future.\n *\n * It is not an error to fail to call `return` on a statement.\n * Failing to call return will only prevent the statement from being reused\n * by other callers. It will not cause a resource leak.\n *\n * The cache is bounded: it retains at most `maxSize` statements, evicting\n * the least recently used statements when the bound is exceeded. Only idle\n * (returned) statements are ever evicted — statements checked out via `get`\n * are not in the cache and thus never touched by eviction. Evicting a\n * statement drops the cache's reference to it; the native `sqlite3_stmt`\n * handle is finalized when the Statement object is garbage collected.\n */\nexport class StatementCache {\n // Map insertion order doubles as recency order: entries are re-inserted\n // on every `get` hit and `return`, so the first entry in the map is the\n // least recently used. Within an entry's array, the first statement is\n // the least recently returned.\n #cache: CachedStatementMap = new Map<string, Statement[]>();\n readonly #db: Database;\n readonly #maxSize: number;\n #size: number = 0;\n\n /**\n * The db connection used to prepare the statement.\n * It is an error to use a statement prepared on one connection with another connection.\n * @param db\n * @param maxSize the maximum number of statements to retain in the cache.\n */\n constructor(db: Database, maxSize: number = DEFAULT_MAX_CACHED_STATEMENTS) {\n assert(maxSize >= 0, 'maxSize must not be negative');\n this.#db = db;\n this.#maxSize = maxSize;\n }\n\n // the number of statements in the cache\n get size() {\n return this.#size;\n }\n\n // the maximum number of statements the cache will retain\n get maxSize() {\n return this.#maxSize;\n }\n\n drop(n: number) {\n assert(n >= 0, 'Cannot drop a negative number of items');\n assert(n <= this.#size, 'Cannot drop more items than are in the cache');\n\n for (let i = 0; i < n; i++) {\n this.#evictLeastRecentlyUsed();\n }\n }\n\n /**\n * Prepares a statement for the given sql unless one is already cached.\n * If one is cached, it is removed from the cache and returned.\n *\n * Since `get` removes the item from the cache it is not an error to fail to call\n * `return`. The gotten statement will be correctly garbage collected.\n *\n * When a gotten statement is not returned, future calls to\n * `get` with the same `sql` will prepare a new statement.\n *\n * @param sql\n * @returns\n */\n get(sql: string): CachedStatement {\n return this.getExact(normalizeWhitespace(sql));\n }\n\n /**\n * Like {@link get}, but keys the statement by `sql` exactly as given,\n * without normalizing its whitespace. This is for callers that pass the\n * same text for a statement every time, such as the SQL of a fetch shape,\n * which then skip the normalization on every call.\n */\n getExact(sql: string): CachedStatement {\n const statements = this.#cache.get(sql);\n if (statements && statements.length > 0) {\n const statement = statements.pop()!;\n this.#size--;\n this.#cache.delete(sql);\n if (statements.length > 0) {\n // Re-insert so the remaining statements for this sql are marked\n // as most recently used.\n this.#cache.set(sql, statements);\n }\n return {sql, statement};\n }\n const statement = this.#db.prepare(sql);\n return {sql, statement};\n }\n\n /**\n * Handles `get` and `return` for the caller by invoking them before\n * and after the callback.\n */\n use<T>(sql: string, cb: (statement: CachedStatement) => T) {\n const statement = this.get(sql);\n try {\n return cb(statement);\n } finally {\n this.return(statement);\n }\n }\n\n /**\n * Add a statement back to the cache so someone else can use it later.\n *\n * If this pushes the cache over its maximum size, the least recently\n * used statements are evicted.\n * @param statement\n */\n return(statement: CachedStatement) {\n const {sql} = statement;\n let statements = this.#cache.get(sql);\n if (statements === undefined) {\n statements = [];\n } else {\n // Delete so the re-insert below moves this sql to the most recently\n // used position.\n this.#cache.delete(sql);\n }\n statements.push(statement.statement);\n this.#cache.set(sql, statements);\n this.#size++;\n\n while (this.#size > this.#maxSize) {\n this.#evictLeastRecentlyUsed();\n }\n }\n\n #evictLeastRecentlyUsed() {\n const lru = this.#cache.entries().next();\n assert(!lru.done, 'Cannot evict from an empty cache');\n const [sql, statements] = lru.value;\n statements.shift();\n this.#size--;\n if (statements.length === 0) {\n this.#cache.delete(sql);\n }\n }\n}\n\nfunction normalizeWhitespace(sql: string) {\n return sql.replaceAll(/\\s+/g, ' ');\n}\n"],"mappings":";;;;;;;;;;;;;AAoBA,IAAa,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkC7C,IAAa,iBAAb,MAA4B;CAK1B,yBAA6B,IAAI,IAAyB;CAC1D;CACA;CACA,QAAgB;;;;;;;CAQhB,YAAY,IAAc,UAAkB,+BAA+B;EACzE,OAAO,WAAW,GAAG,8BAA8B;EACnD,KAAK,MAAM;EACX,KAAK,WAAW;CAClB;CAGA,IAAI,OAAO;EACT,OAAO,KAAK;CACd;CAGA,IAAI,UAAU;EACZ,OAAO,KAAK;CACd;CAEA,KAAK,GAAW;EACd,OAAO,KAAK,GAAG,wCAAwC;EACvD,OAAO,KAAK,KAAK,OAAO,8CAA8C;EAEtE,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,KAAK,wBAAwB;CAEjC;;;;;;;;;;;;;;CAeA,IAAI,KAA8B;EAChC,OAAO,KAAK,SAAS,oBAAoB,GAAG,CAAC;CAC/C;;;;;;;CAQA,SAAS,KAA8B;EACrC,MAAM,aAAa,KAAK,OAAO,IAAI,GAAG;EACtC,IAAI,cAAc,WAAW,SAAS,GAAG;GACvC,MAAM,YAAY,WAAW,IAAI;GACjC,KAAK;GACL,KAAK,OAAO,OAAO,GAAG;GACtB,IAAI,WAAW,SAAS,GAGtB,KAAK,OAAO,IAAI,KAAK,UAAU;GAEjC,OAAO;IAAC;IAAK;GAAS;EACxB;EAEA,OAAO;GAAC;GAAK,WADK,KAAK,IAAI,QAAQ,GACtB;EAAS;CACxB;;;;;CAMA,IAAO,KAAa,IAAuC;EACzD,MAAM,YAAY,KAAK,IAAI,GAAG;EAC9B,IAAI;GACF,OAAO,GAAG,SAAS;EACrB,UAAU;GACR,KAAK,OAAO,SAAS;EACvB;CACF;;;;;;;;CASA,OAAO,WAA4B;EACjC,MAAM,EAAC,QAAO;EACd,IAAI,aAAa,KAAK,OAAO,IAAI,GAAG;EACpC,IAAI,eAAe,KAAA,GACjB,aAAa,CAAC;OAId,KAAK,OAAO,OAAO,GAAG;EAExB,WAAW,KAAK,UAAU,SAAS;EACnC,KAAK,OAAO,IAAI,KAAK,UAAU;EAC/B,KAAK;EAEL,OAAO,KAAK,QAAQ,KAAK,UACvB,KAAK,wBAAwB;CAEjC;CAEA,0BAA0B;EACxB,MAAM,MAAM,KAAK,OAAO,QAAQ,CAAC,CAAC,KAAK;EACvC,OAAO,CAAC,IAAI,MAAM,kCAAkC;EACpD,MAAM,CAAC,KAAK,cAAc,IAAI;EAC9B,WAAW,MAAM;EACjB,KAAK;EACL,IAAI,WAAW,WAAW,GACxB,KAAK,OAAO,OAAO,GAAG;CAE1B;AACF;AAEA,SAAS,oBAAoB,KAAa;CACxC,OAAO,IAAI,WAAW,QAAQ,GAAG;AACnC"}
|