feat: add plan addon filters#4366
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (9)
🚧 Files skipped from review as they are similar to previous changes (7)
📝 WalkthroughWalkthroughAdds deepObject-style filtering and sortable queries to ListPlanAddons: API spec and generated types, middleware binding, handler parsing, service input/validation, adapter predicate refactor using shared filter helpers, and updated tests. ChangesListPlanAddons Filter & Sort Implementation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
7da7fd2 to
b411e6d
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
openmeter/productcatalog/planaddon/service/service_test.go (1)
396-416: ⚡ Quick winSort tests don’t currently prove sorting behavior.
Right now these checks only assert non-empty results, so they can pass even if ordering is wrong. Please add at least two plan-addon assignments with distinct
created_at/idand assert relative order in the returned list.As per coding guidelines: “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 current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openmeter/productcatalog/planaddon/service/service_test.go` around lines 396 - 416, The two sort tests (SortByCreatedAtDesc and SortByID) only assert non-empty results; create two distinct plan-addon records before each test (use env.PlanAddon.CreatePlanAddon or the test fixture helper) with different created_at timestamps and/or IDs, then call env.PlanAddon.ListPlanAddons with ListPlanAddonsInput (OrderByCreatedAt/OrderByID and OrderDesc/OrderAsc) and assert the returned Items are ordered by comparing Items[0].ID vs Items[1].ID or Items[0].CreatedAt vs Items[1].CreatedAt as appropriate; keep this setup and assertions inside the existing t.Run blocks to ensure the tests validate ordering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@api/spec/packages/aip/src/productcatalog/operations.tsp`:
- Line 293: Remove the plan_id filter field from the filter model: delete the
"plan_id?: Common.ULIDFieldFilter;" entry so the TypeSpec model no longer
advertises filter[plan_id]; this ensures the model matches runtime behavior
where planId is provided via the path parameter. Update any related model/type
declarations that reference this field (and associated docs/tests) to avoid
exposing or validating plan_id in the filter. Ensure compilation/typechecks pass
after removing the field.
---
Nitpick comments:
In `@openmeter/productcatalog/planaddon/service/service_test.go`:
- Around line 396-416: The two sort tests (SortByCreatedAtDesc and SortByID)
only assert non-empty results; create two distinct plan-addon records before
each test (use env.PlanAddon.CreatePlanAddon or the test fixture helper) with
different created_at timestamps and/or IDs, then call
env.PlanAddon.ListPlanAddons with ListPlanAddonsInput
(OrderByCreatedAt/OrderByID and OrderDesc/OrderAsc) and assert the returned
Items are ordered by comparing Items[0].ID vs Items[1].ID or Items[0].CreatedAt
vs Items[1].CreatedAt as appropriate; keep this setup and assertions inside the
existing t.Run blocks to ensure the tests validate ordering.
🪄 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: c3685fee-aac8-4a51-8c0c-0393da3f779b
⛔ Files ignored due to path filters (1)
api/v3/openapi.yamlis excluded by!**/openapi.yaml
📒 Files selected for processing (9)
api/spec/packages/aip/src/productcatalog/operations.tspapi/v3/api.gen.goapi/v3/handlers/plans/planaddons/lists.goopenmeter/productcatalog/planaddon/adapter/adapter_test.goopenmeter/productcatalog/planaddon/adapter/planaddon.goopenmeter/productcatalog/planaddon/httpdriver/planaddon.goopenmeter/productcatalog/planaddon/service.goopenmeter/productcatalog/planaddon/service/service_test.gopkg/filter/filter.go
| // Detect whether PlanIDOrKey is a ULID or a key string. | ||
| if _, err := ulid.Parse(params.PlanIDOrKey); err == nil { | ||
| req.PlanID = &filter.FilterULID{FilterString: filter.FilterString{Eq: lo.ToPtr(params.PlanIDOrKey)}} | ||
| } else { | ||
| req.PlanKey = &filter.FilterString{Eq: lo.ToPtr(params.PlanIDOrKey)} | ||
| } | ||
|
|
||
| if ids := lo.FromPtrOr(params.Id, nil); len(ids) > 0 { | ||
| req.AddonID = &filter.FilterULID{FilterString: filter.FilterString{In: lo.ToPtr(ids)}} | ||
| } | ||
|
|
||
| if keys := lo.FromPtrOr(params.Key, nil); len(keys) > 0 { | ||
| req.AddonKey = &filter.FilterString{In: lo.ToPtr(keys)} | ||
| } |
There was a problem hiding this comment.
This change breaks backward compatibility. v1 endpoint silently changes from OR to AND semantics. A v1 caller sending ?id=A,B&key=k1,k2 previously got the union; now gets the intersection.
I'd argue that this was the intended behavior for v1 all along and this is acceptable.
There was a problem hiding this comment.
I think we discussed this at a previously edited v3 endpoint that intersection would be the expected behavior. Should I revert this part to keep the union logic in the old APIs?
| require.NotEmptyf(t, listPlanAddons.Items, "plan add-on assignments must not be empty") | ||
| }) | ||
|
|
||
| t.Run("SortByID", func(t *testing.T) { |
There was a problem hiding this comment.
Every Order/OrderBy combination passes, including OrderBy("") and OrderBy("bogus"). Should we add validation to the handlers https://github.com/openmeterio/openmeter/pull/4366/changes#diff-116ada52ce8ebb117ef465249f9281dd0d490e07c226fb1c79909f6e87cca5a3R115?
There was a problem hiding this comment.
I think, this is a global issue, what do you think about resolving this in a separate PR?
| return q | ||
| } | ||
|
|
||
| func ApplyToPredicate[F Filter, P Predicate](arr []P, f *F, field string) []P { |
There was a problem hiding this comment.
Is this a function we could reuse? Why was this introduced?
There was a problem hiding this comment.
I created this function to simplify the code by removing code duplication inside the adapter layer. I guess it would be useful in other cases where we are using nested queries for filtering, such as here:
// ...
var planPreds []predicate.Plan
planPreds = filter.ApplyToPredicate(planPreds, params.PlanID, plandb.FieldID)
planPreds = filter.ApplyToPredicate(planPreds, params.PlanKey, plandb.FieldKey)
planPreds = filter.ApplyToPredicate(planPreds, params.PlanCurrency, plandb.FieldCurrency)
if len(planPreds) > 0 {
query = query.Where(planaddondb.HasPlanWith(planPreds...))
}There was a problem hiding this comment.
🧹 Nitpick comments (2)
openmeter/productcatalog/planaddon/service/service_test.go (2)
396-416: 🏗️ Heavy liftSort tests don’t validate ordering yet.
Both sort cases only check non-empty results. That can pass even if ordering is broken. Please add at least one additional assignment and assert the returned order for
created_at:descandid:asc.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 current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openmeter/productcatalog/planaddon/service/service_test.go` around lines 396 - 416, The sort test cases ("SortByCreatedAtDesc" and "SortByID") only assert non-empty results; add deterministic fixtures and explicit order assertions: create at least two plan-addons before calling env.PlanAddon.ListPlanAddons (use the same namespace) so you have known insertion order/IDs, then in the "SortByCreatedAtDesc" case assert that returned Items are ordered by CreatedAt descending (newest first) and in "SortByID" assert Items are ordered by ID ascending; update the t.Run blocks that call env.PlanAddon.ListPlanAddons (using planaddon.ListPlanAddonsInput, OrderByCreatedAt/OrderByID and OrderDesc/OrderAsc) to include these explicit comparisons of item IDs or CreatedAt timestamps immediately after require.NotEmptyf.
338-416: ⚡ Quick winPlease add
given/when/thenintent comments to these non-trivial subtests.The new filter/sort subtests are dense; quick intent comments at each subtest start would make failures much easier to scan.
As per coding guidelines
**/*_test.go: "For service and lifecycle subtests in Go, start each subtest body with concise intent comments using 'given:', 'when:', 'then:' format when the scenario is non-trivial".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@openmeter/productcatalog/planaddon/service/service_test.go` around lines 338 - 416, Add concise "given:/when:/then:" intent comments at the start of each non-trivial subtest body (the t.Run blocks named "ByPlanID", "ByAddonID", "ByAddonName", "ByCurrency", "NoMatch", "SortByCreatedAtDesc", and "SortByID") describing the setup (given), the call under test (when — e.g., calling env.PlanAddon.ListPlanAddons with the specific planaddon.ListPlanAddonsInput filter/order), and the expected outcome (then — e.g., expect 1 item, 0 items, or non-empty and no error); place the comments immediately inside each t.Run before invoking ListPlanAddons so test failures are easier to scan.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@openmeter/productcatalog/planaddon/service/service_test.go`:
- Around line 396-416: The sort test cases ("SortByCreatedAtDesc" and
"SortByID") only assert non-empty results; add deterministic fixtures and
explicit order assertions: create at least two plan-addons before calling
env.PlanAddon.ListPlanAddons (use the same namespace) so you have known
insertion order/IDs, then in the "SortByCreatedAtDesc" case assert that returned
Items are ordered by CreatedAt descending (newest first) and in "SortByID"
assert Items are ordered by ID ascending; update the t.Run blocks that call
env.PlanAddon.ListPlanAddons (using planaddon.ListPlanAddonsInput,
OrderByCreatedAt/OrderByID and OrderDesc/OrderAsc) to include these explicit
comparisons of item IDs or CreatedAt timestamps immediately after
require.NotEmptyf.
- Around line 338-416: Add concise "given:/when:/then:" intent comments at the
start of each non-trivial subtest body (the t.Run blocks named "ByPlanID",
"ByAddonID", "ByAddonName", "ByCurrency", "NoMatch", "SortByCreatedAtDesc", and
"SortByID") describing the setup (given), the call under test (when — e.g.,
calling env.PlanAddon.ListPlanAddons with the specific
planaddon.ListPlanAddonsInput filter/order), and the expected outcome (then —
e.g., expect 1 item, 0 items, or non-empty and no error); place the comments
immediately inside each t.Run before invoking ListPlanAddons so test failures
are easier to scan.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c0809fe7-7aa8-43f7-9447-0de28a08a7f2
📒 Files selected for processing (2)
openmeter/productcatalog/planaddon/adapter/adapter_test.goopenmeter/productcatalog/planaddon/service/service_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
- openmeter/productcatalog/planaddon/adapter/adapter_test.go
6e77082 to
3715ac1
Compare
Add filters and sorting to the List Plan Addons endpoint
What
Adds
filter[*]query parameters and asortquery parameter toGET /api/v3/openmeter/plans/{planId}/addons.Supported filters:
id,plan_key,addon_id,addon_key,addon_name,plan_currency(passingfilter[plan_id]is rejected since the plan is already scoped via the path parameter).Supported sort fields:
id(default),created_at,updated_at, with optionalasc/descsuffix.Why
Callers need a way to narrow down plan addon results without client-side filtering, e.g. finding all addons for a given currency or sorted by creation time.
How
ListPlanAddonsParamsFilterand wiredsort/filterquery params intolistPlanAddonsListPlanAddonsRequestTesting
Filter by addon key:
curl -s "http://localhost:8888/api/v3/openmeter/plans/01HX.../addons?filter[addon_key]=storage-addon"Sort by creation date descending:
Summary by CodeRabbit
New Features
Bug Fixes / Behavior
Tests