Skip to content

feat: add support for limiting queries by stored_at#3965

Merged
turip merged 2 commits into
mainfrom
feat/query-stored-at-filter
Mar 18, 2026
Merged

feat: add support for limiting queries by stored_at#3965
turip merged 2 commits into
mainfrom
feat/query-stored-at-filter

Conversation

@turip
Copy link
Copy Markdown
Member

@turip turip commented Mar 18, 2026

Overview

add support for limiting meter queries by stored_at.

A skiplist index is added for faster queries. The skiplist index is minmax typed, as usually a block is written in 1-2 secs, so the stored_at field's value will be in a few seconds range for each block, thus this is quite conservative from the storage perspective.

Notes for reviewer

Summary by CodeRabbit

  • New Features

    • Meter queries can now filter results by stored event timestamps for finer historical data selection.
  • Performance

    • Event table creation now includes an index on storage timestamps to improve query performance.
  • Tests

    • Added test coverage for queries that filter by stored event timestamps to ensure correct SQL and bindings.

@turip turip requested a review from a team as a code owner March 18, 2026 09:26
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

📝 Walkthrough

Walkthrough

Propagates a new Unix-time filter for stored_at through query params and the ClickHouse connector into meter query SQL generation, adds a minmax index on the events table stored_at column, and updates tests to cover the new stored_at WHERE clause.

Changes

Cohort / File(s) Summary
Filter package
pkg/filter/filter.go
Adds FilterTimeUnix type and SelectWhereExpr implementation that emits WHERE expressions using Unix() seconds for time bounds, and recurses for nested And/Or filters.
Query params
openmeter/streaming/query_params.go
Adds FilterStoredAt *filter.FilterTimeUnix to QueryParams and validates it in Validate().
Connector wiring
openmeter/streaming/clickhouse/connector.go
Threads params.FilterStoredAt into queryMeter construction so stored_at filtering is propagated from request params.
Meter query construction
openmeter/streaming/clickhouse/meter_query.go, openmeter/streaming/clickhouse/connector.go
Adds FilterStoredAt field to queryMeter and, when present, injects its SelectWhereExpr("om_events.stored_at", q) into the WHERE clause before GROUP BY.
Events table schema
openmeter/streaming/clickhouse/event_query.go
Adds INDEX om_events_stored_at stored_at TYPE minmax GRANULARITY 4 to the CREATE TABLE builder for events.
Tests
openmeter/streaming/clickhouse/meter_query_test.go, openmeter/streaming/clickhouse/event_query_test.go
Adds test case verifying SQL includes om_events.stored_at < ? with the Unix timestamp bind; updates expected CREATE TABLE SQL to include the new stored_at index.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

release-note/feature

Suggested reviewers

  • tothandras
  • hekike
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature: adding support for filtering meter queries by the stored_at field, which is the core purpose reflected across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/query-stored-at-filter
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@turip turip added the release-note/misc Miscellaneous changes label Mar 18, 2026
@turip turip requested a review from tothandras March 18, 2026 09:27
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
openmeter/streaming/clickhouse/meter_query_test.go (1)

82-110: Great start—please add a few more cases for full filter coverage.

The new case is good, but right now it only exercises $lt. I’d add table cases for $gt/$gte/$lte, nested $and/$or, and an empty filter object to lock down behavior on all supported branches.

As per coding guidelines "**/*_test.go: Make sure the tests are comprehensive and cover the changes. Keep a strong focus on unit tests and in-code integration tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openmeter/streaming/clickhouse/meter_query_test.go` around lines 82 - 110,
Add more unit test cases in the queryMeter table in meter_query_test.go to cover
all filter branches: create additional entries similar to the "basic query with
decimal stored at offset" case but exercising FilterStoredAtOffset with Lt, Gt,
Gte, Lte values, a case using a nested Filter (combined $and/$or) to validate
complex boolean logic, and a case with an empty FilterStoredAtOffset (or
nil/empty filter object) to lock down default behavior; for each case populate
queryMeter fields (Database, EventsTableName, Namespace, Meter,
FilterStoredAtOffset, FilterSubject, From, To, GroupBy, WindowSize,
EnableDecimalPrecision) and assert corresponding wantSQL and wantArgs to reflect
the expected WHERE clauses and arguments (use the same symbols like queryMeter,
FilterStoredAtOffset, FilterSubject, EnableDecimalPrecision, wantSQL, wantArgs
to locate and add the cases).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@openmeter/streaming/clickhouse/event_query.go`:
- Line 35: The new index is only defined during CREATE TABLE via the call to
sb.Define(fmt.Sprintf("INDEX %s_stored_at stored_at TYPE minmax GRANULARITY 4",
d.EventsTableName)), so existing tables won’t receive it; add a migration path
that runs on connector init (or upgrade) which executes an ALTER TABLE
<db>.<table> ADD INDEX IF NOT EXISTS <name> stored_at TYPE minmax GRANULARITY 4
for d.EventsTableName (or uses EventsTableName-derived index name) to ensure
existing tables get the index; implement this in the same initialization flow
that currently builds tables so the ALTER is idempotent and logged/handled on
error.

In `@openmeter/streaming/clickhouse/meter_query.go`:
- Around line 320-323: The code currently calls
d.FilterStoredAtOffset.SelectWhereExpr(...) and passes its result directly to
query.Where, which can produce an empty WHERE clause; update the block handling
FilterStoredAtOffset to first check for nil and then call an IsEmpty() (or
equivalent) on FilterStoredAtOffset before building the expression: only call
SelectWhereExpr(getColumn("stored_at"), query) and pass its result to
query.Where when the filter is non-nil and not empty, otherwise skip adding the
WHERE clause (or return/propagate a validation error as appropriate) to prevent
query.Where("") from being invoked; modify the code around FilterStoredAtOffset,
SelectWhereExpr, getColumn("stored_at"), and query.Where accordingly.

In `@pkg/filter/filter.go`:
- Around line 534-541: Nested $and/$or branches on FilterTimeUnix are delegating
to FilterTime.SelectWhereExpr, causing nested predicates to bind time.Time
instead of Unix seconds; modify the f.And and f.Or handling so the mapper calls
FilterTimeUnix.SelectWhereExpr (i.e., use each element as FilterTimeUnix when
mapping) instead of FilterTime.SelectWhereExpr, keeping the same parameters
(field, q) and preserving the lo.Map(...) and q.And/q.Or wrapping.

---

Nitpick comments:
In `@openmeter/streaming/clickhouse/meter_query_test.go`:
- Around line 82-110: Add more unit test cases in the queryMeter table in
meter_query_test.go to cover all filter branches: create additional entries
similar to the "basic query with decimal stored at offset" case but exercising
FilterStoredAtOffset with Lt, Gt, Gte, Lte values, a case using a nested Filter
(combined $and/$or) to validate complex boolean logic, and a case with an empty
FilterStoredAtOffset (or nil/empty filter object) to lock down default behavior;
for each case populate queryMeter fields (Database, EventsTableName, Namespace,
Meter, FilterStoredAtOffset, FilterSubject, From, To, GroupBy, WindowSize,
EnableDecimalPrecision) and assert corresponding wantSQL and wantArgs to reflect
the expected WHERE clauses and arguments (use the same symbols like queryMeter,
FilterStoredAtOffset, FilterSubject, EnableDecimalPrecision, wantSQL, wantArgs
to locate and add the cases).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f3a6be6e-b4b0-44c7-a6fe-79ebbf7fda72

📥 Commits

Reviewing files that changed from the base of the PR and between 325538e and 0387673.

📒 Files selected for processing (6)
  • openmeter/streaming/clickhouse/connector.go
  • openmeter/streaming/clickhouse/event_query.go
  • openmeter/streaming/clickhouse/meter_query.go
  • openmeter/streaming/clickhouse/meter_query_test.go
  • openmeter/streaming/query_params.go
  • pkg/filter/filter.go

Comment thread openmeter/streaming/clickhouse/event_query.go
Comment thread openmeter/streaming/clickhouse/meter_query.go Outdated
Comment thread pkg/filter/filter.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
openmeter/streaming/clickhouse/meter_query_test.go (1)

82-112: Good new case—please add a couple of edge/operator variants too.

This case is solid for the Lt path. I’d add a few nearby cases (e.g., Gte, nested $and/$or, and empty FilterStoredAt) to lock down SQL generation behavior for the full new filter surface.

As per coding guidelines, "**/*_test.go: Make sure the tests are comprehensive and cover the changes."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openmeter/streaming/clickhouse/meter_query_test.go` around lines 82 - 112,
Add additional test cases alongside the existing one in meter_query_test.go to
cover other FilterStoredAt variants: a case using filter.FilterTimeUnix with
FilterTime.Gte set (use storedAtOffset and expect stored_at >= ? in wantSQL and
storedAtOffset.Unix() in wantArgs), a case with an empty/nil FilterStoredAt to
ensure no stored_at predicate is emitted, and a case with nested logical filters
(e.g., $and/$or) to assert correct SQL generation for combined conditions;
locate the query definitions using the queryMeter struct and the FilterStoredAt
field, mirror the existing pattern (Meter, From/To, GroupBy,
EnableDecimalPrecision) and provide corresponding wantSQL and wantArgs for each
variant to lock down SQL generation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@openmeter/streaming/clickhouse/meter_query_test.go`:
- Around line 82-112: Add additional test cases alongside the existing one in
meter_query_test.go to cover other FilterStoredAt variants: a case using
filter.FilterTimeUnix with FilterTime.Gte set (use storedAtOffset and expect
stored_at >= ? in wantSQL and storedAtOffset.Unix() in wantArgs), a case with an
empty/nil FilterStoredAt to ensure no stored_at predicate is emitted, and a case
with nested logical filters (e.g., $and/$or) to assert correct SQL generation
for combined conditions; locate the query definitions using the queryMeter
struct and the FilterStoredAt field, mirror the existing pattern (Meter,
From/To, GroupBy, EnableDecimalPrecision) and provide corresponding wantSQL and
wantArgs for each variant to lock down SQL generation behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e45d3707-e039-4b6c-80b3-c567395441c9

📥 Commits

Reviewing files that changed from the base of the PR and between 0387673 and 9a1bdac.

📒 Files selected for processing (6)
  • openmeter/streaming/clickhouse/connector.go
  • openmeter/streaming/clickhouse/event_query_test.go
  • openmeter/streaming/clickhouse/meter_query.go
  • openmeter/streaming/clickhouse/meter_query_test.go
  • openmeter/streaming/query_params.go
  • pkg/filter/filter.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • openmeter/streaming/query_params.go
  • openmeter/streaming/clickhouse/connector.go

@turip turip merged commit 8243d0a into main Mar 18, 2026
37 of 38 checks passed
@turip turip deleted the feat/query-stored-at-filter branch March 18, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/misc Miscellaneous changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants