@rocicorp/zero 1.10.0-canary.21 → 1.10.0-canary.23
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/analyze-query/src/bin-analyze.js +1 -1
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/replicache/src/dag/gc.d.ts.map +1 -1
- package/out/replicache/src/dag/gc.js +2 -1
- package/out/replicache/src/dag/gc.js.map +1 -1
- package/out/replicache/src/dag/invalid-ref-count-error.d.ts +12 -0
- package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +1 -0
- package/out/replicache/src/dag/invalid-ref-count-error.js +19 -0
- package/out/replicache/src/dag/invalid-ref-count-error.js.map +1 -0
- package/out/replicache/src/dag/store-impl.d.ts +12 -2
- package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
- package/out/replicache/src/dag/store-impl.js +22 -8
- package/out/replicache/src/dag/store-impl.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts.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-with-mem-fallback.d.ts +15 -5
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +1 -1
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js +25 -25
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +1 -1
- package/out/replicache/src/kv/idb-store.d.ts +9 -0
- package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
- package/out/replicache/src/kv/idb-store.js +14 -2
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-store.d.ts +1 -0
- package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
- package/out/replicache/src/kv/mem-store.js +3 -0
- package/out/replicache/src/kv/mem-store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts +2 -1
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +6 -1
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/store.d.ts +6 -0
- package/out/replicache/src/kv/store.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +10 -5
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +16 -9
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +14 -3
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +104 -9
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/shared/src/arrays.js +1 -15
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/hash.d.ts +1 -0
- package/out/shared/src/hash.d.ts.map +1 -1
- package/out/shared/src/hash.js +10 -28
- package/out/shared/src/hash.js.map +1 -1
- package/out/shared/src/iterables.d.ts +2 -0
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +18 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/json.d.ts.map +1 -1
- package/out/shared/src/json.js +2 -2
- package/out/shared/src/json.js.map +1 -1
- package/out/shared/src/ring-buffer.d.ts +8 -0
- package/out/shared/src/ring-buffer.d.ts.map +1 -1
- package/out/shared/src/ring-buffer.js +22 -1
- package/out/shared/src/ring-buffer.js.map +1 -1
- package/out/shared/src/xxhash32.d.ts +36 -0
- package/out/shared/src/xxhash32.d.ts.map +1 -0
- package/out/shared/src/xxhash32.js +51 -0
- package/out/shared/src/xxhash32.js.map +1 -0
- package/out/z2s/src/compiler.js +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +8 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +28 -1
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +11 -3
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +18 -2
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +23 -9
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/main.js +8 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/mutator.js +2 -0
- package/out/zero-cache/src/server/mutator.js.map +1 -1
- package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -0
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/server/replicator.js +2 -0
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.js +3 -0
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +2 -0
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
- package/out/zero-cache/src/services/analyze.js +3 -2
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +14 -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.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +15 -3
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +3 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +3 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +5 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +7 -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/profz.d.ts +7 -0
- package/out/zero-cache/src/services/profz.d.ts.map +1 -0
- package/out/zero-cache/src/services/profz.js +103 -0
- package/out/zero-cache/src/services/profz.js.map +1 -0
- package/out/zero-cache/src/services/run-ast.d.ts +12 -0
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +27 -15
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/runner.d.ts.map +1 -1
- package/out/zero-cache/src/services/runner.js +1 -1
- package/out/zero-cache/src/services/runner.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +45 -0
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +133 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +14 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +30 -4
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +33 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js +62 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +51 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +78 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +2 -2
- 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 +2 -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 +33 -18
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.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/snapshotter.d.ts +4 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +9 -3
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -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 +470 -90
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/processes.d.ts +32 -0
- package/out/zero-cache/src/types/processes.d.ts.map +1 -1
- package/out/zero-cache/src/types/processes.js +43 -4
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/profiler.d.ts +12 -0
- package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
- package/out/zero-cache/src/types/profiler.js +46 -1
- package/out/zero-cache/src/types/profiler.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 +21 -16
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +10 -1
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +20 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +32 -14
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
- package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-status-enum.js +3 -1
- package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts +6 -0
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +2 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.d.ts +22 -12
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +92 -25
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/custom.js +2 -2
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/error.js +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +20 -3
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +2 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +3 -0
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.d.ts +2 -0
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +48 -9
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-rep.js +1 -1
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +18 -3
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +61 -14
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/types/query-result.d.ts +2 -0
- package/out/zero-client/src/types/query-result.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.d.ts +64 -1
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +223 -51
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/error.d.ts +1 -1
- package/out/zero-protocol/src/query-hash-visitor.d.ts +81 -0
- package/out/zero-protocol/src/query-hash-visitor.d.ts.map +1 -0
- package/out/zero-protocol/src/query-hash-visitor.js +324 -0
- package/out/zero-protocol/src/query-hash-visitor.js.map +1 -0
- package/out/zero-protocol/src/query-hash.d.ts +7 -2
- package/out/zero-protocol/src/query-hash.d.ts.map +1 -1
- package/out/zero-protocol/src/query-hash.js +12 -9
- package/out/zero-protocol/src/query-hash.js.map +1 -1
- package/out/zero-react/src/use-query.d.ts +5 -4
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +86 -9
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-solid/src/solid-view.d.ts +17 -0
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +39 -1
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.js +5 -3
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zql/src/builder/debug-delegate.d.ts +6 -1
- package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
- package/out/zql/src/builder/debug-delegate.js +14 -2
- package/out/zql/src/builder/debug-delegate.js.map +1 -1
- package/out/zql/src/ivm/array-view.d.ts +29 -0
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +58 -9
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.d.ts.map +1 -1
- package/out/zql/src/ivm/cap.js +5 -3
- package/out/zql/src/ivm/cap.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.d.ts.map +1 -1
- package/out/zql/src/ivm/deferred-input.js +3 -2
- package/out/zql/src/ivm/deferred-input.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +1 -1
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +2 -2
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js +6 -5
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +2 -2
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +4 -4
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +10 -8
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +2 -2
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js +7 -4
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +2 -2
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +6 -4
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +15 -3
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +35 -9
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +3 -4
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +9 -7
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +3 -3
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/ivm/view.d.ts +15 -0
- package/out/zql/src/ivm/view.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js +2 -2
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +4 -2
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +69 -36
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-delegate.d.ts +33 -6
- package/out/zql/src/query/query-delegate.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +25 -14
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +414 -94
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-internals.d.ts +21 -11
- package/out/zql/src/query/query-internals.d.ts.map +1 -1
- package/out/zql/src/query/query-internals.js.map +1 -1
- package/out/zql/src/query/query-transitions.d.ts +171 -0
- package/out/zql/src/query/query-transitions.d.ts.map +1 -0
- package/out/zql/src/query/query-transitions.js +207 -0
- package/out/zql/src/query/query-transitions.js.map +1 -0
- package/out/zql/src/query/query.d.ts +11 -2
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +3 -2
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +23 -2
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/typed-view.d.ts +1 -1
- package/out/zql/src/query/typed-view.d.ts.map +1 -1
- package/out/zqlite/src/db.d.ts +9 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +8 -2
- package/out/zqlite/src/db.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +1 -0
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +10 -5
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,18 +1,63 @@
|
|
|
1
1
|
import { assert } from "../../../shared/src/asserts.js";
|
|
2
|
-
import {
|
|
2
|
+
import { deepEqual } from "../../../shared/src/json.js";
|
|
3
|
+
import { SUBQ_PREFIX, insertRelated, normalizeAST, normalizeCondition, normalizedRelated, tableAST } from "../../../zero-protocol/src/ast.js";
|
|
3
4
|
import { defaultFormat } from "../../../zero-types/src/format.js";
|
|
4
|
-
import {
|
|
5
|
+
import { hashOfQueryInternals } from "../../../zero-protocol/src/query-hash-visitor.js";
|
|
5
6
|
import { NotImplementedError } from "../error.js";
|
|
6
7
|
import { ExpressionBuilder, and, cmp, simplifyCondition } from "./expression.js";
|
|
7
8
|
import { queryInternalsTag } from "./query-internals.js";
|
|
9
|
+
import { HashIndex, Transitions } from "./query-transitions.js";
|
|
8
10
|
//#region ../zql/src/query/query-impl.ts
|
|
9
11
|
function newQuery(schema, table) {
|
|
10
|
-
return
|
|
12
|
+
return newQueryInternal(schema, table, tableAST(table), defaultFormat, "client");
|
|
11
13
|
}
|
|
12
14
|
function newQueryImpl(schema, tableName, ast, format, system) {
|
|
15
|
+
return newQueryInternal(schema, tableName, normalizeAST(ast), format, system);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Root queries are interned per schema so that two `createBuilder(schema)` calls
|
|
19
|
+
* hand out the same starting point, and therefore share the whole transition
|
|
20
|
+
* tree below it. Only cleared entries accumulate here, at most one per
|
|
21
|
+
* system/table pair, so no sweeping is needed.
|
|
22
|
+
*/
|
|
23
|
+
var rootsBySchema = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
/**
|
|
25
|
+
* Whether this is the AST `tableAST(tableName)` produces -- the whole table,
|
|
26
|
+
* nothing else. A normalized AST carries every field, so this cannot be a key
|
|
27
|
+
* count; each one has to be checked.
|
|
28
|
+
*/
|
|
29
|
+
function isRootAST(ast, tableName) {
|
|
30
|
+
return ast.table === tableName && ast.schema === void 0 && ast.alias === void 0 && ast.where === void 0 && ast.related === void 0 && ast.start === void 0 && ast.limit === void 0 && ast.orderBy === void 0;
|
|
31
|
+
}
|
|
32
|
+
function newQueryInternal(schema, tableName, ast, format, system) {
|
|
33
|
+
const interned = format === defaultFormat && isRootAST(ast, tableName);
|
|
34
|
+
const key = `${system}:${tableName}`;
|
|
35
|
+
let roots;
|
|
36
|
+
if (interned) {
|
|
37
|
+
roots = rootsBySchema.get(schema);
|
|
38
|
+
const existing = roots?.get(key)?.deref();
|
|
39
|
+
if (existing) return existing;
|
|
40
|
+
}
|
|
13
41
|
const inner = (tableName, ast, format, customQueryID, currentJunction) => new QueryImpl(schema, tableName, ast, format, system, customQueryID, currentJunction, inner);
|
|
14
|
-
|
|
42
|
+
const created = inner(tableName, ast, format, void 0, void 0);
|
|
43
|
+
if (interned) {
|
|
44
|
+
if (!roots) {
|
|
45
|
+
roots = /* @__PURE__ */ new Map();
|
|
46
|
+
rootsBySchema.set(schema, roots);
|
|
47
|
+
}
|
|
48
|
+
roots.set(key, new WeakRef(created));
|
|
49
|
+
}
|
|
50
|
+
return created;
|
|
15
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The AST of a QueryImpl is always normalized. Each step builds its AST in
|
|
54
|
+
* normalized form rather than normalizing afterwards: a normalized AST has
|
|
55
|
+
* every field, so spreading one and replacing a field keeps the field order
|
|
56
|
+
* intact, and only the field a step actually changes needs normalizing (the
|
|
57
|
+
* conditions of a `where`, the position of a new `related`). The ASTs that
|
|
58
|
+
* come in from the outside are normalized by {@link newQueryImpl}, which is
|
|
59
|
+
* what the `NormalizedAST` of the AST it holds stands for.
|
|
60
|
+
*/
|
|
16
61
|
var QueryImpl = class {
|
|
17
62
|
[queryInternalsTag] = true;
|
|
18
63
|
#schema;
|
|
@@ -24,6 +69,26 @@ var QueryImpl = class {
|
|
|
24
69
|
#currentJunction;
|
|
25
70
|
customQueryID;
|
|
26
71
|
#newQuery;
|
|
72
|
+
/**
|
|
73
|
+
* The query this one was derived from, held *strongly*, and the queries
|
|
74
|
+
* derived from this one, held *weakly*. This is the arrangement V8 uses for
|
|
75
|
+
* hidden-class transitions, and it is what makes interning stable: as long as
|
|
76
|
+
* a query is reachable its whole ancestor spine is too, so re-deriving it from
|
|
77
|
+
* the root yields the same instance. See `query-transitions.ts`.
|
|
78
|
+
*/
|
|
79
|
+
#parent;
|
|
80
|
+
#transitions;
|
|
81
|
+
/**
|
|
82
|
+
* The second level of interning, keyed by hash; see `HashIndex`. Set on the
|
|
83
|
+
* root only, which is what scopes it to one schema and one delegate.
|
|
84
|
+
*/
|
|
85
|
+
#byHash;
|
|
86
|
+
/**
|
|
87
|
+
* Memoized because a query is interned: the same node serves every rebuild of
|
|
88
|
+
* a chain, so building this once rather than per `where(fn)` call takes the
|
|
89
|
+
* whole thing -- the builder and the bound `#exists` -- off the repeat path.
|
|
90
|
+
*/
|
|
91
|
+
#expressionBuilder;
|
|
27
92
|
constructor(schema, tableName, ast, format, system, customQueryID, currentJunction, newQuery) {
|
|
28
93
|
this.#schema = schema;
|
|
29
94
|
this.#tableName = tableName;
|
|
@@ -34,6 +99,44 @@ var QueryImpl = class {
|
|
|
34
99
|
this.customQueryID = customQueryID;
|
|
35
100
|
this.#newQuery = newQuery;
|
|
36
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Interns a transition whose key space is finite and schema-derived; see
|
|
104
|
+
* {@linkcode Transitions.storeBounded}. Used for the base sub-query handed to
|
|
105
|
+
* a `related`/`exists` callback, which is determined entirely by the
|
|
106
|
+
* relationship name.
|
|
107
|
+
*/
|
|
108
|
+
#deriveBounded(key, build) {
|
|
109
|
+
const existing = this.#transitions?.lookupBounded(key);
|
|
110
|
+
if (existing !== void 0) return existing;
|
|
111
|
+
return this.#record(key, void 0, void 0, build(), true);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Interns the result of applying a builder operation to this query.
|
|
115
|
+
*
|
|
116
|
+
* `key` names the operation and `value` carries its varying argument, kept
|
|
117
|
+
* apart so the key stays a string V8 has already hashed. When the two do not
|
|
118
|
+
* settle it, `delta` carries the rest and is compared with `deepEqual`. Only
|
|
119
|
+
* the delta is compared, never the whole AST: this query is already canonical,
|
|
120
|
+
* so two of its children are equal exactly when the operations that produced
|
|
121
|
+
* them are.
|
|
122
|
+
*
|
|
123
|
+
* `T` is deliberately unconstrained so that the contextual return type at each
|
|
124
|
+
* call site still drives `#newQuery`'s inference, exactly as it did when the
|
|
125
|
+
* call sites returned `this.#newQuery(...)` directly.
|
|
126
|
+
*/
|
|
127
|
+
#derive(key, value, delta, build) {
|
|
128
|
+
const existing = this.#transitions?.lookup(key, value, delta);
|
|
129
|
+
if (existing !== void 0) return existing;
|
|
130
|
+
return this.#record(key, value, delta, build(), false);
|
|
131
|
+
}
|
|
132
|
+
#record(key, value, delta, created, bounded) {
|
|
133
|
+
const q = created;
|
|
134
|
+
q.#parent = this;
|
|
135
|
+
const transitions = this.#transitions ??= new Transitions();
|
|
136
|
+
if (bounded) transitions.storeBounded(key, q);
|
|
137
|
+
else transitions.store(key, value, delta, q);
|
|
138
|
+
return created;
|
|
139
|
+
}
|
|
37
140
|
run(_options) {
|
|
38
141
|
throwQueryNotRunnable();
|
|
39
142
|
}
|
|
@@ -44,150 +147,204 @@ var QueryImpl = class {
|
|
|
44
147
|
throwQueryNotRunnable();
|
|
45
148
|
}
|
|
46
149
|
nameAndArgs(name, args) {
|
|
47
|
-
return this.#newQuery(this.#tableName, this.#ast, this.format, {
|
|
150
|
+
return this.#derive("nameAndArgs", name, args, () => this.#newQuery(this.#tableName, this.#ast, this.format, {
|
|
48
151
|
name,
|
|
49
152
|
args
|
|
50
|
-
}, this.#currentJunction);
|
|
153
|
+
}, this.#currentJunction));
|
|
51
154
|
}
|
|
52
155
|
hash() {
|
|
53
|
-
if (!this.#hash)
|
|
156
|
+
if (!this.#hash) {
|
|
157
|
+
this.#hash = hashOfQueryInternals(this.#ast, this.format, this.#system, this.#currentJunction, this.customQueryID?.name, this.customQueryID?.args);
|
|
158
|
+
this.#canonicalize();
|
|
159
|
+
}
|
|
54
160
|
return this.#hash;
|
|
55
161
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Folds this query into its root's hash index, now that its hash is known.
|
|
164
|
+
*
|
|
165
|
+
* If an equal query is already indexed, the transition that produced this
|
|
166
|
+
* one is re-pointed at it, so the next rebuild along this path yields that
|
|
167
|
+
* instance rather than a second copy. This query itself is left alone: its
|
|
168
|
+
* identity has already been handed out. Content is verified with `#sameAs`
|
|
169
|
+
* before anything is redirected, so a hash collision costs nothing worse
|
|
170
|
+
* than a missed unification.
|
|
171
|
+
*/
|
|
172
|
+
#canonicalize() {
|
|
173
|
+
const parent = this.#parent;
|
|
174
|
+
if (parent === void 0) return;
|
|
175
|
+
let root = parent;
|
|
176
|
+
while (root.#parent !== void 0) root = root.#parent;
|
|
177
|
+
const index = root.#byHash ??= new HashIndex();
|
|
178
|
+
const existing = index.get(this.#hash);
|
|
179
|
+
if (existing === void 0) index.set(this.#hash, this);
|
|
180
|
+
else if (existing !== this && this.#sameAs(existing)) parent.#transitions?.replace(this, existing);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Whether `other` is interchangeable with this query: everything `hash()`
|
|
184
|
+
* covers, compared structurally. Schema and delegate are not compared. Both
|
|
185
|
+
* are fixed by the root, and this only ever compares queries under one root.
|
|
186
|
+
*/
|
|
187
|
+
#sameAs(other) {
|
|
188
|
+
return this.#system === other.#system && this.#currentJunction === other.#currentJunction && this.customQueryID?.name === other.customQueryID?.name && deepEqual(this.customQueryID?.args, other.customQueryID?.args) && deepEqual(this.format, other.format) && deepEqual(this.#ast, other.#ast);
|
|
189
|
+
}
|
|
190
|
+
one() {
|
|
191
|
+
return this.#derive("one", void 0, void 0, () => this.#newQuery(this.#tableName, {
|
|
192
|
+
...this.#ast,
|
|
193
|
+
limit: 1
|
|
194
|
+
}, {
|
|
195
|
+
...this.format,
|
|
196
|
+
singular: true
|
|
197
|
+
}, this.customQueryID, this.#currentJunction));
|
|
198
|
+
}
|
|
199
|
+
whereExists(relationship, cbOrOptions, options) {
|
|
64
200
|
const cb = typeof cbOrOptions === "function" ? cbOrOptions : void 0;
|
|
65
201
|
const opts = typeof cbOrOptions === "function" ? options : cbOrOptions;
|
|
66
202
|
return this.where(({ exists }) => exists(relationship, cb, opts));
|
|
67
|
-
}
|
|
68
|
-
related
|
|
203
|
+
}
|
|
204
|
+
related(relationship, cb) {
|
|
69
205
|
if (relationship.startsWith("zsubq_")) throw new Error(`Relationship names may not start with "${SUBQ_PREFIX}". That is a reserved prefix.`);
|
|
70
206
|
cb = cb ?? ((q) => q);
|
|
71
207
|
const related = this.#schema.relationships[this.#tableName][relationship];
|
|
72
208
|
assert(related, "Invalid relationship");
|
|
73
209
|
if (isOneHop(related)) {
|
|
74
210
|
const { destSchema, destField, sourceField, cardinality } = related[0];
|
|
75
|
-
const q = this.#newQuery(destSchema, {
|
|
76
|
-
table: destSchema,
|
|
77
|
-
alias: relationship
|
|
78
|
-
}, {
|
|
211
|
+
const q = this.#deriveBounded(`relatedBase:${relationship}`, () => this.#newQuery(destSchema, tableAST(destSchema, relationship), {
|
|
79
212
|
relationships: {},
|
|
80
213
|
singular: cardinality === "one"
|
|
81
|
-
}, this.customQueryID, void 0);
|
|
214
|
+
}, this.customQueryID, void 0));
|
|
82
215
|
const subQuery = asQueryImpl(cb(q));
|
|
83
216
|
assert(isCompoundKey(sourceField), "The source of a relationship must specify at last 1 field");
|
|
84
217
|
assert(isCompoundKey(destField), "The destination of a relationship must specify at last 1 field");
|
|
85
218
|
assert(sourceField.length === destField.length, "The source and destination of a relationship must have the same number of fields");
|
|
86
|
-
return this.#newQuery(this.#tableName, {
|
|
219
|
+
return this.#derive(relatedKey(relationship), astID(subQuery.#ast), void 0, () => this.#newQuery(this.#tableName, {
|
|
87
220
|
...this.#ast,
|
|
88
|
-
related:
|
|
89
|
-
system: this.#system,
|
|
221
|
+
related: insertRelated(this.#ast.related, {
|
|
90
222
|
correlation: {
|
|
91
223
|
parentField: sourceField,
|
|
92
224
|
childField: destField
|
|
93
225
|
},
|
|
94
|
-
subquery: subQuery.#ast
|
|
95
|
-
|
|
226
|
+
subquery: subQuery.#ast,
|
|
227
|
+
system: this.#system
|
|
228
|
+
})
|
|
96
229
|
}, {
|
|
97
230
|
...this.format,
|
|
98
231
|
relationships: {
|
|
99
232
|
...this.format.relationships,
|
|
100
233
|
[relationship]: subQuery.format
|
|
101
234
|
}
|
|
102
|
-
}, this.customQueryID, this.#currentJunction);
|
|
235
|
+
}, this.customQueryID, this.#currentJunction));
|
|
103
236
|
}
|
|
104
237
|
if (isTwoHop(related)) {
|
|
105
238
|
const [firstRelation, secondRelation] = related;
|
|
106
239
|
const { destSchema } = secondRelation;
|
|
107
240
|
const junctionSchema = firstRelation.destSchema;
|
|
108
|
-
const sq = asQueryImpl(cb(this.#newQuery(destSchema, {
|
|
109
|
-
table: destSchema,
|
|
110
|
-
alias: relationship
|
|
111
|
-
}, {
|
|
241
|
+
const sq = asQueryImpl(cb(this.#deriveBounded(`relatedBase:${relationship}`, () => this.#newQuery(destSchema, tableAST(destSchema, relationship), {
|
|
112
242
|
relationships: {},
|
|
113
243
|
singular: secondRelation.cardinality === "one"
|
|
114
|
-
}, this.customQueryID, relationship)));
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
assert(isCompoundKey(
|
|
118
|
-
assert(isCompoundKey(
|
|
119
|
-
|
|
244
|
+
}, this.customQueryID, relationship))));
|
|
245
|
+
const { sourceField: firstSource, destField: firstDest } = firstRelation;
|
|
246
|
+
const { sourceField: secondSource, destField: secondDest } = secondRelation;
|
|
247
|
+
assert(isCompoundKey(firstSource), "Invalid relationship");
|
|
248
|
+
assert(isCompoundKey(firstDest), "Invalid relationship");
|
|
249
|
+
assert(isCompoundKey(secondSource), "Invalid relationship");
|
|
250
|
+
assert(isCompoundKey(secondDest), "Invalid relationship");
|
|
251
|
+
return this.#derive(relatedKey(relationship), astID(sq.#ast), void 0, () => this.#newQuery(this.#tableName, {
|
|
120
252
|
...this.#ast,
|
|
121
|
-
related:
|
|
122
|
-
system: this.#system,
|
|
253
|
+
related: insertRelated(this.#ast.related, {
|
|
123
254
|
correlation: {
|
|
124
|
-
parentField:
|
|
125
|
-
childField:
|
|
255
|
+
parentField: firstSource,
|
|
256
|
+
childField: firstDest
|
|
126
257
|
},
|
|
127
258
|
hidden: true,
|
|
128
259
|
subquery: {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
related: [{
|
|
132
|
-
system: this.#system,
|
|
260
|
+
...tableAST(junctionSchema, relationship),
|
|
261
|
+
related: [normalizedRelated({
|
|
133
262
|
correlation: {
|
|
134
|
-
parentField:
|
|
135
|
-
childField:
|
|
263
|
+
parentField: secondSource,
|
|
264
|
+
childField: secondDest
|
|
136
265
|
},
|
|
137
|
-
subquery: sq.#ast
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
266
|
+
subquery: sq.#ast,
|
|
267
|
+
system: this.#system
|
|
268
|
+
})]
|
|
269
|
+
},
|
|
270
|
+
system: this.#system
|
|
271
|
+
})
|
|
141
272
|
}, {
|
|
142
273
|
...this.format,
|
|
143
274
|
relationships: {
|
|
144
275
|
...this.format.relationships,
|
|
145
276
|
[relationship]: sq.format
|
|
146
277
|
}
|
|
147
|
-
}, this.customQueryID, this.#currentJunction);
|
|
278
|
+
}, this.customQueryID, this.#currentJunction));
|
|
148
279
|
}
|
|
149
280
|
throw new Error(`Invalid relationship ${relationship}`);
|
|
150
|
-
}
|
|
151
|
-
where
|
|
281
|
+
}
|
|
282
|
+
where(fieldOrExpressionFactory, opOrValue, value) {
|
|
152
283
|
let cond;
|
|
153
284
|
if (typeof fieldOrExpressionFactory === "function") cond = fieldOrExpressionFactory(this.expressionBuilder());
|
|
154
285
|
else {
|
|
155
286
|
assert(arguments.length >= 2, "Invalid condition. Too few arguments.");
|
|
156
|
-
|
|
157
|
-
|
|
287
|
+
const twoArg = arguments.length === 2;
|
|
288
|
+
const op = twoArg ? "=" : opOrValue;
|
|
289
|
+
const raw = twoArg ? opOrValue : value;
|
|
290
|
+
if (raw === null || typeof raw !== "object") {
|
|
291
|
+
const hit = this.#transitions?.lookup(whereKey(fieldOrExpressionFactory, op), raw ?? null, void 0);
|
|
292
|
+
if (hit !== void 0) return hit;
|
|
293
|
+
}
|
|
294
|
+
cond = twoArg ? cmp(fieldOrExpressionFactory, opOrValue) : cmp(fieldOrExpressionFactory, opOrValue, value);
|
|
158
295
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
296
|
+
let key;
|
|
297
|
+
let tValue;
|
|
298
|
+
let delta = cond;
|
|
299
|
+
if (cond.type === "simple" && cond.left.type === "column") {
|
|
300
|
+
key = whereKey(cond.left.name, cond.op);
|
|
301
|
+
const right = cond.right;
|
|
302
|
+
tValue = right.type === "literal" && isPrimitive(right.value) ? right.value : rightTag(right);
|
|
303
|
+
delta = void 0;
|
|
304
|
+
} else {
|
|
305
|
+
const exact = condKey(cond);
|
|
306
|
+
if (exact === void 0) key = treeKey(cond);
|
|
307
|
+
else {
|
|
308
|
+
key = "where:tree";
|
|
309
|
+
tValue = exact;
|
|
310
|
+
delta = void 0;
|
|
311
|
+
}
|
|
172
312
|
}
|
|
173
|
-
|
|
174
|
-
|
|
313
|
+
return this.#derive(key, tValue, delta, () => {
|
|
314
|
+
const existingWhere = this.#ast.where;
|
|
315
|
+
const merged = existingWhere ? and(existingWhere, cond) : cond;
|
|
316
|
+
return this.#newQuery(this.#tableName, {
|
|
317
|
+
...this.#ast,
|
|
318
|
+
where: normalizeCondition(simplifyCondition(merged))
|
|
319
|
+
}, this.format, this.customQueryID, this.#currentJunction);
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
start(row, opts) {
|
|
323
|
+
return this.#derive(opts?.inclusive ? "start:inclusive" : "start:exclusive", valueTag(row), void 0, () => this.#newQuery(this.#tableName, {
|
|
324
|
+
...this.#ast,
|
|
325
|
+
start: {
|
|
326
|
+
row,
|
|
327
|
+
exclusive: !opts?.inclusive
|
|
328
|
+
}
|
|
329
|
+
}, this.format, this.customQueryID, this.#currentJunction));
|
|
330
|
+
}
|
|
331
|
+
limit(limit) {
|
|
175
332
|
if (limit < 0) throw new Error("Limit must be non-negative");
|
|
176
333
|
if ((limit | 0) !== limit) throw new Error("Limit must be an integer");
|
|
177
334
|
if (this.#currentJunction) throw new NotImplementedError("Limit is not supported in junction relationships yet. Junction relationship being limited: " + this.#currentJunction);
|
|
178
|
-
return this.#newQuery(this.#tableName, {
|
|
335
|
+
return this.#derive("limit", limit, void 0, () => this.#newQuery(this.#tableName, {
|
|
179
336
|
...this.#ast,
|
|
180
337
|
limit
|
|
181
|
-
}, this.format, this.customQueryID, this.#currentJunction);
|
|
182
|
-
}
|
|
183
|
-
orderBy
|
|
338
|
+
}, this.format, this.customQueryID, this.#currentJunction));
|
|
339
|
+
}
|
|
340
|
+
orderBy(field, direction) {
|
|
184
341
|
if (this.#currentJunction) throw new NotImplementedError("Order by is not supported in junction relationships yet. Junction relationship being ordered: " + this.#currentJunction);
|
|
185
|
-
return this.#newQuery(this.#tableName, {
|
|
342
|
+
return this.#derive(direction === "asc" ? "orderBy:asc" : "orderBy:desc", field, void 0, () => this.#newQuery(this.#tableName, {
|
|
186
343
|
...this.#ast,
|
|
187
344
|
orderBy: [...this.#ast.orderBy ?? [], [field, direction]]
|
|
188
|
-
}, this.format, this.customQueryID, this.#currentJunction);
|
|
189
|
-
}
|
|
190
|
-
#exists
|
|
345
|
+
}, this.format, this.customQueryID, this.#currentJunction));
|
|
346
|
+
}
|
|
347
|
+
#exists(relationship, cb, options) {
|
|
191
348
|
cb = cb ?? ((q) => q);
|
|
192
349
|
const flip = options?.flip;
|
|
193
350
|
const scalar = options?.scalar;
|
|
@@ -197,10 +354,8 @@ var QueryImpl = class {
|
|
|
197
354
|
const { destSchema: destTableName, sourceField, destField } = related[0];
|
|
198
355
|
assert(isCompoundKey(sourceField), "Invalid relationship");
|
|
199
356
|
assert(isCompoundKey(destField), "Invalid relationship");
|
|
200
|
-
const subQuery = asQueryImpl(cb(this.#newQuery(destTableName, {
|
|
201
|
-
|
|
202
|
-
alias: `${SUBQ_PREFIX}${relationship}`
|
|
203
|
-
}, defaultFormat, this.customQueryID, void 0)));
|
|
357
|
+
const subQuery = asQueryImpl(cb(this.#deriveBounded(`existsBase:${relationship}`, () => this.#newQuery(destTableName, tableAST(destTableName, `${SUBQ_PREFIX}${relationship}`), defaultFormat, this.customQueryID, void 0))));
|
|
358
|
+
astID(subQuery.#ast);
|
|
204
359
|
return {
|
|
205
360
|
type: "correlatedSubquery",
|
|
206
361
|
related: {
|
|
@@ -224,10 +379,7 @@ var QueryImpl = class {
|
|
|
224
379
|
assert(isCompoundKey(secondRelation.destField), "Invalid relationship");
|
|
225
380
|
const { destSchema } = secondRelation;
|
|
226
381
|
const junctionSchema = firstRelation.destSchema;
|
|
227
|
-
const queryToDest = cb(this.#newQuery(destSchema, {
|
|
228
|
-
table: destSchema,
|
|
229
|
-
alias: `${SUBQ_PREFIX}zhidden_${relationship}`
|
|
230
|
-
}, defaultFormat, this.customQueryID, relationship));
|
|
382
|
+
const queryToDest = cb(this.#deriveBounded(`existsJunctionBase:${relationship}`, () => this.#newQuery(destSchema, tableAST(destSchema, `${SUBQ_PREFIX}zhidden_${relationship}`), defaultFormat, this.customQueryID, relationship)));
|
|
231
383
|
return {
|
|
232
384
|
type: "correlatedSubquery",
|
|
233
385
|
related: {
|
|
@@ -237,9 +389,8 @@ var QueryImpl = class {
|
|
|
237
389
|
childField: firstRelation.destField
|
|
238
390
|
},
|
|
239
391
|
subquery: {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
where: {
|
|
392
|
+
...tableAST(junctionSchema, `${SUBQ_PREFIX}${relationship}`),
|
|
393
|
+
where: normalizeCondition({
|
|
243
394
|
type: "correlatedSubquery",
|
|
244
395
|
related: {
|
|
245
396
|
system: this.#system,
|
|
@@ -252,7 +403,7 @@ var QueryImpl = class {
|
|
|
252
403
|
op: "EXISTS",
|
|
253
404
|
...flip !== void 0 ? { flip } : {},
|
|
254
405
|
...scalar !== void 0 ? { scalar } : {}
|
|
255
|
-
}
|
|
406
|
+
})
|
|
256
407
|
}
|
|
257
408
|
},
|
|
258
409
|
op: "EXISTS",
|
|
@@ -260,18 +411,187 @@ var QueryImpl = class {
|
|
|
260
411
|
};
|
|
261
412
|
}
|
|
262
413
|
throw new Error(`Invalid relationship ${relationship}`);
|
|
263
|
-
}
|
|
414
|
+
}
|
|
264
415
|
get ast() {
|
|
265
416
|
return this.#ast;
|
|
266
417
|
}
|
|
267
418
|
expressionBuilder() {
|
|
268
|
-
return new ExpressionBuilder(this.#exists);
|
|
419
|
+
return this.#expressionBuilder ??= new ExpressionBuilder(this.#exists.bind(this));
|
|
269
420
|
}
|
|
270
421
|
};
|
|
271
422
|
function asQueryImpl(q) {
|
|
272
423
|
assert(q instanceof QueryImpl, "Expected QueryImpl instance");
|
|
273
424
|
return q;
|
|
274
425
|
}
|
|
426
|
+
/**
|
|
427
|
+
* A stable id per query AST.
|
|
428
|
+
*
|
|
429
|
+
* Every `QueryImpl` allocates its own AST object, so these are one-to-one with
|
|
430
|
+
* queries, and interning makes the object identity stable across rebuilds. That
|
|
431
|
+
* lets a `related` or `exists` transition key on *which* sub-query it points at
|
|
432
|
+
* rather than comparing the sub-tree.
|
|
433
|
+
*
|
|
434
|
+
* Assigned only where it is needed. A `WeakMap.set` costs on the order of a
|
|
435
|
+
* hundred nanoseconds, so doing this for every query rather than for the few
|
|
436
|
+
* that are sub-queries was one of the largest single costs of building a query
|
|
437
|
+
* from cold. ASTs that never pass through here -- including the junction AST a
|
|
438
|
+
* two-hop `exists` builds inline -- are absent, and fall back to a delta.
|
|
439
|
+
*/
|
|
440
|
+
var astIDs = /* @__PURE__ */ new WeakMap();
|
|
441
|
+
var nextASTID = 0;
|
|
442
|
+
function astID(ast) {
|
|
443
|
+
let id = astIDs.get(ast);
|
|
444
|
+
if (id === void 0) {
|
|
445
|
+
id = ++nextASTID;
|
|
446
|
+
astIDs.set(ast, id);
|
|
447
|
+
}
|
|
448
|
+
return id;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Memoized transition keys.
|
|
452
|
+
*
|
|
453
|
+
* A transition key must be a string V8 has already hashed, or the `Map` lookup
|
|
454
|
+
* has to hash it from scratch -- measured at ~148ns against ~10ns, which dwarfs
|
|
455
|
+
* everything else a lookup does. Both tables are keyed by schema-derived names,
|
|
456
|
+
* so they are bounded by the schema.
|
|
457
|
+
*/
|
|
458
|
+
var whereKeys = /* @__PURE__ */ new Map();
|
|
459
|
+
function whereKey(column, op) {
|
|
460
|
+
let byOp = whereKeys.get(column);
|
|
461
|
+
if (byOp === void 0) {
|
|
462
|
+
byOp = /* @__PURE__ */ new Map();
|
|
463
|
+
whereKeys.set(column, byOp);
|
|
464
|
+
}
|
|
465
|
+
let key = byOp.get(op);
|
|
466
|
+
if (key === void 0) {
|
|
467
|
+
key = `where:${column}:${op}`;
|
|
468
|
+
byOp.set(op, key);
|
|
469
|
+
}
|
|
470
|
+
return key;
|
|
471
|
+
}
|
|
472
|
+
var relatedKeys = /* @__PURE__ */ new Map();
|
|
473
|
+
function relatedKey(relationship) {
|
|
474
|
+
let key = relatedKeys.get(relationship);
|
|
475
|
+
if (key === void 0) {
|
|
476
|
+
key = `related:${relationship}`;
|
|
477
|
+
relatedKeys.set(relationship, key);
|
|
478
|
+
}
|
|
479
|
+
return key;
|
|
480
|
+
}
|
|
481
|
+
function isPrimitive(v) {
|
|
482
|
+
return v === null || typeof v !== "object";
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Folds a JSON value into a self-delimiting token: a string is
|
|
486
|
+
* length-prefixed, a number is terminated, an array or object is
|
|
487
|
+
* count-prefixed and encodes its members recursively, and the rest are fixed
|
|
488
|
+
* width. Tokens can therefore be concatenated into a key with no way for one
|
|
489
|
+
* to run into the next, and the leading tag keeps `'1'` and `1` apart.
|
|
490
|
+
*
|
|
491
|
+
* Not `JSON.stringify`: it writes `Infinity`, `NaN` and `null` all as `null`,
|
|
492
|
+
* and this token is trusted as exact, so a nested value that serialized like
|
|
493
|
+
* another's would hand back a query with the wrong value in its AST. Numbers
|
|
494
|
+
* are written the way `String` writes them, which keeps those apart. An
|
|
495
|
+
* `undefined` property is skipped, as `deepEqual` would skip it; property
|
|
496
|
+
* order is part of the encoding, so an object spelled in another order
|
|
497
|
+
* interns separately.
|
|
498
|
+
*/
|
|
499
|
+
function valueTag(v) {
|
|
500
|
+
switch (typeof v) {
|
|
501
|
+
case "string": return `:s${enc(v)}`;
|
|
502
|
+
case "number": return `:n${v};`;
|
|
503
|
+
case "boolean": return v ? ":t" : ":f";
|
|
504
|
+
default: {
|
|
505
|
+
if (v === null) return ":z";
|
|
506
|
+
if (Array.isArray(v)) {
|
|
507
|
+
let out = `:a${v.length}:`;
|
|
508
|
+
for (const e of v) out += valueTag(e);
|
|
509
|
+
return out;
|
|
510
|
+
}
|
|
511
|
+
const o = v;
|
|
512
|
+
let body = "";
|
|
513
|
+
let n = 0;
|
|
514
|
+
for (const key in o) {
|
|
515
|
+
const e = o[key];
|
|
516
|
+
if (e !== void 0 && Object.hasOwn(o, key)) {
|
|
517
|
+
body += enc(key) + valueTag(e);
|
|
518
|
+
n++;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return `:o${n}:${body}`;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Folds the right-hand side of a simple condition into a transition value, so
|
|
527
|
+
* that the transition is exact and the lookup needs no comparison at all.
|
|
528
|
+
*
|
|
529
|
+
* Arrays (`IN`) and parameter references are encoded in full: that is one
|
|
530
|
+
* pass over a small value, where leaving them in the delta would instead cost
|
|
531
|
+
* a `deepEqual` over the whole condition for every sibling a lookup walks
|
|
532
|
+
* past.
|
|
533
|
+
*/
|
|
534
|
+
function rightTag(right) {
|
|
535
|
+
if (right.type !== "literal") return `:p${valueTag(right)}`;
|
|
536
|
+
return valueTag(right.value);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Length-prefixes a free-form string so it can be concatenated into a key
|
|
540
|
+
* without a separator being ambiguous with the content.
|
|
541
|
+
*/
|
|
542
|
+
function enc(s) {
|
|
543
|
+
return `${s.length}:${s}`;
|
|
544
|
+
}
|
|
545
|
+
/** Encodes an optional boolean without collapsing `undefined` into `false`. */
|
|
546
|
+
function tri(b) {
|
|
547
|
+
return b === void 0 ? "-" : b ? "t" : "f";
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* An exact key for a whole condition tree, or `undefined` for a shape we cannot
|
|
551
|
+
* encode (which falls back to {@linkcode treeKey} plus a delta).
|
|
552
|
+
*
|
|
553
|
+
* Everything variable-length is length-prefixed, so distinct trees cannot
|
|
554
|
+
* produce the same string and the key needs no `deepEqual` to back it up. That
|
|
555
|
+
* matters because the alternative -- one coarse bucket per shape -- turns N
|
|
556
|
+
* sibling conditions off the same parent into an N-deep scan of tree
|
|
557
|
+
* comparisons, which measured far slower than not interning at all.
|
|
558
|
+
*/
|
|
559
|
+
function condKey(cond) {
|
|
560
|
+
switch (cond.type) {
|
|
561
|
+
case "simple":
|
|
562
|
+
if (cond.left.type !== "column") return;
|
|
563
|
+
return `S${enc(cond.left.name)}${enc(cond.op)}${rightTag(cond.right)}`;
|
|
564
|
+
case "correlatedSubquery": {
|
|
565
|
+
const id = astIDs.get(cond.related.subquery);
|
|
566
|
+
return id === void 0 ? void 0 : `E${id}:${enc(cond.op)}${tri(cond.flip)}${tri(cond.scalar)}`;
|
|
567
|
+
}
|
|
568
|
+
case "and":
|
|
569
|
+
case "or": {
|
|
570
|
+
let out = `${cond.type === "and" ? "A" : "O"}${cond.conditions.length}:`;
|
|
571
|
+
for (const c of cond.conditions) {
|
|
572
|
+
const k = condKey(c);
|
|
573
|
+
if (k === void 0) return;
|
|
574
|
+
out += k;
|
|
575
|
+
}
|
|
576
|
+
return out;
|
|
577
|
+
}
|
|
578
|
+
default: return;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* A coarse bucket key for the conditions {@linkcode condKey} cannot encode --
|
|
583
|
+
* a two-hop `exists`, whose junction AST is built inline and so has no identity
|
|
584
|
+
* of its own. Reads only the top of the tree, so it is cheap; the delta tells
|
|
585
|
+
* apart what shares it.
|
|
586
|
+
*/
|
|
587
|
+
function treeKey(cond) {
|
|
588
|
+
switch (cond.type) {
|
|
589
|
+
case "correlatedSubquery": return `where:e:${cond.related.subquery.alias}:${cond.op}`;
|
|
590
|
+
case "and":
|
|
591
|
+
case "or": return `where:${cond.type}:${cond.conditions.length}`;
|
|
592
|
+
default: return "where:*";
|
|
593
|
+
}
|
|
594
|
+
}
|
|
275
595
|
function throwQueryNotRunnable() {
|
|
276
596
|
throw new Error("Query is not runnable");
|
|
277
597
|
}
|