Skip to content

Fix timeseries WHERE filter routing via exhaustive collection_type dispatch#5

Merged
farhan-syah merged 4 commits intomainfrom
fix/timeseries-where-routing
Mar 30, 2026
Merged

Fix timeseries WHERE filter routing via exhaustive collection_type dispatch#5
farhan-syah merged 4 commits intomainfrom
fix/timeseries-where-routing

Conversation

@farhan-syah
Copy link
Copy Markdown
Contributor

@farhan-syah farhan-syah commented Mar 30, 2026

Summary

Fixes #4SELECT * FROM ts_collection WHERE field = 'value' returned empty results because the Filter(TableScan) path in the plan converter never checked for timeseries (or columnar/spatial) collections, silently misrouting them to DocumentOp::Scan.

Root cause: Four independent is_kv() / is_timeseries() / is_plain_columnar() / is_spatial() methods each performed separate catalog lookups, and callers had to remember to check all of them. Missing a check meant silent misrouting to the document engine fallback.

Fix: Replace the is_*() waterfall with a single collection_type() method that returns Option<CollectionType>, then dispatch via exhaustive match. Rust's pattern exhaustiveness checking now guarantees that adding a new CollectionType variant produces compile errors at every dispatch site.

Changes

  • converter.rs — Replaced 4 is_*() helpers with collection_type(). Refactored Filter(TableScan), bare TableScan, and Limit handlers to exhaustive match. Timeseries WHERE filters now correctly extract time-range bounds and preserve column projections. Limit propagation covers all scan types (TimeseriesOp::Scan, ColumnarOp::Scan, SpatialOp::Scan, KvOp::Scan).
  • converter_helpers.rs — Aggregate timeseries detection uses collection_type().
  • dml.rs — DML routing uses exhaustive match. Spatial collections now route to columnar insert.
  • plan_builder/mod.rs — Replaced is_kv() + is_timeseries() with single collection_type().
  • plan_builder/document.rsPointGet/PointPut/PointDelete use exhaustive match. Columnar collections now return explicit errors instead of silent misrouting to DocumentOp.
  • collection_insert.rs — Replaced is_strict() || is_columnar() with !is_schemaless() to also skip KV and timeseries.
  • ddl/collection.rs — Storage mode registration uses exhaustive match. KV collections register with their schema.

Test plan

  • cargo test --all-features — 3223 passed, 0 failures
  • cargo clippy -p nodedb --all-targets -- -D warnings — clean
  • Manual: SELECT * FROM metrics WHERE qtype = 'AAAA' LIMIT 10 on a timeseries collection returns rows
  • Manual: SELECT * FROM metrics WHERE elapsed_ms > 1000 LIMIT 5 on a timeseries collection returns rows
  • Manual: SELECT * FROM columnar_table WHERE field = 'x' LIMIT 10 on a plain columnar collection returns rows

farhan-syah and others added 4 commits March 30, 2026 21:31
…tion_type() method

Replace four separate is_timeseries / is_plain_columnar / is_spatial / is_kv predicate
methods with a single collection_type() call that performs one catalog read. Each call
site is updated to match exhaustively on CollectionType, so new collection variants
produce a compile error instead of silently falling through to document routing.

Filter(TableScan) and bare TableScan paths in the converter now share the same dispatch
logic. DML routing in dml.rs and point-operation builders in the native dispatch layer
follow the same pattern. Helper functions serialize_predicate_filters,
serialize_scan_filters, and resolve_scan_projection are extracted to eliminate repeated
inline serialization blocks.
…path

In ilp_listener.rs, fix schema comparison to use content equality instead
of length comparison, replace silent error swallowing on catalog writes with
tracing::warn!, fix catalog() call to use .as_ref(), and collapse nested if
chains into let-chain conditions per clippy.

In timeseries.rs, replace .unwrap() on memtable lookups with proper
let-else guards that return a structured Internal error response, and
convert the third unwrap in the schema-columns branch to a let-chain
condition so a missing memtable no longer panics.
@farhan-syah farhan-syah merged commit db54e38 into main Mar 30, 2026
@farhan-syah farhan-syah deleted the fix/timeseries-where-routing branch March 31, 2026 01:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Timeseries: WHERE filters on scans not routed through TimeseriesOp::Scan

1 participant