Skip to content

Commit ed2e077

Browse files
committed
feat: add filter and sort to billing profile
1 parent 499cdc5 commit ed2e077

8 files changed

Lines changed: 1007 additions & 655 deletions

File tree

api/spec/packages/aip/src/billing/operations.tsp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ using TypeSpec.OpenAPI;
1313

1414
namespace Billing;
1515

16+
/**
17+
* Filter options for listing billing profiles.
18+
*/
19+
@friendlyName("ListBillingProfilesParamsFilter")
20+
model ListBillingProfilesParamsFilter {
21+
#suppress "@openmeter/api-spec-aip/doc-decorator" "filter field"
22+
id?: Common.ULIDFieldFilter;
23+
#suppress "@openmeter/api-spec-aip/doc-decorator" "filter field"
24+
name?: Common.StringFieldFilter;
25+
}
26+
1627
interface BillingProfilesOperations {
1728
/**
1829
* List billing profiles.
@@ -22,6 +33,29 @@ interface BillingProfilesOperations {
2233
@summary("List billing profiles")
2334
list(
2435
...Common.PagePaginationQuery,
36+
37+
/**
38+
* Sort billing profiles returned in the response. Supported sort attributes are:
39+
*
40+
* - `id`
41+
* - `name`
42+
* - `created_at` (default)
43+
* - `updated_at`
44+
*
45+
* The `asc` suffix is optional as the default sort order is ascending. The `desc`
46+
* suffix is used to specify a descending order.
47+
*/
48+
@query(#{ name: "sort" })
49+
sort?: Common.SortQuery,
50+
51+
/**
52+
* Filter billing profiles returned in the response.
53+
*
54+
* To filter billing profiles by name add the following query param:
55+
* filter[name]=my-profile
56+
*/
57+
@query(#{ style: "deepObject", explode: true })
58+
filter?: ListBillingProfilesParamsFilter,
2559
): Shared.PagePaginatedResponse<BillingProfile> | Common.ErrorResponses;
2660

2761
/**

api/v3/api.gen.go

Lines changed: 690 additions & 644 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v3/handlers/billingprofiles/list.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99

1010
api "github.com/openmeterio/openmeter/api/v3"
1111
"github.com/openmeterio/openmeter/api/v3/apierrors"
12+
"github.com/openmeterio/openmeter/api/v3/filters"
13+
"github.com/openmeterio/openmeter/api/v3/request"
1214
"github.com/openmeterio/openmeter/api/v3/response"
1315
"github.com/openmeterio/openmeter/openmeter/billing"
1416
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
@@ -57,6 +59,35 @@ func (h *handler) ListBillingProfiles() ListBillingProfilesHandler {
5759
},
5860
}
5961

62+
if params.Sort != nil {
63+
sort, err := request.ParseSortBy(*params.Sort)
64+
if err != nil {
65+
return ListBillingProfilesRequest{}, apierrors.NewBadRequestError(ctx, err, apierrors.InvalidParameters{
66+
{Field: "sort", Reason: err.Error(), Source: apierrors.InvalidParamSourceQuery},
67+
})
68+
}
69+
req.OrderBy = billing.OrderBy(sort.Field)
70+
req.Order = sort.Order.ToSortxOrder()
71+
}
72+
73+
if params.Filter != nil {
74+
id, err := filters.FromAPIFilterULID(params.Filter.Id)
75+
if err != nil {
76+
return ListBillingProfilesRequest{}, apierrors.NewBadRequestError(ctx, err, apierrors.InvalidParameters{
77+
{Field: "filter[id]", Reason: err.Error(), Source: apierrors.InvalidParamSourceQuery},
78+
})
79+
}
80+
req.ID = id
81+
82+
name, err := filters.FromAPIFilterString(params.Filter.Name)
83+
if err != nil {
84+
return ListBillingProfilesRequest{}, apierrors.NewBadRequestError(ctx, err, apierrors.InvalidParameters{
85+
{Field: "filter[name]", Reason: err.Error(), Source: apierrors.InvalidParamSourceQuery},
86+
})
87+
}
88+
req.Name = name
89+
}
90+
6091
return req, nil
6192
},
6293
func(ctx context.Context, request ListBillingProfilesRequest) (ListBillingProfilesResponse, error) {

api/v3/openapi.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,6 +2377,34 @@ paths:
23772377
description: List billing profiles.
23782378
parameters:
23792379
- $ref: '#/components/parameters/PagePaginationQuery'
2380+
- name: sort
2381+
in: query
2382+
required: false
2383+
description: |-
2384+
Sort billing profiles returned in the response. Supported sort attributes are:
2385+
2386+
- `id`
2387+
- `name`
2388+
- `created_at` (default)
2389+
- `updated_at`
2390+
2391+
The `asc` suffix is optional as the default sort order is ascending. The `desc`
2392+
suffix is used to specify a descending order.
2393+
schema:
2394+
$ref: '#/components/schemas/SortQuery'
2395+
explode: false
2396+
style: form
2397+
- name: filter
2398+
in: query
2399+
required: false
2400+
description: |-
2401+
Filter billing profiles returned in the response.
2402+
2403+
To filter billing profiles by name add the following query param:
2404+
filter[name]=my-profile
2405+
schema:
2406+
$ref: '#/components/schemas/ListBillingProfilesParamsFilter'
2407+
style: deepObject
23802408
responses:
23812409
'200':
23822410
description: Page paginated response.
@@ -8189,6 +8217,15 @@ components:
81898217
$ref: '#/components/schemas/StringFieldFilterExact'
81908218
additionalProperties: false
81918219
description: Filter options for listing add-ons.
8220+
ListBillingProfilesParamsFilter:
8221+
type: object
8222+
properties:
8223+
id:
8224+
$ref: '#/components/schemas/ULIDFieldFilter'
8225+
name:
8226+
$ref: '#/components/schemas/StringFieldFilter'
8227+
additionalProperties: false
8228+
description: Filter options for listing billing profiles.
81928229
ListChargesParamsFilter:
81938230
type: object
81948231
properties:

openmeter/billing/adapter/profile.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88

99
"github.com/samber/lo"
1010

11-
"github.com/openmeterio/openmeter/api"
1211
"github.com/openmeterio/openmeter/openmeter/app"
1312
"github.com/openmeterio/openmeter/openmeter/billing"
1413
"github.com/openmeterio/openmeter/openmeter/customer"
@@ -23,6 +22,7 @@ import (
2322
taxcodeadapter "github.com/openmeterio/openmeter/openmeter/taxcode/adapter"
2423
"github.com/openmeterio/openmeter/pkg/clock"
2524
"github.com/openmeterio/openmeter/pkg/convert"
25+
"github.com/openmeterio/openmeter/pkg/filter"
2626
"github.com/openmeterio/openmeter/pkg/framework/entutils"
2727
"github.com/openmeterio/openmeter/pkg/models"
2828
"github.com/openmeterio/openmeter/pkg/pagination"
@@ -160,20 +160,23 @@ func (a *adapter) ListProfiles(ctx context.Context, input billing.ListProfilesIn
160160
query = query.Where(billingprofile.DeletedAtIsNil())
161161
}
162162

163+
query = filter.ApplyToQuery(query, input.ID, billingprofile.FieldID)
164+
query = filter.ApplyToQuery(query, input.Name, billingprofile.FieldName)
165+
163166
order := entutils.GetOrdering(sortx.OrderDefault)
164167
if !input.Order.IsDefaultValue() {
165168
order = entutils.GetOrdering(input.Order)
166169
}
167170

168171
switch input.OrderBy {
169-
case api.BillingProfileOrderByCreatedAt:
170-
query = query.Order(billingprofile.ByCreatedAt(order...))
171-
case api.BillingProfileOrderByUpdatedAt:
172-
query = query.Order(billingprofile.ByUpdatedAt(order...))
173-
case api.BillingProfileOrderByName:
172+
case billing.OrderByID:
173+
query = query.Order(billingprofile.ByID(order...))
174+
case billing.OrderByName:
174175
query = query.Order(billingprofile.ByName(order...))
175-
case api.BillingProfileOrderByDefault:
176-
query = query.Order(billingprofile.ByDefault(order...))
176+
case billing.OrderByUpdatedAt:
177+
query = query.Order(billingprofile.ByUpdatedAt(order...))
178+
case billing.OrderByCreatedAt, billing.OrderByDefault:
179+
fallthrough
177180
default:
178181
query = query.Order(billingprofile.ByCreatedAt(order...))
179182
}

openmeter/billing/httpdriver/profile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ func (h *handler) ListProfiles() ListProfilesHandler {
248248
return ListProfilesRequest{
249249
Namespace: ns,
250250
IncludeArchived: lo.FromPtrOr(params.IncludeArchived, DefaultIncludeArchived),
251-
OrderBy: lo.FromPtrOr(params.OrderBy, api.BillingProfileOrderByCreatedAt),
251+
OrderBy: billing.OrderBy(lo.FromPtrOr(params.OrderBy, api.BillingProfileOrderByCreatedAt)),
252252
Order: sortx.Order(lo.FromPtrOr(params.Order, api.SortOrderDESC)),
253253

254254
Page: pagination.Page{

openmeter/billing/profile.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/openmeterio/openmeter/openmeter/app"
1313
"github.com/openmeterio/openmeter/openmeter/productcatalog"
1414
"github.com/openmeterio/openmeter/pkg/datetime"
15+
"github.com/openmeterio/openmeter/pkg/filter"
1516
"github.com/openmeterio/openmeter/pkg/models"
1617
"github.com/openmeterio/openmeter/pkg/pagination"
1718
"github.com/openmeterio/openmeter/pkg/sortx"
@@ -366,15 +367,43 @@ type CreateProfileAppsInput = ProfileAppReferences
366367

367368
type ListProfilesResult = pagination.Result[Profile]
368369

370+
type OrderBy string
371+
372+
func (o OrderBy) Values() []OrderBy {
373+
return []OrderBy{
374+
OrderByCreatedAt,
375+
OrderByUpdatedAt,
376+
OrderByName,
377+
}
378+
}
379+
380+
func (o OrderBy) Validate() error {
381+
if !slices.Contains(o.Values(), o) {
382+
return fmt.Errorf("invalid order by: %s", o)
383+
}
384+
return nil
385+
}
386+
387+
const (
388+
OrderByID OrderBy = "id"
389+
OrderByCreatedAt OrderBy = OrderBy(api.BillingProfileOrderByCreatedAt)
390+
OrderByUpdatedAt OrderBy = OrderBy(api.BillingProfileOrderByUpdatedAt)
391+
OrderByName OrderBy = OrderBy(api.BillingProfileOrderByName)
392+
OrderByDefault OrderBy = OrderBy(api.BillingProfileOrderByDefault)
393+
)
394+
369395
type ListProfilesInput struct {
370396
pagination.Page
371397

372398
Expand ProfileExpand
373399

374400
Namespace string
375401
IncludeArchived bool
376-
OrderBy api.BillingProfileOrderBy
402+
OrderBy OrderBy
377403
Order sortx.Order
404+
405+
ID *filter.FilterULID
406+
Name *filter.FilterString
378407
}
379408

380409
func (i ListProfilesInput) Validate() error {
@@ -386,7 +415,25 @@ func (i ListProfilesInput) Validate() error {
386415
return fmt.Errorf("error validating expand: %w", err)
387416
}
388417

389-
return nil
418+
var errs []error
419+
if i.ID != nil {
420+
if err := i.ID.Validate(); err != nil {
421+
errs = append(errs, err)
422+
}
423+
}
424+
if i.Name != nil {
425+
if err := i.Name.Validate(); err != nil {
426+
errs = append(errs, err)
427+
}
428+
}
429+
430+
if i.OrderBy != "" {
431+
if err := i.OrderBy.Validate(); err != nil {
432+
errs = append(errs, err)
433+
}
434+
}
435+
436+
return models.NewNillableGenericValidationError(errors.Join(errs...))
390437
}
391438

392439
type ProfileExpand struct {

0 commit comments

Comments
 (0)