Skip to content

feat: add plan addon filters#4366

Open
borosr wants to merge 2 commits into
mainfrom
feat/planaddon-v3-api-filters
Open

feat: add plan addon filters#4366
borosr wants to merge 2 commits into
mainfrom
feat/planaddon-v3-api-filters

Conversation

@borosr
Copy link
Copy Markdown
Collaborator

@borosr borosr commented May 15, 2026

Add filters and sorting to the List Plan Addons endpoint

What

Adds filter[*] query parameters and a sort query parameter to GET /api/v3/plans/{planId}/addons.

Supported filters: id, plan_key, addon_id, addon_key, addon_name, plan_currency (passing filter[plan_id] is rejected since the plan is already scoped via the path parameter).

Supported sort fields: id (default), created_at, updated_at, with optional asc/desc suffix.

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

  • Extended the TypeSpec model with ListPlanAddonsParamsFilter and wired sort/filter query params into listPlanAddons
  • Regenerated OpenAPI spec and Go server bindings
  • Updated the HTTP handler to parse and validate filter/sort params, then pass them into ListPlanAddonsRequest
  • Propagated the new fields through the service and adapter layers

Testing

Filter by addon key:

curl -s "http://localhost:8888/api/v3/plans/01HX.../addons?filter[addon_key]=storage-addon"

Sort by creation date descending:

curl -s -H "Authorization: Bearer $OPENMETER_API_KEY" \
  "http://localhost:8888/api/v3/plans/01HX.../addons?sort=created_at%3Adesc"

Summary by CodeRabbit

  • New Features

    • Add query-time deep-object filtering for plan add‑ons by id, plan id/key, add‑on id/key/name, and plan currency.
    • Add sorting for plan add‑ons listing (id default, created_at, updated_at).
  • Bug Fixes / Behavior

    • Request handling now distinguishes plan ID vs plan key and validates incoming filter parameters, returning errors for invalid values.
  • Tests

    • Expanded tests covering filtering, sorting, and no-match scenarios.

Review Change Stack

@borosr borosr requested a review from tothandras May 15, 2026 10:38
@borosr borosr self-assigned this May 15, 2026
@borosr borosr requested a review from a team as a code owner May 15, 2026 10:38
@borosr borosr added the release-note/ignore Ignore this change when generating release notes label May 15, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9ccf1b3d-d3ab-4a09-a7de-2c8b13081da5

📥 Commits

Reviewing files that changed from the base of the PR and between b411e6d and 9bef020.

⛔ Files ignored due to path filters (1)
  • api/v3/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (3)
  • api/spec/packages/aip/src/productcatalog/operations.tsp
  • api/v3/api.gen.go
  • api/v3/handlers/plans/planaddons/lists.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • api/spec/packages/aip/src/productcatalog/operations.tsp

📝 Walkthrough

Walkthrough

Adds deepObject-style filtering and sort support to ListPlanAddons: API contract and generated types, handler binding and validation, service input typed filters and validation, adapter predicate construction using filter helpers, and updated tests.

Changes

ListPlanAddons Filter & Sort Implementation

Layer / File(s) Summary
API contract and code generation
api/spec/packages/aip/src/productcatalog/operations.tsp, api/v3/api.gen.go
TypeSpec adds ListPlanAddonsParamsFilter with plan/addon id/key/name and plan_currency; listPlanAddons documents supported sort attributes and wires filter as deepObject; codegen adds ListPlanAddonsParamsFilter type, extends ListPlanAddonsParams with Sort/Filter, and updates middleware and swagger payload.
HTTP handler binding, parsing, and validation
api/v3/handlers/plans/planaddons/lists.go, openmeter/productcatalog/planaddon/httpdriver/planaddon.go
Handlers import filter/sort helpers, enforce plan scoping from path or key, parse optional deepObject filters (id, plan_key, addon_id, addon_key, addon_name, plan_currency) into typed request fields, return 400 on parse errors, and map sort to OrderBy/Order.
Service input types and validation
openmeter/productcatalog/planaddon/service.go
Replaces slice-based filters (IDs, PlanIDs, PlanKeys, etc.) with pointer-typed filters (ID, PlanID, PlanKey, AddonID, AddonKey, AddonName, PlanCurrency) and updates Validate() to validate each non-nil filter and aggregate errors.
Adapter query predicate construction
openmeter/productcatalog/planaddon/adapter/planaddon.go
Refactors query building to use filter.ApplyToQuery/helpers: apply assignment-level ID predicates, build HasPlanWith and HasAddonWith predicates combining per-field filters, and convert key→version maps into OR predicates inside relation predicates.
HTTP driver request mapping
openmeter/productcatalog/planaddon/httpdriver/planaddon.go
Branches on ULID vs key for PlanIDOrKey, wires KeyVersion into AddonKeyVersions, and maps params.Id/params.Key into typed addon ID/key filters.
Filter helper utilities
pkg/filter/filter.go
Adds generic ApplyToPredicate helper that conditionally appends a typed Ent predicate selected from a filter into a predicate slice.
Test updates for filters and sorting
openmeter/productcatalog/planaddon/adapter/adapter_test.go, openmeter/productcatalog/planaddon/service/service_test.go
Tests updated to use FilterULID/FilterString inputs for ID, PlanID, AddonID, PlanKey, AddonKey, AddonName, and PlanCurrency; include sorting checks and no-match edge cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • openmeterio/openmeter#4164: Adds deepObject filter[...] support and refactors list request/adapter code to use shared pkg/filter helpers for a different resource (features), similar pattern to this PR.

Suggested labels

release-note/feature

Suggested reviewers

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

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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 'feat: add plan addon filters' directly and accurately describes the main change: adding filtering and sorting capabilities to the Plan Addons endpoint.
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 feat/planaddon-v3-api-filters

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.

@borosr borosr force-pushed the feat/planaddon-v3-api-filters branch from 7da7fd2 to b411e6d Compare May 15, 2026 10:42
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: 1

🧹 Nitpick comments (1)
openmeter/productcatalog/planaddon/service/service_test.go (1)

396-416: ⚡ Quick win

Sort 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/id and 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

📥 Commits

Reviewing files that changed from the base of the PR and between f67a8a1 and 7da7fd2.

⛔ Files ignored due to path filters (1)
  • api/v3/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (9)
  • api/spec/packages/aip/src/productcatalog/operations.tsp
  • api/v3/api.gen.go
  • api/v3/handlers/plans/planaddons/lists.go
  • openmeter/productcatalog/planaddon/adapter/adapter_test.go
  • openmeter/productcatalog/planaddon/adapter/planaddon.go
  • openmeter/productcatalog/planaddon/httpdriver/planaddon.go
  • openmeter/productcatalog/planaddon/service.go
  • openmeter/productcatalog/planaddon/service/service_test.go
  • pkg/filter/filter.go

Comment thread api/spec/packages/aip/src/productcatalog/operations.tsp Outdated
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.

1 participant