Skip to content

feat(api): simplify v3 query filter types#4218

Merged
tothandras merged 1 commit intomainfrom
fix/v3-openapi
Apr 24, 2026
Merged

feat(api): simplify v3 query filter types#4218
tothandras merged 1 commit intomainfrom
fix/v3-openapi

Conversation

@tothandras
Copy link
Copy Markdown
Contributor

@tothandras tothandras commented Apr 24, 2026

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Query filters now properly reject multiple operators applied to the same dimension, preventing ambiguous filter configurations.
  • Refactor

    • Simplified query filter validation model and streamlined constraint enforcement for improved clarity and maintainability.

@tothandras tothandras requested a review from a team as a code owner April 24, 2026 06:25
@tothandras tothandras added the release-note/ignore Ignore this change when generating release notes label Apr 24, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

📝 Walkthrough

Walkthrough

This change removes support for unknown/arbitrary filter operators across the codebase by eliminating the AdditionalProperties field from filter types, deleting associated validation functions, and shifting operator validation responsibility to downstream filter value validators. The generated API types are updated accordingly, and tests are adjusted to reflect the new constraints.

Changes

Cohort / File(s) Summary
TypeSpec Filter Definitions
api/spec/packages/aip/src/shared/filters.tsp
Removed @minProperties(1), @maxProperties(1) decorators and ...Record<never>; spreads from QueryFilterString, QueryFilterStringMapItem, QueryFilterInteger, QueryFilterFloat, QueryFilterNumeric, QueryFilterBoolean, and QueryFilterDateTime models.
Generated API Types
api/v3/api.gen.go
Removed AdditionalProperties map[string]interface{} field and custom Get/Set/MarshalJSON/UnmarshalJSON methods from QueryFilterString and QueryFilterStringMapItem types; regenerated swagger spec payload.
Handler Validation
api/v3/handlers/features/create.go, api/v3/handlers/features/create_test.go
Removed per-filter operator validation calls; now relies on downstream feature.MeterGroupByFilters.Validate for constraint enforcement. Deleted test case for unknown operator scenarios.
Query Conversion & Validation
api/v3/handlers/meters/query/convert.go, api/v3/handlers/meters/query/convert_test.go
Removed ValidateQueryFilterString, ValidateQueryFilterStringMapItem functions and firstKey helper; eliminated test coverage for unknown operator validation while preserving conversion/extraction tests.
Query Filter Error Handling
api/v3/handlers/meters/query/errors.go
Removed ErrUnknownFilterOperator, NewUnknownFilterOperatorError, and ErrCodeUnknownFilterOperator definitions; remaining code uses "unsupported_filter_operator" error instead.
Query Parameter Building
api/v3/handlers/meters/query/params.go, api/v3/handlers/meters/query/params_test.go
Removed ValidateQueryFilterStringMapItem call for dimension filters; tests updated to verify multiple-operator detection via field-level constraints rather than AdditionalProperties-based unknown operators.
Feature/Meter Validation
openmeter/productcatalog/feature/feature.go, openmeter/productcatalog/feature/meter_group_by_filters_test.go
Added validation of filter values via filterValue.Validate() in MeterGroupByFilters.Validate; new test file covers scenarios for single operator, unknown keys, and multiple operators on the same filter.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • gergely-kurucz-konghq
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 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 change: simplifying v3 query filter types by removing property constraints and additional properties support across multiple filter models.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 fix/v3-openapi

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.

@tothandras tothandras enabled auto-merge (squash) April 24, 2026 06:28
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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/v3/api.gen.go (1)

4724-4750: ⚠️ Potential issue | 🟠 Major

Make and/or recurse into QueryFilterStringMapItem.

Line 4726 and Line 4750 currently branch into []QueryFilterString, which drops the exists operator from any nested boolean expression. That makes valid map-item filters like {"or":[{"exists":false},{"eq":"foo"}]} impossible to represent with the generated Go types.

Suggested shape after fixing the source schema and regenerating
 type QueryFilterStringMapItem struct {
 	// And Combines the provided filters with a logical AND.
-	And *[]QueryFilterString `json:"and,omitempty"`
+	And *[]QueryFilterStringMapItem `json:"and,omitempty"`
@@
 	// Or Combines the provided filters with a logical OR.
-	Or *[]QueryFilterString `json:"or,omitempty"`
+	Or *[]QueryFilterStringMapItem `json:"or,omitempty"`
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/v3/api.gen.go` around lines 4724 - 4750, The And and Or fields on
QueryFilterStringMapItem currently reference []QueryFilterString which prevents
nested map-item operators like "exists" from being represented; change the types
of And and Or on QueryFilterStringMapItem to *[]QueryFilterStringMapItem (so
nested boolean expressions recurse into the same map-item shape), update any
usages that construct or parse those fields to expect the new type, and
regenerate or run codegen/tests to ensure the schema change is applied
consistently.
🧹 Nitpick comments (1)
openmeter/productcatalog/feature/meter_group_by_filters_test.go (1)

13-50: Solid coverage for the new validation path! 👍

The three sub-tests hit the key cases nicely: happy path, unknown dimension key, and the multi-operator rejection (which is really what this PR hinges on downstream).

Optional nit if you're feeling completionist: you could also add a tiny assertion that the returned error on the unknown-key case is (or wraps) a *FeatureInvalidFiltersError — that way a future refactor that accidentally swallows the type still gets caught. Totally fine to skip.

🧪 Optional extra assertion
 	t.Run("unknown dimension key", func(t *testing.T) {
 		f := MeterGroupByFilters{
 			"nonexistent": filter.FilterString{Eq: lo.ToPtr("value")},
 		}

 		err := f.Validate(m)
 		require.Error(t, err)
+		var invalidErr *FeatureInvalidFiltersError
+		require.ErrorAs(t, err, &invalidErr)
 	})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openmeter/productcatalog/feature/meter_group_by_filters_test.go` around lines
13 - 50, In the unknown-dimension-key sub-test of
TestMeterGroupByFiltersValidate, add an assertion that the returned error from
MeterGroupByFilters.Validate(m) is (or wraps) a *FeatureInvalidFiltersError to
guard against type-swallowing refactors; keep the existing require.Error check,
then use errors.As (or require.ErrorAs) to verify the concrete error type is
*FeatureInvalidFiltersError, referencing MeterGroupByFilters.Validate and
FeatureInvalidFiltersError so the test fails if the wrong error type is
returned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@api/v3/api.gen.go`:
- Around line 4724-4750: The And and Or fields on QueryFilterStringMapItem
currently reference []QueryFilterString which prevents nested map-item operators
like "exists" from being represented; change the types of And and Or on
QueryFilterStringMapItem to *[]QueryFilterStringMapItem (so nested boolean
expressions recurse into the same map-item shape), update any usages that
construct or parse those fields to expect the new type, and regenerate or run
codegen/tests to ensure the schema change is applied consistently.

---

Nitpick comments:
In `@openmeter/productcatalog/feature/meter_group_by_filters_test.go`:
- Around line 13-50: In the unknown-dimension-key sub-test of
TestMeterGroupByFiltersValidate, add an assertion that the returned error from
MeterGroupByFilters.Validate(m) is (or wraps) a *FeatureInvalidFiltersError to
guard against type-swallowing refactors; keep the existing require.Error check,
then use errors.As (or require.ErrorAs) to verify the concrete error type is
*FeatureInvalidFiltersError, referencing MeterGroupByFilters.Validate and
FeatureInvalidFiltersError so the test fails if the wrong error type is
returned.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5efd9ed2-75e5-4d34-9a95-853eeb0ca617

📥 Commits

Reviewing files that changed from the base of the PR and between 4484dfd and f0f4ad3.

⛔ Files ignored due to path filters (1)
  • api/v3/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (11)
  • api/spec/packages/aip/src/shared/filters.tsp
  • api/v3/api.gen.go
  • api/v3/handlers/features/create.go
  • api/v3/handlers/features/create_test.go
  • api/v3/handlers/meters/query/convert.go
  • api/v3/handlers/meters/query/convert_test.go
  • api/v3/handlers/meters/query/errors.go
  • api/v3/handlers/meters/query/params.go
  • api/v3/handlers/meters/query/params_test.go
  • openmeter/productcatalog/feature/feature.go
  • openmeter/productcatalog/feature/meter_group_by_filters_test.go
💤 Files with no reviewable changes (6)
  • api/v3/handlers/features/create_test.go
  • api/v3/handlers/meters/query/convert_test.go
  • api/v3/handlers/meters/query/errors.go
  • api/v3/handlers/meters/query/params.go
  • api/v3/handlers/meters/query/convert.go
  • api/spec/packages/aip/src/shared/filters.tsp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/ignore Ignore this change when generating release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants