diff --git a/api/api.gen.go b/api/api.gen.go index d957210b1..14ed29b35 100644 --- a/api/api.gen.go +++ b/api/api.gen.go @@ -719,6 +719,75 @@ type IngestedEvent struct { ValidationError *string `json:"validationError,omitempty"` } +// ListEntitlementGrantResponse defines model for ListEntitlementGrantResponse. +type ListEntitlementGrantResponse struct { + union json.RawMessage +} + +// ListEntitlementGrantResponse0 defines model for . +type ListEntitlementGrantResponse0 = []EntitlementGrant + +// ListEntitlementGrantResponse1 defines model for . +type ListEntitlementGrantResponse1 struct { + // Items List of grants. + Items []EntitlementGrant `json:"items"` + + // Page Current page number. + Page int `json:"page"` + + // PageSize Number of grants per page. + PageSize int `json:"pageSize"` + + // TotalCount Total number of grants. + TotalCount int `json:"totalCount"` +} + +// ListEntitlementResponse defines model for ListEntitlementResponse. +type ListEntitlementResponse struct { + union json.RawMessage +} + +// ListEntitlementResponse0 defines model for . +type ListEntitlementResponse0 = []Entitlement + +// ListEntitlementResponse1 defines model for . +type ListEntitlementResponse1 struct { + // Items List of entitlements. + Items []Entitlement `json:"items"` + + // Page Current page number. + Page int `json:"page"` + + // PageSize Number of entitlements per page. + PageSize int `json:"pageSize"` + + // TotalCount Total number of entitlements. + TotalCount int `json:"totalCount"` +} + +// ListFeatureResponse defines model for ListFeatureResponse. +type ListFeatureResponse struct { + union json.RawMessage +} + +// ListFeatureResponse0 defines model for . +type ListFeatureResponse0 = []Feature + +// ListFeatureResponse1 defines model for . +type ListFeatureResponse1 struct { + // Items List of features. + Items []Feature `json:"items"` + + // Page Current page number. + Page int `json:"page"` + + // PageSize Number of features per page. + PageSize int `json:"pageSize"` + + // TotalCount Total number of features. + TotalCount int `json:"totalCount"` +} + // Meter A meter is a configuration that defines how to match and aggregate events. type Meter = models.Meter @@ -1209,6 +1278,12 @@ type QueryLimit = int // QueryOffset defines model for queryOffset. type QueryOffset = int +// QueryPage defines model for queryPage. +type QueryPage = int + +// QueryPageSize defines model for queryPageSize. +type QueryPageSize = int + // QueryTo defines model for queryTo. type QueryTo = time.Time @@ -1249,6 +1324,12 @@ type UnexpectedProblemResponse = Problem // ListEntitlementsParams defines parameters for ListEntitlements. type ListEntitlementsParams struct { + // Page Page number to return + Page *QueryPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of entries to return per page + PageSize *QueryPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + // Limit Number of entries to return Limit *QueryLimit `form:"limit,omitempty" json:"limit,omitempty"` @@ -1281,6 +1362,12 @@ type IngestEventsApplicationCloudeventsBatchPlusJSONBody = []Event // ListFeaturesParams defines parameters for ListFeatures. type ListFeaturesParams struct { + // Page Page number to return + Page *QueryPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of entries to return per page + PageSize *QueryPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + // Limit Number of entries to return Limit *QueryLimit `form:"limit,omitempty" json:"limit,omitempty"` @@ -1299,6 +1386,12 @@ type ListFeaturesParamsOrderBy string // ListGrantsParams defines parameters for ListGrants. type ListGrantsParams struct { + // Page Page number to return + Page *QueryPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of entries to return per page + PageSize *QueryPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + // Limit Number of entries to return Limit *QueryLimit `form:"limit,omitempty" json:"limit,omitempty"` @@ -1922,6 +2015,192 @@ func (t *EntitlementCreateInputs) UnmarshalJSON(b []byte) error { return err } +// AsListEntitlementGrantResponse0 returns the union data inside the ListEntitlementGrantResponse as a ListEntitlementGrantResponse0 +func (t ListEntitlementGrantResponse) AsListEntitlementGrantResponse0() (ListEntitlementGrantResponse0, error) { + var body ListEntitlementGrantResponse0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementGrantResponse0 overwrites any union data inside the ListEntitlementGrantResponse as the provided ListEntitlementGrantResponse0 +func (t *ListEntitlementGrantResponse) FromListEntitlementGrantResponse0(v ListEntitlementGrantResponse0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementGrantResponse0 performs a merge with any union data inside the ListEntitlementGrantResponse, using the provided ListEntitlementGrantResponse0 +func (t *ListEntitlementGrantResponse) MergeListEntitlementGrantResponse0(v ListEntitlementGrantResponse0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsListEntitlementGrantResponse1 returns the union data inside the ListEntitlementGrantResponse as a ListEntitlementGrantResponse1 +func (t ListEntitlementGrantResponse) AsListEntitlementGrantResponse1() (ListEntitlementGrantResponse1, error) { + var body ListEntitlementGrantResponse1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementGrantResponse1 overwrites any union data inside the ListEntitlementGrantResponse as the provided ListEntitlementGrantResponse1 +func (t *ListEntitlementGrantResponse) FromListEntitlementGrantResponse1(v ListEntitlementGrantResponse1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementGrantResponse1 performs a merge with any union data inside the ListEntitlementGrantResponse, using the provided ListEntitlementGrantResponse1 +func (t *ListEntitlementGrantResponse) MergeListEntitlementGrantResponse1(v ListEntitlementGrantResponse1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ListEntitlementGrantResponse) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ListEntitlementGrantResponse) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsListEntitlementResponse0 returns the union data inside the ListEntitlementResponse as a ListEntitlementResponse0 +func (t ListEntitlementResponse) AsListEntitlementResponse0() (ListEntitlementResponse0, error) { + var body ListEntitlementResponse0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementResponse0 overwrites any union data inside the ListEntitlementResponse as the provided ListEntitlementResponse0 +func (t *ListEntitlementResponse) FromListEntitlementResponse0(v ListEntitlementResponse0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementResponse0 performs a merge with any union data inside the ListEntitlementResponse, using the provided ListEntitlementResponse0 +func (t *ListEntitlementResponse) MergeListEntitlementResponse0(v ListEntitlementResponse0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsListEntitlementResponse1 returns the union data inside the ListEntitlementResponse as a ListEntitlementResponse1 +func (t ListEntitlementResponse) AsListEntitlementResponse1() (ListEntitlementResponse1, error) { + var body ListEntitlementResponse1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementResponse1 overwrites any union data inside the ListEntitlementResponse as the provided ListEntitlementResponse1 +func (t *ListEntitlementResponse) FromListEntitlementResponse1(v ListEntitlementResponse1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementResponse1 performs a merge with any union data inside the ListEntitlementResponse, using the provided ListEntitlementResponse1 +func (t *ListEntitlementResponse) MergeListEntitlementResponse1(v ListEntitlementResponse1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ListEntitlementResponse) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ListEntitlementResponse) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsListFeatureResponse0 returns the union data inside the ListFeatureResponse as a ListFeatureResponse0 +func (t ListFeatureResponse) AsListFeatureResponse0() (ListFeatureResponse0, error) { + var body ListFeatureResponse0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListFeatureResponse0 overwrites any union data inside the ListFeatureResponse as the provided ListFeatureResponse0 +func (t *ListFeatureResponse) FromListFeatureResponse0(v ListFeatureResponse0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListFeatureResponse0 performs a merge with any union data inside the ListFeatureResponse, using the provided ListFeatureResponse0 +func (t *ListFeatureResponse) MergeListFeatureResponse0(v ListFeatureResponse0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsListFeatureResponse1 returns the union data inside the ListFeatureResponse as a ListFeatureResponse1 +func (t ListFeatureResponse) AsListFeatureResponse1() (ListFeatureResponse1, error) { + var body ListFeatureResponse1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListFeatureResponse1 overwrites any union data inside the ListFeatureResponse as the provided ListFeatureResponse1 +func (t *ListFeatureResponse) FromListFeatureResponse1(v ListFeatureResponse1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListFeatureResponse1 performs a merge with any union data inside the ListFeatureResponse, using the provided ListFeatureResponse1 +func (t *ListFeatureResponse) MergeListFeatureResponse1(v ListFeatureResponse1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ListFeatureResponse) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ListFeatureResponse) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // AsNotificationChannelWebhook returns the union data inside the NotificationChannel as a NotificationChannelWebhook func (t NotificationChannel) AsNotificationChannelWebhook() (NotificationChannelWebhook, error) { var body NotificationChannelWebhook @@ -2671,6 +2950,22 @@ func (siw *ServerInterfaceWrapper) ListEntitlements(w http.ResponseWriter, r *ht // Parameter object where we will unmarshal all parameters from the context var params ListEntitlementsParams + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", true, false, "page", r.URL.Query(), ¶ms.Page) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "page", Err: err}) + return + } + + // ------------- Optional query parameter "pageSize" ------------- + + err = runtime.BindQueryParameter("form", true, false, "pageSize", r.URL.Query(), ¶ms.PageSize) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pageSize", Err: err}) + return + } + // ------------- Optional query parameter "limit" ------------- err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit) @@ -2786,6 +3081,22 @@ func (siw *ServerInterfaceWrapper) ListFeatures(w http.ResponseWriter, r *http.R // Parameter object where we will unmarshal all parameters from the context var params ListFeaturesParams + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", true, false, "page", r.URL.Query(), ¶ms.Page) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "page", Err: err}) + return + } + + // ------------- Optional query parameter "pageSize" ------------- + + err = runtime.BindQueryParameter("form", true, false, "pageSize", r.URL.Query(), ¶ms.PageSize) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pageSize", Err: err}) + return + } + // ------------- Optional query parameter "limit" ------------- err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit) @@ -2921,6 +3232,22 @@ func (siw *ServerInterfaceWrapper) ListGrants(w http.ResponseWriter, r *http.Req // Parameter object where we will unmarshal all parameters from the context var params ListGrantsParams + // ------------- Optional query parameter "page" ------------- + + err = runtime.BindQueryParameter("form", true, false, "page", r.URL.Query(), ¶ms.Page) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "page", Err: err}) + return + } + + // ------------- Optional query parameter "pageSize" ------------- + + err = runtime.BindQueryParameter("form", true, false, "pageSize", r.URL.Query(), ¶ms.PageSize) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pageSize", Err: err}) + return + } + // ------------- Optional query parameter "limit" ------------- err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit) @@ -4563,277 +4890,283 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "cBcWVZL89O7T/wsAAP//bhNSDRlvAQA=", + "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", + "AQA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/client/go/client.gen.go b/api/client/go/client.gen.go index f15187b49..c7c98646e 100644 --- a/api/client/go/client.gen.go +++ b/api/client/go/client.gen.go @@ -719,6 +719,75 @@ type IngestedEvent struct { ValidationError *string `json:"validationError,omitempty"` } +// ListEntitlementGrantResponse defines model for ListEntitlementGrantResponse. +type ListEntitlementGrantResponse struct { + union json.RawMessage +} + +// ListEntitlementGrantResponse0 defines model for . +type ListEntitlementGrantResponse0 = []EntitlementGrant + +// ListEntitlementGrantResponse1 defines model for . +type ListEntitlementGrantResponse1 struct { + // Items List of grants. + Items []EntitlementGrant `json:"items"` + + // Page Current page number. + Page int `json:"page"` + + // PageSize Number of grants per page. + PageSize int `json:"pageSize"` + + // TotalCount Total number of grants. + TotalCount int `json:"totalCount"` +} + +// ListEntitlementResponse defines model for ListEntitlementResponse. +type ListEntitlementResponse struct { + union json.RawMessage +} + +// ListEntitlementResponse0 defines model for . +type ListEntitlementResponse0 = []Entitlement + +// ListEntitlementResponse1 defines model for . +type ListEntitlementResponse1 struct { + // Items List of entitlements. + Items []Entitlement `json:"items"` + + // Page Current page number. + Page int `json:"page"` + + // PageSize Number of entitlements per page. + PageSize int `json:"pageSize"` + + // TotalCount Total number of entitlements. + TotalCount int `json:"totalCount"` +} + +// ListFeatureResponse defines model for ListFeatureResponse. +type ListFeatureResponse struct { + union json.RawMessage +} + +// ListFeatureResponse0 defines model for . +type ListFeatureResponse0 = []Feature + +// ListFeatureResponse1 defines model for . +type ListFeatureResponse1 struct { + // Items List of features. + Items []Feature `json:"items"` + + // Page Current page number. + Page int `json:"page"` + + // PageSize Number of features per page. + PageSize int `json:"pageSize"` + + // TotalCount Total number of features. + TotalCount int `json:"totalCount"` +} + // Meter A meter is a configuration that defines how to match and aggregate events. type Meter = models.Meter @@ -1209,6 +1278,12 @@ type QueryLimit = int // QueryOffset defines model for queryOffset. type QueryOffset = int +// QueryPage defines model for queryPage. +type QueryPage = int + +// QueryPageSize defines model for queryPageSize. +type QueryPageSize = int + // QueryTo defines model for queryTo. type QueryTo = time.Time @@ -1249,6 +1324,12 @@ type UnexpectedProblemResponse = Problem // ListEntitlementsParams defines parameters for ListEntitlements. type ListEntitlementsParams struct { + // Page Page number to return + Page *QueryPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of entries to return per page + PageSize *QueryPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + // Limit Number of entries to return Limit *QueryLimit `form:"limit,omitempty" json:"limit,omitempty"` @@ -1281,6 +1362,12 @@ type IngestEventsApplicationCloudeventsBatchPlusJSONBody = []Event // ListFeaturesParams defines parameters for ListFeatures. type ListFeaturesParams struct { + // Page Page number to return + Page *QueryPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of entries to return per page + PageSize *QueryPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + // Limit Number of entries to return Limit *QueryLimit `form:"limit,omitempty" json:"limit,omitempty"` @@ -1299,6 +1386,12 @@ type ListFeaturesParamsOrderBy string // ListGrantsParams defines parameters for ListGrants. type ListGrantsParams struct { + // Page Page number to return + Page *QueryPage `form:"page,omitempty" json:"page,omitempty"` + + // PageSize Number of entries to return per page + PageSize *QueryPageSize `form:"pageSize,omitempty" json:"pageSize,omitempty"` + // Limit Number of entries to return Limit *QueryLimit `form:"limit,omitempty" json:"limit,omitempty"` @@ -1922,6 +2015,192 @@ func (t *EntitlementCreateInputs) UnmarshalJSON(b []byte) error { return err } +// AsListEntitlementGrantResponse0 returns the union data inside the ListEntitlementGrantResponse as a ListEntitlementGrantResponse0 +func (t ListEntitlementGrantResponse) AsListEntitlementGrantResponse0() (ListEntitlementGrantResponse0, error) { + var body ListEntitlementGrantResponse0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementGrantResponse0 overwrites any union data inside the ListEntitlementGrantResponse as the provided ListEntitlementGrantResponse0 +func (t *ListEntitlementGrantResponse) FromListEntitlementGrantResponse0(v ListEntitlementGrantResponse0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementGrantResponse0 performs a merge with any union data inside the ListEntitlementGrantResponse, using the provided ListEntitlementGrantResponse0 +func (t *ListEntitlementGrantResponse) MergeListEntitlementGrantResponse0(v ListEntitlementGrantResponse0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsListEntitlementGrantResponse1 returns the union data inside the ListEntitlementGrantResponse as a ListEntitlementGrantResponse1 +func (t ListEntitlementGrantResponse) AsListEntitlementGrantResponse1() (ListEntitlementGrantResponse1, error) { + var body ListEntitlementGrantResponse1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementGrantResponse1 overwrites any union data inside the ListEntitlementGrantResponse as the provided ListEntitlementGrantResponse1 +func (t *ListEntitlementGrantResponse) FromListEntitlementGrantResponse1(v ListEntitlementGrantResponse1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementGrantResponse1 performs a merge with any union data inside the ListEntitlementGrantResponse, using the provided ListEntitlementGrantResponse1 +func (t *ListEntitlementGrantResponse) MergeListEntitlementGrantResponse1(v ListEntitlementGrantResponse1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ListEntitlementGrantResponse) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ListEntitlementGrantResponse) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsListEntitlementResponse0 returns the union data inside the ListEntitlementResponse as a ListEntitlementResponse0 +func (t ListEntitlementResponse) AsListEntitlementResponse0() (ListEntitlementResponse0, error) { + var body ListEntitlementResponse0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementResponse0 overwrites any union data inside the ListEntitlementResponse as the provided ListEntitlementResponse0 +func (t *ListEntitlementResponse) FromListEntitlementResponse0(v ListEntitlementResponse0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementResponse0 performs a merge with any union data inside the ListEntitlementResponse, using the provided ListEntitlementResponse0 +func (t *ListEntitlementResponse) MergeListEntitlementResponse0(v ListEntitlementResponse0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsListEntitlementResponse1 returns the union data inside the ListEntitlementResponse as a ListEntitlementResponse1 +func (t ListEntitlementResponse) AsListEntitlementResponse1() (ListEntitlementResponse1, error) { + var body ListEntitlementResponse1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListEntitlementResponse1 overwrites any union data inside the ListEntitlementResponse as the provided ListEntitlementResponse1 +func (t *ListEntitlementResponse) FromListEntitlementResponse1(v ListEntitlementResponse1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListEntitlementResponse1 performs a merge with any union data inside the ListEntitlementResponse, using the provided ListEntitlementResponse1 +func (t *ListEntitlementResponse) MergeListEntitlementResponse1(v ListEntitlementResponse1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ListEntitlementResponse) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ListEntitlementResponse) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + +// AsListFeatureResponse0 returns the union data inside the ListFeatureResponse as a ListFeatureResponse0 +func (t ListFeatureResponse) AsListFeatureResponse0() (ListFeatureResponse0, error) { + var body ListFeatureResponse0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListFeatureResponse0 overwrites any union data inside the ListFeatureResponse as the provided ListFeatureResponse0 +func (t *ListFeatureResponse) FromListFeatureResponse0(v ListFeatureResponse0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListFeatureResponse0 performs a merge with any union data inside the ListFeatureResponse, using the provided ListFeatureResponse0 +func (t *ListFeatureResponse) MergeListFeatureResponse0(v ListFeatureResponse0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsListFeatureResponse1 returns the union data inside the ListFeatureResponse as a ListFeatureResponse1 +func (t ListFeatureResponse) AsListFeatureResponse1() (ListFeatureResponse1, error) { + var body ListFeatureResponse1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromListFeatureResponse1 overwrites any union data inside the ListFeatureResponse as the provided ListFeatureResponse1 +func (t *ListFeatureResponse) FromListFeatureResponse1(v ListFeatureResponse1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeListFeatureResponse1 performs a merge with any union data inside the ListFeatureResponse, using the provided ListFeatureResponse1 +func (t *ListFeatureResponse) MergeListFeatureResponse1(v ListFeatureResponse1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ListFeatureResponse) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ListFeatureResponse) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // AsNotificationChannelWebhook returns the union data inside the NotificationChannel as a NotificationChannelWebhook func (t NotificationChannel) AsNotificationChannelWebhook() (NotificationChannelWebhook, error) { var body NotificationChannelWebhook @@ -3211,6 +3490,38 @@ func NewListEntitlementsRequest(server string, params *ListEntitlementsParams) ( if params != nil { queryValues := queryURL.Query() + if params.Page != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "page", runtime.ParamLocationQuery, *params.Page); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.PageSize != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "pageSize", runtime.ParamLocationQuery, *params.PageSize); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + if params.Limit != nil { if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { @@ -3424,6 +3735,38 @@ func NewListFeaturesRequest(server string, params *ListFeaturesParams) (*http.Re if params != nil { queryValues := queryURL.Query() + if params.Page != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "page", runtime.ParamLocationQuery, *params.Page); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.PageSize != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "pageSize", runtime.ParamLocationQuery, *params.PageSize); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + if params.Limit != nil { if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { @@ -3629,6 +3972,38 @@ func NewListGrantsRequest(server string, params *ListGrantsParams) (*http.Reques if params != nil { queryValues := queryURL.Query() + if params.Page != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "page", runtime.ParamLocationQuery, *params.Page); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.PageSize != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "pageSize", runtime.ParamLocationQuery, *params.PageSize); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + if params.Limit != nil { if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { @@ -5901,7 +6276,7 @@ func (r GetDebugMetricsResponse) StatusCode() int { type ListEntitlementsResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *[]Entitlement + JSON200 *ListEntitlementResponse ApplicationproblemJSON400 *BadRequestProblemResponse ApplicationproblemJSON401 *UnauthorizedProblemResponse ApplicationproblemJSONDefault *UnexpectedProblemResponse @@ -5975,7 +6350,7 @@ func (r IngestEventsResponse) StatusCode() int { type ListFeaturesResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *[]Feature + JSON200 *ListFeatureResponse ApplicationproblemJSON400 *BadRequestProblemResponse ApplicationproblemJSON401 *UnauthorizedProblemResponse ApplicationproblemJSONDefault *UnexpectedProblemResponse @@ -6075,7 +6450,7 @@ func (r GetFeatureResponse) StatusCode() int { type ListGrantsResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *[]EntitlementGrant + JSON200 *ListEntitlementGrantResponse ApplicationproblemJSON401 *UnauthorizedProblemResponse ApplicationproblemJSONDefault *UnexpectedProblemResponse } @@ -7569,7 +7944,7 @@ func ParseListEntitlementsResponse(rsp *http.Response) (*ListEntitlementsRespons switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest []Entitlement + var dest ListEntitlementResponse if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -7703,7 +8078,7 @@ func ParseListFeaturesResponse(rsp *http.Response) (*ListFeaturesResponse, error switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest []Feature + var dest ListFeatureResponse if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -7891,7 +8266,7 @@ func ParseListGrantsResponse(rsp *http.Response) (*ListGrantsResponse, error) { switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest []EntitlementGrant + var dest ListEntitlementGrantResponse if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -9637,277 +10012,283 @@ func ParseResetEntitlementUsageResponse(rsp *http.Response) (*ResetEntitlementUs // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+y9/XLbNtYwfisYPc/MJru0LDtJm/g3nWcUfyRu6iT1R5u0zi+BSEjCmgJUALSsZvLH", - "exfv9T1X8g4OABIkQYmS5TSbprOzrUUSODg43zg452Mn5pMpZ4Qp2dn72JligSdEEQF/xWPMGEmPE/1H", - "QmQs6FRRzjp7nT7KGP0jI+jip+MDRBPCFB1SItCQC4QR4/rPGOu3kR2m24k6VH87xWrciToMT0hnz5sk", - "6gjyR0YFSTp7SmQk6sh4TCZYz05u8GSa6vd7O/3T3x68PDh8cX72y8PT06Ojn7978uzRUf+XTtRR86l+", - "RypB2ajz6VPU0YCplEwIU8vXAcAz5H3TAHR51LsH/JU4Ilhlgrwg8/oizscE0QTxIVJj4kOPuICfrsjc", - "PR2acdqsqzTpbdeoQRlN1cP3il8RJsNLvm61S4upDQZpWt71ahv24+6bt78dvj7Zf3Hy9EX/+Zsffzt6", - "fPbg7c9B6C1m14B/8Z4U494JnY0EXoL0GrzwSQO0brg7gZWyOM0SckBSokgA5GPzHCXmBc0KghKZg/pH", - "RsS8gLUynA9iQoY4S1Vnb4hTSaICZLMWC9qA85RgBrCB2NRMc5Zmo/bY1DwJnzbgszzsIqz+tyDDzl7n", - "v7YLkb5tnsrtfAANKWDhiKaKOAavg2seUzZCgzmaZKmi0zQXHrJ7yS7ZhcQjsoc+/I/99Qf7762dy6zX", - "2/2u+vPuh0vWsBH2ldIOUEUmoIUqZJAjHwuB59UFPRM8mz4FGRmcqPSSPx1OEqrXjtPXgk+JUJSEZy/j", - "6YxOADEwLmzoSA+OBnOJZlSNEbnBsUITrOJxBWs+KL/rad79QNk0UxZ7pccTnpD03Q+jqdp6aNCYE+TH", - "DjzUrKefFnwDg3n44oN/kxh+kGoO3JcQMn2V/+ph8Swzv7YkC2ler5CF/fWHOJOKT4hwdFH7fQFh2Hdv", - "RxiCT+orOVNYKJRgRbYUnRBEGTo92kcPHjx4ordxglX3koE8kfSadJtJV48eFm67vd0HW72drd7Oea+3", - "B//7rRN1zOga/W7yoKyDeTxyrki6odZ6SE5JrGVJgjCSlI1SgvBoJMgIK4JmNE3RgCBBVCYYSYA8CY7H", - "bsMQZgmC1c8oS/ise8k+2EcfEJUII0EkEdckyakaXeM0W4COUYC1coz8bknVLvddtPJeWgF/QCUepAs1", - "gH2jrQpwA95OB8DgP9EJDbDOy2wyIEKbYRYkpLjdmgbYUhgoCNFOr9fzANrRf03wDZ1kE/dwQpn905MI", - "ioyIKEB9NRxK0hZWeUWnDZByM04QVB9OH6xeM1jnvA7SIUs2wK2KL+PV3bV59VfgoTP6J1nOrlHBr5mW", - "l8u41tn1gqjcki94f0oE5Q3sDQzZjJBZAXRbW8JbZ2Xt53RCfuOMhD0UkBxarGjg9fRuIbCjf3JGEJYo", - "IUOqV00ZPDvuv+wjPS7SA6MDrPAAS4LujZWa7m1vz2azLsUMd7kYbeuBtvRA8r4mhxrO9YAX5/swIczn", - "cJ1JkizDUb64IJV3Ls73fa3c6U+IoDHefklm799ycRWkG5Gl5Lb+jh6jwXa0w9+Jt2NpTBuWQZ+02Xuw", - "XzbAXBm3Hey5KUGTALAa0UROOZPGpHuKk1PyR0akei34ICWTU/sUYh6cKcJAJuLpNLVY3p6aN//1b6lX", - "99E3vxKiMNX215jghAi0b0bYOp9PCRpjiTJGbqYk1g6J4YHL0tA3k/Syo6lKYZXJzt5DLb3BDe/saViR", - "BbZYWSbYngVoS/+0N8DJlrBvfWrLx3bxBkHlzfNn/RR19jkbpjTeDLpiOxhlo0OmhDHVEyDA529+Oemd", - "9fZPfvvx7OfdB8+enLx4c/rz6+874F3hBCtYlN7YKXmN5y6o05nS9w9fif7V+KfrOR1T/mT6aGf8hNIj", - "9rRT0GpBXVs7xpK3G5eSZEQEIjdUKlnaiSfFTtiXcCoITubFy017Yl9ovR0VJIe2xb2iB33J1RHPWLJZ", - "EgZvE8TmUA9ewsXDAhcvuUJH9oWm9TOutswgm6DIYkaz9mMNut5/smEMWFcUcECLSTxMPOrtlDFxXHpt", - "ET78ATeFlePymBcMZ2rMBf1z05iZUKlNFsQFouwapzRBEMsrEYmHGh+SBXjJ/Nc2gZSLyoAXufjdLD48", - "sU6E4KJEIj0fD/l7h/a9Zly4VzeEiQqEn/JRrSJMMYvJcyoVdzZcXZOb30niLFWWoIH5EFFmDGTKmTGf", - "pqXYiX2tr8DZDluFfrTaDYuVMXDBRbdGorFxu+XYB/g9hY3Os0FKwGTAySuWziueGgOvRmPWDLYUs+at", - "T1EHVh6GX3GFU4uacojdmbAbhDwUzKnqjcZYlhmxQaNEzSqaqvlxrp9fHvx4+ujB7uHjZ+dPfznb333z", - "4tHBw05dl96zlnG3+av7vi5VUoF56FyXQlFrK1EqTReWY6yhs5fyGKfbP568SmMlX/zyeKun/9lp0t/e", - "Ul1sYcAztTdIMbsCoijRrltQ3a4dZxPMtjTkeJASRG6mKWbGFre+RqzdZTWmEvE4zoQgmqgdHZtt6pac", - "hQFP5miSSaWdEYx+PHv1EnEX+aqFRsiNIkxSzmTzZtuQRXlNwX1dfJjkfWJYdV6GfMUAfmHM/x6E5l2A", - "wIvtr+/FxekxEmRIDIrVGKvC35C+lxy33Yp2FJZzbiZoaIscBYaQ+/z8/DUyL6CYJwSNCCMCayk9mANg", - "XNARZQhCb+6UoDUxPSxJFsrUg92OFxx69OSJF4QxvkYlDJPzTB3fGMkxFyqqMoHMJhMs5hW4kB65jN6g", - "P1ON+tWwpj0prakxZRJh2PXQXjdPu9BjWradFbqFpw5H+VbnIjBEwoeFkoPVUb26CWVYcQERfDyd6qm0", - "zrThxAad5I301L5pj540cEu/ObFvGrBp3OKTM/NiISDnL20sTa/yU9ThjLwadvZ+X6xMA0B8ilp/kgPR", - "+guHnU/vyvh3v2vJmaarAW6/3RcEK3LMphn4d+0XMcaCJEeUpInsfHoX1SKc8KYsQiRajWSSeCfEYEQs", - "Iq8QiOss1QxQhjj6uC7E08CR2scOYVoE/Z6T/LuySnTU3YIb6zxX2fUqPjbKgaXB1+DGyvcrcmaFGjfN", - "pWsTewi423FacE9LJLr3sUJqC3Iyzj1LHQwFS8FUOp8ksdTcvWSHVI21Ks7zYbQXnA+uv3E0WbHzVzKQ", - "8hySxiyfzwCw/a8td2x/BVHYGqR+QG7Ns/N+/hlyo+WHHYsFHrhbr1s5cadEG02UjczrHkWF3SmPwJ4J", - "bCMDq0pP+LI01RLSN1R8QhT2hG2ZlJcksmnqsBF336WGAwSwlTRWITkHTnal5DEFm3NG1Xglom3wUX3/", - "ZEoFkf0mj18/Nv5SglVuy5qkogogqxyhL4WLkRtlyIEE3QkNnH7HHEgV+IJTIgEf3ga+GjyiBMsKRKw/", - "vuY0IUkTjgGx+em+txQskfkS3YsxY1y54y+Eh4oIIJX73TVRXFHNZYpdqqNrTFNbGbwhERYWZMURZbEg", - "WJI8dsSHhcvn5aXUjBA84RlrwJ55poc3RInOxjxLE+OcT7mkil4TZIIy7eI6tQgUGQ5JrIcJ7eChe2j2", - "0WQVmaWzBGEWj7lxC4WjC/u8i14Lfg3ba06a3AFnTKhVD2Cd6C+Kk190b0JZpsj9jVJ3weYriND8G0fo", - "mkYm+OaUpym/JqLv7VqRX9BIJYKnetn6S4QVZLOoyFL6bEzjsWaNOYoxQ2N8rXc3oUOIJhTBSA2mFs4a", - "eTMrSOdojDU5DLnVxTAypD89dTFMy072mRa6MU7jLAWhi+Ve/ur7vn71/Sm89gM6OX5576S64gid9N/c", - "cx88hYnNFxE6oaz88v3769HkWirdCxuufC5XU76T6lK+7fSd7PRUUC6ompdziqKAKHRvlrU0spiHDMcx", - "HWlTM39TbwecpZAEDamQGluv3UPIKstFaEJiOsGpFaWyi37VA6Z8RoT7DVGWwKkMG7mZ6GTKBYQEu5fs", - "iAtk1x/poT14d/RsE71xmRjpjVZjzCrv7HYv2a9jApF6DbcgSJJrInCai9xrTFMIcjnbVOJJbn2bpBI5", - "l4pMkCSpVjcl00EB5RnQpcrnhnQlFGNJJJrB1HY6qS3BYpoc1pRckzTyho5TLvWIWgkq6VtVflZLvgPH", - "5jBCzwh7OeNuRuAHE0mLcepmpMRom4q1JksLhpm0v1+ABbamNjNi0OQFACU69QKSu48eLU5Wu4WhVLX2", - "fevEGgBlVVxSW0sieS6MtY6DcEvn2n2eixnPa9hMMMrO4PsSueE1zFLghQlmc0+MajoAgo7QUHDNDQq4", - "Npva47EBBjszjomEhML8NFy/paFNyY0mm4QqS2Cyi/rmdSpRokGaQHKYGYmz3B82E2RwPo0LgW7xo4n3", - "nibRy449w0xTPtOvXHbQ1FlMNvhOpcwg4RWYg0p02RlkgimU8Bm77LjXYKD7ywNyTVtVM/qKN9AQXrHp", - "UpP6TnRr1qzhD3XR3i8uPIkUSwUKJmwM68fGjcBWwY3xdEpYPXJwu3xnnzcLkKLQ0tox5ueJgQYYxQp0", - "3J5yQw4KlWd8qLxk4nIyci2/VLq3f9C+WSlCpK0eJ6XdvOSaMETrN8aoViVjnElFkgiNsbQMCKIepzM8", - "l1q36DlKxJ+nQUcdKi8Y5C67BO1FkB+QqSAxhtnoiHFRcOIAx1eEJV30OgUXTy/BwwqiTCqCk//PnI4B", - "03jZsxN+XaSRDrNaNKkEsMwI2GYNfPCWZ4BEo+KsDMkUn2DQmekc4ZSzkaQJqSLU6EvLJEjGhGFBOZo5", - "hxLUpBFbkO8AdyuM/Oqi4yHSFotxR6n0Un41hUXuKlbh5lmd2whNYZB4Nwdg+O4lO9eq2xvQGAbqHxKs", - "azCtrUyXcC5MR5kwKMZohudG9RtrGNKQjbTQNA0iOLKbamSzDaqoTDDvzBOnbrXlpYLBfYJZBsjOcSaz", - "eFwgAVA6IcbE14+NyDcDXnYidFl3MPTP2sy5rHuZlx0niLHBrjPKDBm1MLMrdPW6ldV9AAnQvhGZ24DO", - "ALUfO2P8eJgrsQhV5jRZBdbl8e5urGuKVc9u3GFH6exmkp8y1tzFzUVuA0ey2UIdUQk3VQ8O2qmHYKD2", - "dvpkc5r822nHXZ122NkX3L7Ok9yvyNwF4iELKAe9NG9xKW6zXFJjDQ/yEsJ9alnOK/ZIcg0j6nbngJ/j", - "yDwA4Z1Zi2aukkYecXt1R2hLSFp3yJG+07ONOZbmhTBVQh7ZFAu422aHClQJ6KJzbUDl93NwKnlx/Wg2", - "JgzFYxJf5TlgFnJr4Gr1SYExPd/QwQ1roYxsjQQGA9h+lBsSlkfseiM/51pbFnOeCcRnzDqEXfQcwzcD", - "oi0js59Vnv542bki853Lzh667MCqdi47nxalGzltZo/eS8rM/tYyK8hux1KO+kWDVT+vttZRfTtfMW1k", - "lkJRAcdQdlGj4z7IaKoQFjxjSYOPbPyWsk8N7kuSQRIxuPU1H7mLXCQ0p2Bpw6ETTJln0AZoLzIGpqE9", - "RrSNqelOIkZGWOV3+W6d8dvEJgG8yhqPSs0h7dmpLTkuPbDMva9AUvaYgMrzVeMYSy+64p+iIyOW9FPB", - "pTFofU7WM8sK3AamBhg950kbzMHs6NYk+8qMUCUfQ38unsj+oVCs5zL+oSG9CJHuqOvc2AIPmsBNYnaZ", - "mPkQ7fR65cRsNMhspH+mqZ9rqGF0kqDHvcgGhnN/bbeH7Ior+FqPLhsyy1vj7pQYdlF5KnqFfW3Y11iV", - "4Vz0R2umovviryDVYHDm2t2xWJSsXImHpTxL4EOJzuyJrhFTwIdn5nJE6QDKHV6VCiJsqUwMuJbfpvDM", - "Xmdn90GoTAJcQnsU7/SGOCFbO/ETsvUw+S7eerz7/aOt+NFu/OC77x/sJA+0LpA8E5CQLom4pjHZgtuL", - "UUd7rddESLOEnW6v498+q1xTpJNq1GxnD/7X7fV2fisgnAo+mapAivrCs7pQuj+kX1wDIeB5ynHSXVBJ", - "ogFxoXM7DYm9SRPO4LV3IkHQOJEJ+T7GJUUn2kvFCbCa4nC3e7f38Dt3t1tDaVW0f0sHbueUlHXtKfiz", - "PxE2UmPwaFmWAks1ylwNlX+/txRlq6SWw2tGQsFizAK09O3Wk4pXhIMmS+fPKx0V629JvmVY6t6Ope4l", - "88OO3ygtY8wRK7bVl4oIcQm4Cq/4+NnKk/hbQOfzWPCiuXno6MwXJLIkSPKDYQt2Jk2hiAJkw8HLAGqq", - "lnIAfw0cuVj15CwGmNLJZ4vK0rOp4EkWE4Hu5e4l6D6zPfe7YYcSZMsSiI3oqeGOTohUeDLVYMzsoah/", - "6yDf1hC/Pnjw4Em38TygItmCZwIrckhY0pRx7uSNQagg5nzFWkc25Aj+VrHK8hqs7F1m/QPSLduUKTRy", - "noGjkpp+jDo3WyO+ZX80TG0Upvdkyxx6mxp9GkOdEVXjbNCN+WQ71hQOH8ptmVxtjfj29e42/ACQ1tJq", - "6hlHxSmvtYr4MC/0FfQ6G5OnSG0oeBml9IqgnV004UyNq8bmzm4o2JhkRQJRm4nc+2YumMjOY5XH81cX", - "p52oc9B/24k6vx4evuhEnZNXL8+fd6LO28P+qbc5DRudgxRZHITMHa+qVhFGqKSfiXhMr8MJfMeVa4Ta", - "fzNvR4hxxMis7N3FmPnBf20s0rvMpAxYAIujJBYfKwWB6oHWWvSnX0JR/od24YymQRzOpoHhMXISspw0", - "sof2X19sPeeZkBE6B0snQv3Xx2gfp6l2MFTcEEIKrSpwZepzwlimsaumaOUVMYk4DNHJJFPgYtSrdVRu", - "s5qMy7Hg2WjMjcukYYhM2Rl7vgVaQ3OwwObOIJw35dG5f8iAW30FSVYuqmPhwIWjik0qpKs9F4HD5jgi", - "/xm4oJI8c0XmxRTS5HDGnEkqQdNCnhEkxOB0OsYsg5ItKB5jDT0RJrSVYDmuOcedhaUsP1d2fORH3OSc", - "xTnGyY0iQn9q8yhs4ijjyqg7Q2f2fKuBvsHhtAXITN03eYvlvJoWiyFFlTxbOU920YVZivXlzVsy5lPg", - "nIHgUFsFMrggNy8/GxA4vpJddNh4wmpTKMybcNKapqZyAUSKAV+2bJmfeQFQaH8IQgCsxAsxjO0V/YMX", - "TXm+7uLyfJ+aMB0uG3me4yJP4vcFSjmN3+6yl2VgLNw8klfkJcJxb45myFsjiXdYeHZxooXU/quLl+d5", - "cao8BF3wgWGB9xB6CDGCqeoTzLT3KkCVYvVeDaVjK+2W2l/m2AYmW6CQtTapA/OTSVUowk/GhgADyOFa", - "EGPcWYTaqnHSRIuoknXxKbXVHmnJcz+Y3ZGsViI0WPKpXLzpxcvXO2/P3/x8+ub5+cGPD1+8Pv3+9W+9", - "0KZ8HsVwyW6hGVYRtyFbXC8xRAmQuPo0E+yAz5gtfHFGRvnN3MqGSPOolP2KBplgkA2GxmYAyE7ooxG9", - "Jiz/JBjNLKxqNCBqRoj1mKVh73iM2YgkiNA8uFudskheFVogWvLQo5eCew2FOA5ZsnIZDsKSOynC8cVW", - "BwGU2zMNmeOsSe+1yAOpr8utZSAIvoJ91U4qjsfO2jHb3rzUPZOCfXyw505fqmpnwVG8xsynRkQUzFJB", - "RL5Pf1dUQFJG8DBGKwWbMTozuX/KpCoVqaOVUwdQ03Njy+QZWB2vIuoi5+hZDs0piblIOs1LsAVUF53T", - "XBNhsgMXnLRUWGv30V9dd6dUccfea/ws9XZquK8d4jZWVC+XVgleeFwtgWYl/Kx1Uy2EgZWKnHcXmYvF", - "pfRK4aqfjg/QvQtGr4mQwEcXZtyfyA2N+Ujg6dgmXp5xYeyUPDgt7lcw+uy7R799/+hR/+jX/ovnhzu7", - "L9/29n9+cvRcq0mstKPU2ev8/7/3tp70n+4fHB49e/7ji5OXr38+PTv/5dc3b39793H3u0//HcD/x+aV", - "TfCNi2V+96Aa2vRnxVt/9raevPvXvf/Ze5//cf+fgeneBQjgmI2IVCRZ54Ctr0WS+dzGR8Ek485RgxJv", - "tqeCEFxUzoqIm3KVU7cVjtmSv+6YrVi5KdhWq4toYh4mvlq1tXK8LMwbct/WpvJpypXZIzYavOL1W/gq", - "ZARDjkiIe80yIVJVSjyyZ1w2M3XMZ3CTFKvYupx58WJjzFYoxXMfO3uds4uTTo0Uj3OHXAs02wnkvLQv", - "UV5b3KO1/+6WKorrH1zBCwkSqsqXcN5oWWNu3ndehVcKea9zcvzy4vywvrultSzeY8By33u/av7U8e/9", - "7UR33hui7hajC4utpUclHjo/Nh4Jw1mJ4sVutjsJKe1Lk2VYDFPbsaaA0Us8IQmc9b/GENHS7hRUPdNA", - "khulHUmr3fza9LJIUzLr0vKpi16QucxLrLkgI/PigZBx4ccB9dOMJUTImAvihQUbDs0X0GK9plmyZoeQ", - "lnptaWqRXKi/a/W9GkEyJ4G3ReJn0J411q+uPUBpVUIzWWpFFlxJe/5DmiQAV3/HRtjyl+zHXKCzi5MI", - "9X95FqGT45fm+sFJ/40fZZNGBjNbhh+qZsM6bJjAHPhMsZDu4CAvRnDEBbp4efzzxeH7WvAuKoNtICrK", - "DpopuugoFPgrEOBQqGG0N3aqVqwnVWvbMCuVyV+h0Hwpq9k0w/GlsS/lSrMsOXAFppVdoxPbnrjyKWGm", - "kgIv/nt7ejXaNsMBwDUFEC424ePYimDtjtVZ3x5iGgUKG9SJOv5ed6JO/5dnnUhrL/3//Tfl7BjzZXlH", - "mpHRLyF303j5OSNifkokXIIJ4UXAMxMxM3YJlOXvhlK+fv8YMg4qhmjVymsyGK9Nau7OrqMiCAA1dYiw", - "hGZCI+FTVm25Q5uYxlNYxZdOsNgscTZ40Wrli8dIq0CHRyp8Vm8L4/D6cVNFSxTfWFuQDUk62NlGIz5H", - "TUCVCz5zIZF2vPQlE0xUi7EstTkXlSppub4Gw9rrpNWU+nVeT/gyiDcJjwtSt5Ya89fu6kAoe6aItXmI", - "3zRFuzjwXVz9NqsrT+UvZgVtnjPHRrXXS+8kbt/0Ll1WUfLXw6fPX7160cT9gRF/JYMx51e3rue4aOh3", - "4cXs88lklZpNgSHgnDVwtdEkKAVrluWph3neoe0L69cS6W6uOlVS6iC26IK6f9PCwURl0WCMQ1yoBJod", - "p35XInwafiG1WyUoYUk6L52Le51zA+JiZncyFBieJmuiesITSDRtwPXuHWSPvatXpdck6CdjhPoJ54fy", - "sttZRMomQcsVnQ6kplcnM9TWNCcMU6/A8ZUTlEu2XVESgDdWFfE2iNtQuTe8k7U9vAtxW57l7mRvZZ4G", - "QbxqtkqQXkP5KiXCKwI75h6nNNXTN52yEiS81bJWNkmCRZ+wlgTYHDz1r7Q0Ltm67o4yS165+zGw5AXq", - "+zb62ar4+vVkO3i+ptB6ArWHtPh4Ds3P5IrtR0waInREMN3TJJJwtViiqXfQbwWTL309Y/7N1v7F2fmr", - "k63nh/2Dw9POnjUiWxnwdMQoG52RWIQKv5yZx0jCc1tRjYsqQP5ZGXcuV0zotbkynUCC0BEoyz30YYAl", - "+e7hB0RYzBPNypglfIIGc6U51B6/pXM0FWRIb1xu34fZWJL4/YcuOiUxn0wI099K+ifZQ7sPKwE48+7Z", - "d6Pd5z+x81nypD9+Prs4PjkajX45e/JqyF/j4cvH5QPQe+aj+//zO976s7/1W2/ryb+2f3j38cFutNPr", - "BQ9AO5kItEhxVHRx+pO9UlzjDWr2uSwOxkpN5d72tv0FTPJGlVRhaA1IdTffLbc0XgZlpkb3zGOF7mJe", - "rCmnWzJmVQ1V8WufACGCoQdUdkOlyauzgDfJom/Muyrzon6p1FPRroWaDqOu+M6Xy+VVTH5NXB8utRBg", - "LllqHr4iZ4Zij/5reQLGAvlijiNr3X5sLc08ZxvMM0EVERRX2+HGXJhWpgllo0sWagWriVDbJR/sFd8P", - "tjJa3j9Hj2Py09CESEgTAra1t+KCciN0BWwlb57VEXFHjj1J6TUR87MFHZjcO64LU8h6yy/XrkwxQAoH", - "ZTAC1HMrczpw9Xc1Y9oSx8rrem2/s82LV/n+NEtNBn7QGC/IKSr6Flc2swB7mdUOsNps0POxIHLM0+R1", - "sebVNTSMaPRzgYOPDccwjUVdWtYS+sWpQFJuHLVygyVX5GnZx+7GYjmkvfB+XpYjXjkEr0oN1Q2yy25u", - "I1BUrfISvvJM8o4PSp1C2h2svGuqx2dJrx6OstLMONoSKUFHI0iezYXfBwvgBydpPnhr+nDJZCamWLp7", - "AkTkUv9Dvp4PWgSHiLxMki2iWwHYvWIQG3T5bVbRmOSoGxCoS2nrI6wdB3Da5ctSPKuGJw7zbIXm4IS/", - "2FYi76Cm/SpKuziwWC+mD+WwSjWzzi729w/PzjpR56h//NPhQSfqnB2+PDh++azzbllk+i4OkIowhQHV", - "n7IVDht56bwwnBxFO8PJuY4V1yessxfFLkuXoFwdWE/AtqSrJtW3yZjm4onehVC7RhStsHQsvS3BUCm0", - "tuTdJRG3U2vg3O1+hRThRvcpPMG7wGJrb61lKemRGiOMTpvW/Bbwf7T74+4D5UiUdb3kLn0HLrO47PWS", - "06M9+dTe+s4vjIOjr2c2zSqcWmpl7/sXSpsjFcbWjzpGYR6bgfUbvtEkQzF+aUWIe6cAVmbTKZfE3pbP", - "jY2SIvs9T354fXi6fwiJYS4lo9fTm2Ifv7w4eXp4Wnra67VOzmlpzlVdn2rhxAIRqwbsACFgexg06G2u", - "Cw+pHW29x3PTZ4CZABekEbu6aF6Bwuo11BZ8soEAYME09ejfmrSvEQOGpCuFbW7TV8P6g3lRJvBYoQme", - "O64pWGUwh3tLUNy2kuv5e+Vu7oILTD5d1S+Kf2OhRSw0wTd28Ts9SIh2f22Uu/zIcl5knZFZQFy3YTsr", - "0QuWu2SuMdDGeC8vpFq1KezzvBGaGqNJlio6dRQgoBQUVL5c2qI232VHDe8WJWa1uVUXynlqdSDpqde1", - "JU2eoNNcej4uOY6QORisQRD0LxYwZCi8eDtdvMBZqcbcVotZAkBfUvoRALTZVJFzF3IIpossqTrxtGqq", - "IUFwPG6o/L9SSlKO+9vnI208/0jDVs85atLge+25rCn5CJDRmHm0Hs+VSpXoFeJJs03safsF144W6vdC", - "gT1aqL/+lryxudiRDRvZFKucNFoplVVyrO7G7727BKwWs4U84nAO1u315F9a/ucuIpVtCGy9A1iIwgR0", - "eVMpy75pVmaqQATOLd2NkfJXZjRbXgQGKM6wbUcirY2s+Wo6M5law4OUbLRvrrmCEoSOuIbOfw1slc0H", - "RAK8oc1/zYXCKdxTDu1RzJnMJkQgaOVp67FV742nKZ9BDUhTHU2CgPNvir4rmXRNazP9yJNc/nv9yZsM", - "CShSsPCGbWO5AbPiDp+8N0t7f9xnBw9eT3/9dbe/+6t4PHny7+Gf5Hn67M3jm8n+m9mz7vzRHw/Ptvq/", - "/nGUfffHv4f46M/enz//8fDwz93Hp5LNf5n9OBy+efTHzck1D1xIryOpKS4QITrMj5byTNCi0RZcd5B5", - "MzE7cln9V9G/QOE36viwN1+yze+oA3xOCR9bNDYotbG/k1R4lwSwsUvdxdFt0+2igLgJcijE5KHIALVZ", - "w3lDGKxsbICXGfauSH7VuheNhZa1VBJ8kJLJaolufWQ/QwdEYZpK23cG3Ts92kffP+59f797ybx6nQWH", - "Fr3obXbN1I4E5x0TPId73CaRu3qzFeYCkkzm3i1t6H6Q332S9qDvYa8XdcAkA9szQc6syZGQCbZnZ4eb", - "UHsDnGyJmqnlMhns7HXJXakMQG6mKWbGMCkvVhNOUTvclewyEJQJZ+EK6zzDpAo3yemji9NjlJeSN5fl", - "aaVov4OxJWwabRZLeymPcbr948mrNFbyxS+Pt3r6n516rf86Zy7IRoIESpuJFPOE1DPETKFyqBic24St", - "sfuwVOeJMvVgt+P1/Hv05InX88+QUb3rnyGsOr4xkmMuVK1ehMwmEyzmFbhsMm3ZTQqQ6rIa79oWLfLZ", - "MOx6aK+bp13IDMu2M+xyGRzlWx05Fmp3YdEc2DvxtNELi9UOcXv1fGL7gl/7ndVbGlUMDxaPeaiKEENY", - "DKgSev/NSxBpx9I10K/OxqoNNReZx1BC9BqnK/bFO2TZpO6+uLEit5qQzljQh/KLROVxOSvZVC+2gRQ4", - "9GJ8hpTIWOw3QxjzTPzl+9AC/TBAY6RrKsiWs3ANTmSpZEqeA16g7jLr9Xa/g2YuSZZSNoIM2oP+2z0E", - "/xxCpmiC55fs18PDF3vejzNCri4ZNBDYK36FvgOX7O1h/9R/eU6wKDUjWKULQdSp1cPfC3SitlXCvfbh", - "qX9NEhKDJcnb2opqF+Mpn9oW5OXcZNvtHY9c/ylKTPF2Kky3RWYa72p8UiiGrInIL+LuA7FSKrFpFGSm", - "AN/X1jOw5Zg3EZ1falcnJCXrw2e/vkP4aFCo4wTsdhtUgpKKXlnGVepOLgVgUWx/OYKgw7wdwtTrp4wq", - "akoQmpaUeUn/Yr/7qnuHDS4W5icvTig7K7ywVaox+h1ucUMoEJt4NBeGC6sFPOyJqhOURcmN3SpWSm8u", - "rLwB8fhpil0Idt+6k+ilCTEvj5RAtfFqfyKvP8I4G8gph4KpUCTy0XfGYhZ0Stxs8DDO5PvC+K77LPXl", - "1/323Vb0sbQGRwh/60Ytlrck8zfAn6W6Fy2bim0q3GDLyLcONSxvimEm8ig6TBvLL4bViKcCpk9HS/EW", - "6DUQ4vtfS+V+KtztFfkytUzgTpef12hLO0V+k6JSMmP+QosCXh4sG/UlzLgksUcptoB+WOrP7Lt5gkdR", - "Lb9eoD4T+mXWOOCzvAx+pfD+SiWzGwr/B04XHPDrrnALHSs/biaR4DNjk5mvZBHEF0YNQu1T+LQY2xhp", - "cH1f0mtX+54Ke1ChdSq5qT00N47NOKBcLcnZeJOc4DR1zVRUPhdQpKkCIMtTDrga60HlCvguU4ihm2Au", - "YP2WhtS2OVVzaPFp6AN6+O1zfkVJP9OU+zHULRR6Is3IAOHpFMXwtgZXP8//Mke9nffvpanxWPATntIX", - "BDYfBvMOMNyUA4IFEUdOiPMp/gPydkKgBA84OlEH8ANBLxismH6s1DSffO1pNQZaT7V8if+eqfpEoZUh", - "ypCWGlvWriva3y2B4hNE2k23ogMeB/yaAx5nE1foomNvn+bXRnNR1aV8O9EDgHM65KFzEMJOvArHgDAG", - "XaZtuXQj/+DKMNSbtjU8iw81euFcRKI5z7TvbKpp2pS3yNRVs6W+YExT39M4TyUvaGtr65L989WUCFvy", - "E1LUNDv+7//9P+geQHcfmY5NnIEc4OWuwJR5kMH2d/8JDJrSmDAJasiSe3+K4zFBu1Apu0Dg3vb2bDbr", - "Ynja5WK0bT+V2z8d7x++PDvc2u32umM1Sb0wYKeEj07UKZXi7vbghH5KGJ7Szl7nQbfXfWAqDYxhd7fx", - "lG5f72wnZJCNtidECWq2fUSCERUjPuFtZN82Df7gYNyWSB1WqrFKJKmWyBPKEkZHY4UuzvfL2wkD7fOM", - "KSLuyft6cwhspHH3teCb0NLHHViX2S8wSZ4RdaDhsqOB0SSnXCNQr2S317Mt+pW9wKfIjdqeppjCkUvR", - "Z7bQ8v+Fnh/+9BrlZP3eLudl00Iv2X+h87evD+ufxGZtl6z6xBzffbQOxw+XheG2c9n5hMDQ6vZW/C6C", - "IvE/XHa0DQXDdAPZB59qdZ4PBqTY2MjsbOOuQtbVw95Ok/bJ0b99wXCmxlzQP0liw6qn9qFx6W1i0fJx", - "yM0UumPVRoETN4hzG1Kw18smOTEobM6sgUY67/QHjvj9/JlG2oeoVqVXu0TakBRJSiSkm9jN0H4zlVpJ", - "TzllyqhwZaoHgOeYTCijUgkj7qaZmHLpojFlotazHvrgad4V2JwONybdFK9sgwyEOkWNXR6rb78aDiUJ", - "1bp4BV2OBrYzm9Pm8E2hzKEV0tO5Uza4lDlW8tydsb3Mm8/J9d1Slq61nC4xditbycN2wESqcYwLdpZy", - "sAxj9JYT9FOc2AOXAFt8kawF6yVlinSs5RMqund4MyWCgrGQ3q8w3PVyVquqEK2RKUPYxK0EZq7pf4Bh", - "rtdnlSPBJ6055ZwHuKRQDq6bGLd+RwPHpMCdQX6BvjDlLjH5YaH5yx0W7tSPCm/NL/4FjLU6jPwH9vWH", - "RjIrrlWraK9pZ6b8xT7Z2U12ksffb/We4GTr4SCOt/Cj75OtR4MHjx7tPnzygCS7d73Y3abFtr0aU25t", - "s4pYNCxgrj8NstGIstFXLx4rosuXkOaHd5+izpSH8tENomXRvZ8LNIDeLj4ytdPjLpI1dtQPSUczfC4f", - "7SH7U57MFwgGr6P5v+pCokVnnU9R03hbsLZ/LRY9X7nEib5+OdNWzLQWL0WjnAB/5IEA62K60mKVzCaf", - "cbwsJ+jwoV18gSFlpuE1e4DbOArMgxMTVuQ1Tj3zOdV8CBE2bLi2CHHbhMyKHn8YKLCWxTGRcpil6TyX", - "QF+zqD32gz0hGesZnP493cXenXuzybY8ciP9hztihaNVOGKtzlaLg5i67oLCtvV28N0GCG0l3L59Pwxp", - "wz2hz+MMeqWY2lo8xaK/citnWHBCOwewyeZxLAVhVdtteWKqZmlhLBVWNO6ivt9s3T2nQ5Q3bNe/54lW", - "fmK0acTkPskv0s95BqlIUO6pOAN1XfBtD1aXgG/vSsOlSNe6XdtgRedtCDCXKgfClP+QlY72XfSKpfMi", - "w1+NocM7Zkmg05PGSXFDWtvRnoS6ZDnuYswYN/3UDNOiFCsiIhuntiwWkmomh+4oL+XVzihczRC0o3vp", - "erJJrTt8Km6TS7ot9OHOpiENQWcfFTlOXwyDP2ozxkuujrVNrRny84gJs91F5/51QkWO2rc/2v86Tj4Z", - "EZISFWqgDF3JfVGRqyOqfC5hOU/AHa3QFxGUWyjFe4sBLBUAS1IVoUGm7IfOM3MjJtzU2EF4ONSmYV4d", - "uBQzNDHjCcFMwt0gLZ1m2Fa0cojU8Lhh8yMqyMW6InNzugUZpvaDEugOUJOMTa4pz8p9/tEYX7tCHDZP", - "Dg2pgFaCCKMpEXla1ABLGjSRDuC7QpisZiPlW9wJqPeHjZqjyOrbED89NJMt5acjnrHPwknWRFqDlaKw", - "vfuMKI/moaRMw5nanexl73PKa+gS/PXSht7KWwhY01J+uWNkO+q7RGZV9NSSJvWlLsxWPQADW6WLzjka", - "Eu3S593S7V3u/LqQNxeapgRLSCaH992yHGzb7oT0BZm/EscHn0qnfdsfvb9eCUsx+i07r1tCkzv4zGDv", - "mzO4dBHW2TMKYgNCYdXDPNipVRw5QwHdL9sJGzn6W5Pvtz/Cv5cYVb9wmmiDBZv5jJWi7SmqDRuUcjYy", - "3fRoEumftcXD/qGQwlfE1OCkDA0zAa6dy8/LnSjOZBdVp8iNJkGU4DjWgiKdmxEJ2FFRfssBs7nNGQKX", - "bYwlwqkgOJmjASEMYaUEHWTeBRszB/h2gkwwZcZ+G2aFK+eZeoNMAEQzVvQbhhFckwFkw9W54QaWFEaS", - "slHqZtOCb86zwhH1pRgYc5jlyfa2lAAfop1ezxh2kqMhFui7noVPLxOWZ8eLvJXds5ZgaQ6qJEmH99GM", - "Z2niQPQKfj3sgSkMuVTaiLzmNDEYhUGj/N0BifmESNQzWNPzfNcrbEoDHiDXItAYvmH3U2+84c1Vhail", - "3Ja2oklazZGmF/dF+XC3tSse9p4s/36fs2FKY/U55JPeWMfO6wgoRwiLDBPzTjeomk/M9xs8A/c7XLsG", - "zpXUcpvwaXig1Abba9of6O26oF99i/IX0D++2re90mLd7wMebGO8UhvgVRSp26QvWpFOHLU4OrXk0xy2", - "/Gd/SfLnP49NFDCQihu56B8u4klFWxE2pKPMUDMa0pTowS5ZHk0xGbaNkTzXPP0u4nh278ORO5Nou/G4", - "nV+E5qtmwOi2m7D/LTDZjuP/9//+H2TZaWK5pcb2NU20/RH+fZy8gtOGhQbzUtlwyYwjlPcAH8zR8QEc", - "d6TZqDmy5ph7NUupBHhLe8kAXI6s3c5C+YKJwW5GIzEsiKIFti8URrujjet9E6AbFKCG5v144RcY61tf", - "YplAUqNF/bN3XQbaGcIduBoxw2sbIefo7lJy27zq3ctc7ZNzOiG/cdb+syM4US66NK3y1TPLam2/yt+/", - "tbAwWWm/fwxxeyVDrZLR1pg55uqy7zoO9i/G18q4WSZfdCNer9IUkWy65q340gluIUWAGU6J1FwOFyjJ", - "jdqO5XXTjSIz43u4MRrZPwhLIouwCPAbaXxGgKtLFlpWVPlxB350qH6/E3nbE0EmZLSzWxtqpzyUQc3u", - "8qF2e7WhdkNDPSgPtVsaymQvRg/b3Eq6gICSJsevOanGE7/rSXd35LE4ZJIf2pgaFsaZbA6gnLlB/xLT", - "JRSHqYiUgr4Wl8BsG61w+NkQqd1htCIHdQm5+PWKt/0C5YsP/ILNAZrOwYItXv/DT8WAvErHYba63AZP", - "xQAgmzh54Gqt3+mBeXCnFvBDmAy+9uTG4Ko9Piu1Pmqd6bjv5/E09/YNRfVCbZDvJsYXaoVeLs4eDv8F", - "Gxv8RVl8wabRdbCDHee/vPS+L+5op6DjAAJbc8kyFbX90f7XktNpG7wJ0l9jZpP5KMxVq2mtHMiWgbUg", - "0X31GWx5uPNWJLMwm201AnhG1J3vfu+LEGh/g/y3WxJVsHzsxTRpFnLNdGU+uwvS+vJVvTGG26j6L4Mz", - "XJ3Lr5Y3LA3fiZpuU8Sh5kfayjEtvMjbFHH4kn3Iwnlc32E0keHictpaUejPkoBZ29FVQjEhyvlbOZ56", - "zXJDjLr9Ef5tbem2ZpS5ZN3WiDI7vCrLWrhuT5Frtk3vfHq3TGEYNPzdDClit/N25Cdct7EV1ITp6thC", - "S5hWZt8CjWsGGtfTN5/L0TGb21ZBFJ1A/zb6QVjqv6uoJDQ3bBWShMaAd++k1FtjtvFQoB3pFxCJNN0T", - "l6gaAPZbDHLNGKQwdLgBjbX9Uf9rjdAjbOAKcUfLOqtpMAPbOhFHAO9vGm5ciTraxxoX73jFRt7wdvc+", - "q6TSv//tzOAVqWaFYOJiwqlHEm9PO1+yev6ro4et1DNwwN8lbrgh5Wpq05fTltZJSK2U8Q/cMp9mg5TG", - "6RyRmykHJwfsPvudbEhmNaX3G1Ja2/cFz1OpwAOEph65A5ivuUbdUTBPsJIJvW6c8CvJnP3MObDf8j+/", - "5X9+Nvfe9lcBWVPrAfL7O03y4RYov7/T5F3NH7V9QKpppObroFh25UUbhHCLq0wQmAj2WGmM4Xmrkctk", - "blFQuzR0UVe7iw7MZmgVsPuou3qd7d1HXplt/cdnrLLd6hzF7+C/wglKeS++3QtscRUMUFfCW4iNlsbS", - "guzQbYik+bu7qpXu3+5KUz6DvqTG1gCQS5bEu6arGa1vPZQIMWzcl1oRrRR225xyXgLml3dT9q7iY5WO", - "V631wTZlUM8Fm7DXmlfgL9lxPoxsUBHe3UnbPiVYuNwNU9EcazELkFsxJMJpGirF7j+vitL8LtNHjULv", - "XVjN4tHKHAIf+AMuvS9Zn1EWbU7bL8LeAHFY9yFoEBKfSmKi3DUw1Pe2xaLr3fk3s5R628hqb7uaUIBe", - "3YgmHilqg8JWHSNJZAqfmQldXdiCTZLueoW7X5cWUhrvm75erq89sliqtT1ht/SyVFu7N78v1GDpeheo", - "7t5MLK6Yrnvf6QvUZLlVFrjvlGP3FnVaLtnFVBKhpCdBbHkIqWWBifZJTz0dD/36h3m5MyjsCgXQnHRw", - "53i1T+BVWXp3ioWi0PndVXDOK7zmVa1tAelgsFgvwe3/+qHeTZPZubdoiPFqMDdvC24abPuqhfebLG7H", - "pYYIc2skyKYBGZzX6DxOXokXZL6x0ip5uWJnYV6RefOhbME8qx2wlIFveSbrCKx8Evs1FKL78su8LKTP", - "aG1z4BlRrSnuGVF3R26bc6NzidksIb/y02BNNt7Gri/TbtNltOzdoCMuUDwm8VWliDzC0AIoKoohg0Pn", - "nZAxqQhOlpiqt+o3WqXOL78w8C27fP4n9Oi05bNrJLxev5ZC+I2xRGosCEEagbKKob2iNK3t22Mr2dqO", - "Lto21B8iG0mYo0S/P6GMSKBfeFge1HyVsYSIdO73XwFYoHeBxh1WVIvq3IL2uQRGzb16V3bRdQm7R7qj", - "buQqY1TK9DJCEukVzsdS8pgWxrr96j4UBt5CT82qy3uRkCFlxCKhGMmyrp4dXXb2MQMuPjt7hTTx6BEM", - "xV92unroM/N5aeSUKKjeaxrapBzKKZfLSc7G1BUkhsrJ5VkvpOldQWW5y8Qb9BZJovQn8rKD7ukJqgUr", - "7wNYJ3Wk2b4SE1OlmaAYSyIjU0nZDoqyqak2tWXa5xiwoJGbMxL0W3pjU3KjvaqEKiTnUrN6F6FDE9bb", - "A9pwESvo7aMn3On1ej3kCptJlGTCtegwpYo12fNEE1qFVGAb+2hErwnLVbseFprqwLI403sHZezvMc62", - "rD13v1yjnuRte16QeVFlWcxr3T38z4zYLz40xZhdaWsoc83c5N53UYmewb0cYpo6Cn3Ye4KgPTiszvRL", - "YeVC0TKvSWp7JDGu0IQndDiHFiKwfLNSRFVzhrAvZTdi5mw+fckDsU13opIc+Wsyikuqqw6l9/grTCP+", - "wjsdlfhonaLX7czHUtsK/cZRLiM+rdrQg0qZubYcrK5pfYLXkg96A2kFlrhWbQMtE6SNm3tSbnk3+zWb", - "Z6xuYjZiax379MtswPGtncbm2mkEmOHWRrOhdWf8YTQgY3xNuchRA2YQmCNeYbayJQUcOQc2BNsD7CG9", - "pSRBgsSZEMRo8wQJnqb8mghzRUhbBJhdgUU1G9N4nPc+zOGZ0cR21QdnwRhgU6wUEUw608HvZxFp82/C", - "pTIGHYyYcPYPlbcRM2YVjSGmbY0cbeJYSkBvLQxgTYAYKuHf2DUBNEhnlplGIbACbZQbM63onOG1BLGS", - "yx5AJ3nKZk3cmTGhX5FtM4IGRM0IYSDkzE8aLnMOyRLz882UWgMbUphte1/wTwZcjaFjJWYJVlzMYXIP", - "DxA6Muu2PTmmgnJB1Tw3j2ENZd+ICgQixSyUdNFPfEYEYpArZUca05EW0G64yGxjDw2Is3/hDanyV3xg", - "cjLDPnE5kPJ+ToprB4VPND4gCxazDKdIEL2j+s2C91GpVQpGCabp3B+cSkT+yOAIzxsAVg9N7szukGsi", - "5ijBc3SPjhgHYz6nd+emGBfstPqzI/iZaRQzndpEMmMxTzCFhjJeUxTXj0Yb3kgQSVQXPTWP3/eHioj3", - "p/pH9AM6OX557wTfuCn7QIcROum/uec+eEqGXBDzRYROKCu/fP9+Gf2u0+BYs2WCOHTNMQqhZIMnNhOa", - "wlIIk9A/U6/QLYTKnHyo1H6jICMsklQzOR+apqamnY9WW3RRo9D1erVsVGffvSsAi/T8gSZ3wNDGX+8I", - "WG1cB9J0vfnWsXTVS4Vrd63ZgAGfZ+EE7ffynQc5hmZOA2iAZ614o7shQOxa8w25iK2W65eDyzZyJ8dY", - "GPk9xrJvtb+Lypk4D4UOX5mWkwZ3pvvTJEsVnaYEcWWUjUsKgt4mJkGXJOW+yNX58z5aMWfXhFFQBoJg", - "yZmMXBR7xsWVtURAp5YwCOtc7Hw8I77v8Qsg+a92PaqZQNRYLopOzMUVvYcG63tgWWzBE8rQ6dE+evDg", - "wRO94xOs8gxo0ACMzwwCQo6IHqETvnTSUEHbTNHZ6+QQdDbvf7QUdGbbWgRnAGlf0anqnVxzhOgtGF8W", - "YcBGVoBo4+eviWcsv3Jtuv6VNlyQa36lpU4eO9ar8wL0Vjp0UV8WrkxzULc5fhsZe+myM6EjAU3gLzvl", - "rvLOA7IhUmgClVaC4liiGUnT7iXr50C7w5EsF9/WcRlTqbjQrpQ10GRkBg8gYsqnWQoJS3peayH2FQgV", - "qfBk2kW/avitpWfdTRAsA7BPwXSM6u0DJZKKpil4UTQBr8w4aZEfJoa1e00brfkKO+KOG4wPqi3WCeTs", - "mVh3pH037TCAIlFjba9HCGcJ1ctsztvYZJR5RYHeMtnDj8n+ba7erxs/abx17xOjuTR9JyfhZTvhS6Co", - "1TQpTtMWVbDKB+DVZO4USwVeasj+JEg/NhLD9vrE0vrGnWhNe0IQnLxi6dxdil2av/1uydnH36BKwV+l", - "nreNOmq+uH0KVr/01ZaLRGgVl+X3OZsDcU472alAEcopnHfGgktZ+B1AeEVhyUv2NBMs4TP23H4qLDRw", - "Fq4o45nMh+VDJMkIVglq3TpB7jfwYSQB+aCdmLmdx0YVbWDGHoQU7XcHFoIikmeX6Z83A6zmWjRJqrDO", - "7O8hXNnjasIEjccu8yCP9DDDXpQz5JoAp6UQvIF9ppdqAoFee2Pw9PRTmH65dLRgf34hWfOdoEtQ7juZ", - "QLbiQEZzn7pW8KMumXKyzgg3SPGTSImMmaC71006S7HZaJNE4CWoeO06Q/4YdC/avD8W1W2QZLPosW4m", - "3JpR+g/TNXq0eRQp/jkQdEb/JA42WL9hAr0CaIBlA+aGTwfzLtrPI7RyzAX0Ph1j247bX3Dzwrz+UwvL", - "QtgTQduhKuo8f3Vx2ok6B/23tygGWK3IcJcevBNzNhDuxEaDHz/OhaEBRyPwmyO/zJF3GsBTbdiluZUS", - "xbqf0VIQzogMn4qas5MJFlfGW5VOiptkqFJ6VsBUMAdw0DJf+7tG+bqjoC7qq+qgdigzLpXoTyJ4gnhm", - "RrL6EeKWPE1JguDsyA9dUlE/auqiY2Wb6qv51J53aqkwZ7F/iyfvvDWgaarFnoUGzmwgQmsBq0wos0GO", - "MzAaLhz49uDNTmkMIY2m0KFpdVQft66Pvx9ZhsvkIOfNiV4+ATWHYWwOUtIGExKuFyS5b6BgFo/NAbcK", - "J5I4+4kOIbEyfOoEJOKR6YXtS/pXeGXrnTmVXav8CLnf4FyB7tE2GARJzMGkxrvCV8SdQEcoqShiMJrN", - "i8XJoU3QHGYm8HXuXyUzDjEN6OoJZZkiKMnARBjzmW/HG+0G9igEhLhw27YRtayxrDBlfaCdUPQvPwSf", - "jUludpcEhaU7qn1SPRaBzCSLRLNEbxMMFV+yLXQ8RKB524zoPhjiVC77YvG8BQ5sjnTTZeU1rhYfluKj", - "4J9/06NNetToonV96kopn7xsT7iYzz7nV5SU6vgQcR0uf5PyGGqAZSLt7HXGSk33trd3dr/v9rq97s7e", - "48ePHwf8oVhPU/pK7m1v8ylhxtg2z/XMdoEBfwEUgabg1IkHykZE2qBzghIyyEajInEp98F//4lgwdCE", - "C/LuXn1uyrcTHsvtkVGgW6CgSbINo2xr3XpNyew+8Ia1lG03iKBbUwcTzrspG5nrBmDt5m7GLeCzmiEI", - "oG282BJAmzZfqmbXGqwJZ0TRP8l2guV4wLFIbOmOrYRck1Qrm61RRhNSAtBegm8JoHerfU1kuRFKQOR3", - "plqCUcn6WhVBJdM0TFcLuLoO40FO8M5Mkl10IckwS8HuKhgCQi+GVbr+fDBC29WXii/2Xx9bk8BaZpkk", - "QppTJkhpgky/wsoztyPyeBVHkrCkNKS8ZIqjaywohwMn03UN3ZuRwZjzqwjJFMdXESIqNtlUa1JCqbZy", - "cBcWVZL89O7T/wsAAP//bhNSDRlvAQA=", + "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", + "AQA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/client/node/clients/entitlement.ts b/api/client/node/clients/entitlement.ts index 05b5c6edc..bc6c5bade 100644 --- a/api/client/node/clients/entitlement.ts +++ b/api/client/node/clients/entitlement.ts @@ -1,5 +1,6 @@ import { components, operations } from '../schemas/openapi.js' import { RequestOptions, BaseClient, OpenMeterConfig } from './client.js' +import { Paginated } from './pagination.js' export type Entitlement = | EntitlementMetered @@ -36,15 +37,13 @@ export class EntitlementClient extends BaseClient { /** * List all entitlements regardless of subject. - * @description - * Most useful for administrative purposes. * @example * const entitlement = await openmeter.entitlements.list() */ public async list( params?: ListEntitlementQueryParams, options?: RequestOptions - ): Promise { + ): Promise> { const searchParams = params ? BaseClient.toURLSearchParams(params) : undefined diff --git a/api/client/node/clients/feature.ts b/api/client/node/clients/feature.ts index 897338dac..e162b6ac1 100644 --- a/api/client/node/clients/feature.ts +++ b/api/client/node/clients/feature.ts @@ -1,5 +1,6 @@ import { components, operations } from '../schemas/openapi.js' import { RequestOptions, BaseClient, OpenMeterConfig } from './client.js' +import { Paginated } from './pagination.js' export type Feature = components['schemas']['Feature'] export type FeatureCreateInputs = components['schemas']['FeatureCreateInputs'] @@ -63,7 +64,7 @@ export class FeatureClient extends BaseClient { public async list( params?: ListFeatureQueryParams, options?: RequestOptions - ): Promise { + ): Promise> { const searchParams = params ? BaseClient.toURLSearchParams(params) : undefined diff --git a/api/client/node/clients/grant.ts b/api/client/node/clients/grant.ts index e5dfcb0f6..5f46eadd4 100644 --- a/api/client/node/clients/grant.ts +++ b/api/client/node/clients/grant.ts @@ -1,5 +1,6 @@ import { components, operations } from '../schemas/openapi.js' import { RequestOptions, BaseClient, OpenMeterConfig } from './client.js' +import { Paginated } from './pagination.js' export type EntitlementGrant = components['schemas']['EntitlementGrant'] export type EntitlementGrantCreateInput = @@ -22,7 +23,7 @@ export class GrantClient extends BaseClient { public async list( params?: ListGrantQueryParams, options?: RequestOptions - ): Promise { + ): Promise> { const searchParams = params ? BaseClient.toURLSearchParams(params) : undefined diff --git a/api/client/node/clients/pagination.ts b/api/client/node/clients/pagination.ts new file mode 100644 index 000000000..54677ab05 --- /dev/null +++ b/api/client/node/clients/pagination.ts @@ -0,0 +1,6 @@ +export interface Paginated { + items: T[] + totalCount: number + page: number + pageSize: number +} diff --git a/api/client/node/schemas/openapi.ts b/api/client/node/schemas/openapi.ts index 77774ec49..a018c184f 100644 --- a/api/client/node/schemas/openapi.ts +++ b/api/client/node/schemas/openapi.ts @@ -3,6 +3,17 @@ * Do not make direct changes to the file. */ +/** OneOf type helpers */ +type Without = { [P in Exclude]?: never } +type XOR = T | U extends object + ? (Without & U) | (Without & T) + : T | U +type OneOf = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? OneOf<[XOR, ...Rest]> + : never + export interface paths { '/api/v1/events': { /** @@ -127,13 +138,14 @@ export interface paths { /** * List entitlements * @description List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + * If page is provided that takes precedence and the paginated response is returned. */ get: operations['listEntitlements'] } '/api/v1/features': { /** * List features - * @description List all features. + * @description List all features. If page is provided that takes precedence and the paginated response is returned. */ get: operations['listFeatures'] /** @@ -161,6 +173,8 @@ export interface paths { /** * List grants * @description List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + * + * If page is provided that takes precedence and the paginated response is returned. */ get: operations['listGrants'] } @@ -610,6 +624,30 @@ export interface components { archivedAt?: string } & components['schemas']['FeatureCreateInputs'] & components['schemas']['SharedMetaFields'] + ListFeatureResponse: OneOf< + [ + components['schemas']['Feature'][], + { + /** + * @description Total number of features. + * @example 500 + */ + totalCount: number + /** + * @description Current page number. + * @example 1 + */ + page: number + /** + * @description Number of features per page. + * @example 100 + */ + pageSize: number + /** @description List of features. */ + items: components['schemas']['Feature'][] + }, + ] + > /** @description Limited representation of a feature resource which includes only its unique identifiers (id, key). */ FeatureMeta: { /** @@ -754,6 +792,30 @@ export interface components { | components['schemas']['EntitlementMetered'] | components['schemas']['EntitlementStatic'] | components['schemas']['EntitlementBoolean'] + ListEntitlementResponse: OneOf< + [ + components['schemas']['Entitlement'][], + { + /** + * @description Total number of entitlements. + * @example 500 + */ + totalCount: number + /** + * @description Current page number. + * @example 1 + */ + page: number + /** + * @description Number of entitlements per page. + * @example 100 + */ + pageSize: number + /** @description List of entitlements. */ + items: components['schemas']['Entitlement'][] + }, + ] + > /** * @description A segment of the grant burn down history. * @@ -994,6 +1056,30 @@ export interface components { voidedAt?: string recurrence?: components['schemas']['RecurringPeriod'] } + ListEntitlementGrantResponse: OneOf< + [ + components['schemas']['EntitlementGrant'][], + { + /** + * @description Total number of grants. + * @example 500 + */ + totalCount: number + /** + * @description Current page number. + * @example 1 + */ + page: number + /** + * @description Number of grants per page. + * @example 100 + */ + pageSize: number + /** @description List of grants. */ + items: components['schemas']['EntitlementGrant'][] + }, + ] + > EntitlementValue: { /** * @description Whether the subject has access to the feature. Shared accross all entitlement types. @@ -1640,6 +1726,10 @@ export interface components { entitlementIdOrFeatureKey: string /** @description Include deleted entries. */ includeDeleted?: boolean + /** @description Page number to return */ + queryPage?: number + /** @description Number of entries to return per page */ + queryPageSize?: number /** @description Number of entries to return */ queryLimit?: number /** @description Number of entries to skip */ @@ -2105,10 +2195,13 @@ export interface operations { /** * List entitlements * @description List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + * If page is provided that takes precedence and the paginated response is returned. */ listEntitlements: { parameters: { query?: { + page?: components['parameters']['queryPage'] + pageSize?: components['parameters']['queryPageSize'] limit?: components['parameters']['queryLimit'] offset?: components['parameters']['queryOffset'] /** @description Order by field */ @@ -2116,10 +2209,10 @@ export interface operations { } } responses: { - /** @description List of entitlements. */ + /** @description List of entitlements. If page is provided that takes precedence and the paginated response is returned. */ 200: { content: { - 'application/json': components['schemas']['Entitlement'][] + 'application/json': components['schemas']['ListEntitlementResponse'] } } 400: components['responses']['BadRequestProblemResponse'] @@ -2129,11 +2222,13 @@ export interface operations { } /** * List features - * @description List all features. + * @description List all features. If page is provided that takes precedence and the paginated response is returned. */ listFeatures: { parameters: { query?: { + page?: components['parameters']['queryPage'] + pageSize?: components['parameters']['queryPageSize'] limit?: components['parameters']['queryLimit'] offset?: components['parameters']['queryOffset'] /** @description Order by field */ @@ -2143,10 +2238,10 @@ export interface operations { } } responses: { - /** @description List of features. */ + /** @description List of features. If page is provided that takes precedence and the paginated response is returned. */ 200: { content: { - 'application/json': components['schemas']['Feature'][] + 'application/json': components['schemas']['ListFeatureResponse'] } } 400: components['responses']['BadRequestProblemResponse'] @@ -2226,10 +2321,14 @@ export interface operations { /** * List grants * @description List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + * + * If page is provided that takes precedence and the paginated response is returned. */ listGrants: { parameters: { query?: { + page?: components['parameters']['queryPage'] + pageSize?: components['parameters']['queryPageSize'] limit?: components['parameters']['queryLimit'] offset?: components['parameters']['queryOffset'] /** @description Order by field */ @@ -2238,10 +2337,10 @@ export interface operations { } } responses: { - /** @description List of grants. */ + /** @description List of grants. If page is provided that takes precedence and the paginated response is returned. */ 200: { content: { - 'application/json': components['schemas']['EntitlementGrant'][] + 'application/json': components['schemas']['ListEntitlementGrantResponse'] } } 401: components['responses']['UnauthorizedProblemResponse'] diff --git a/api/client/python/src/openmeter/_operations/_operations.py b/api/client/python/src/openmeter/_operations/_operations.py index a552b09a4..e59f79972 100644 --- a/api/client/python/src/openmeter/_operations/_operations.py +++ b/api/client/python/src/openmeter/_operations/_operations.py @@ -385,7 +385,13 @@ def build_query_portal_meter_request( def build_list_entitlements_request( - *, limit: int = 1000, offset: int = 0, order_by: str = "createdAt", **kwargs: Any + *, + page: int = 1, + page_size: int = 100, + limit: int = 1000, + offset: int = 0, + order_by: str = "createdAt", + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -396,6 +402,10 @@ def build_list_entitlements_request( _url = "/api/v1/entitlements" # Construct parameters + if page is not None: + _params["page"] = _SERIALIZER.query("page", page, "int", minimum=1) + if page_size is not None: + _params["pageSize"] = _SERIALIZER.query("page_size", page_size, "int", maximum=1000, minimum=1) if limit is not None: _params["limit"] = _SERIALIZER.query("limit", limit, "int", maximum=1000, minimum=1) if offset is not None: @@ -410,7 +420,14 @@ def build_list_entitlements_request( def build_list_features_request( - *, limit: int = 1000, offset: int = 0, order_by: str = "updatedAt", include_archived: bool = False, **kwargs: Any + *, + page: int = 1, + page_size: int = 100, + limit: int = 1000, + offset: int = 0, + order_by: str = "updatedAt", + include_archived: bool = False, + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -421,6 +438,10 @@ def build_list_features_request( _url = "/api/v1/features" # Construct parameters + if page is not None: + _params["page"] = _SERIALIZER.query("page", page, "int", minimum=1) + if page_size is not None: + _params["pageSize"] = _SERIALIZER.query("page_size", page_size, "int", maximum=1000, minimum=1) if limit is not None: _params["limit"] = _SERIALIZER.query("limit", limit, "int", maximum=1000, minimum=1) if offset is not None: @@ -492,7 +513,14 @@ def build_delete_feature_request(feature_id: str, **kwargs: Any) -> HttpRequest: def build_list_grants_request( - *, limit: int = 1000, offset: int = 0, order_by: str = "updatedAt", include_deleted: bool = False, **kwargs: Any + *, + page: int = 1, + page_size: int = 100, + limit: int = 1000, + offset: int = 0, + order_by: str = "updatedAt", + include_deleted: bool = False, + **kwargs: Any ) -> HttpRequest: _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) @@ -503,6 +531,10 @@ def build_list_grants_request( _url = "/api/v1/grants" # Construct parameters + if page is not None: + _params["page"] = _SERIALIZER.query("page", page, "int", minimum=1) + if page_size is not None: + _params["pageSize"] = _SERIALIZER.query("page_size", page_size, "int", maximum=1000, minimum=1) if limit is not None: _params["limit"] = _SERIALIZER.query("limit", limit, "int", maximum=1000, minimum=1) if offset is not None: @@ -2889,13 +2921,25 @@ def query_portal_meter( @distributed_trace def list_entitlements( - self, *, limit: int = 1000, offset: int = 0, order_by: str = "createdAt", **kwargs: Any - ) -> List[JSON]: + self, + *, + page: int = 1, + page_size: int = 100, + limit: int = 1000, + offset: int = 0, + order_by: str = "createdAt", + **kwargs: Any + ) -> Any: """List entitlements. List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + If page is provided that takes precedence and the paginated response is returned. + :keyword page: Page number to return. Default value is 1. + :paramtype page: int + :keyword page_size: Number of entries to return per page. Default value is 100. + :paramtype page_size: int :keyword limit: Number of entries to return. Default value is 1000. :paramtype limit: int :keyword offset: Number of entries to skip. Default value is 0. @@ -2903,17 +2947,9 @@ def list_entitlements( :keyword order_by: Order by field. Known values are: "createdAt" and "updatedAt". Default value is "createdAt". :paramtype order_by: str - :return: list of JSON object - :rtype: list[JSON] + :return: any + :rtype: any :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == [ - {} - ] """ error_map = { 404: ResourceNotFoundError, @@ -2927,9 +2963,11 @@ def list_entitlements( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[JSON]] = kwargs.pop("cls", None) + cls: ClsType[Any] = kwargs.pop("cls", None) _request = build_list_entitlements_request( + page=page, + page_size=page_size, limit=limit, offset=offset, order_by=order_by, @@ -2957,25 +2995,31 @@ def list_entitlements( deserialized = None if cls: - return cls(pipeline_response, cast(List[JSON], deserialized), {}) # type: ignore + return cls(pipeline_response, cast(Any, deserialized), {}) # type: ignore - return cast(List[JSON], deserialized) # type: ignore + return cast(Any, deserialized) # type: ignore @distributed_trace def list_features( self, *, + page: int = 1, + page_size: int = 100, limit: int = 1000, offset: int = 0, order_by: str = "updatedAt", include_archived: bool = False, **kwargs: Any - ) -> List[JSON]: - # pylint: disable=line-too-long + ) -> Any: """List features. - List all features. + List all features. If page is provided that takes precedence and the paginated response is + returned. + :keyword page: Page number to return. Default value is 1. + :paramtype page: int + :keyword page_size: Number of entries to return per page. Default value is 100. + :paramtype page_size: int :keyword limit: Number of entries to return. Default value is 1000. :paramtype limit: int :keyword offset: Number of entries to skip. Default value is 0. @@ -2985,47 +3029,9 @@ def list_features( :paramtype order_by: str :keyword include_archived: Include archived features. Default value is False. :paramtype include_archived: bool - :return: list of JSON object - :rtype: list[JSON] + :return: any + :rtype: any :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == [ - { - "createdAt": "2020-02-20 00:00:00", # The date and time the resource - was created. Required. - "id": "str", # Readonly unique ULID identifier. Required. - "key": "str", # The key is an immutable unique identifier of the - feature used throughout the API, for example when interacting with a - subject's entitlements. The key has to be unique across all active features, - but archived features can share the same key. The key should consist of - lowercase alphanumeric characters and dashes. Required. - "name": "str", # The name of the feature. Required. - "updatedAt": "2020-02-20 00:00:00", # The date and time the resource - was last updated. The initial value is the same as createdAt. Required. - "archivedAt": "2020-02-20 00:00:00", # Optional. If the feature is - archived, no new entitlements can be created for it. - "deletedAt": "2020-02-20 00:00:00", # Optional. The date and time - the resource was deleted. - "metadata": { - "str": "str" # Optional. Additional metadata for the - feature, useful for syncing with external systems and annotating custom - fields. - }, - "meterGroupByFilters": { - "str": "str" # Optional. Optional meter group by filters. - Useful if the meter scope is broader than what feature tracks. Example - scenario would be a meter tracking all token use with groupBy fields for - the model, then the feature could filter for model=gpt-4. - }, - "meterSlug": "str" # Optional. The meter that the feature is - associated with and and based on which usage is calculated. The meter - selected must have SUM or COUNT aggregation. - } - ] """ error_map = { 404: ResourceNotFoundError, @@ -3039,9 +3045,11 @@ def list_features( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[JSON]] = kwargs.pop("cls", None) + cls: ClsType[Any] = kwargs.pop("cls", None) _request = build_list_features_request( + page=page, + page_size=page_size, limit=limit, offset=offset, order_by=order_by, @@ -3070,9 +3078,9 @@ def list_features( deserialized = None if cls: - return cls(pipeline_response, cast(List[JSON], deserialized), {}) # type: ignore + return cls(pipeline_response, cast(Any, deserialized), {}) # type: ignore - return cast(List[JSON], deserialized) # type: ignore + return cast(Any, deserialized) # type: ignore @overload def create_feature(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> JSON: @@ -3492,19 +3500,26 @@ def delete_feature(self, feature_id: str, **kwargs: Any) -> None: # pylint: dis def list_grants( self, *, + page: int = 1, + page_size: int = 100, limit: int = 1000, offset: int = 0, order_by: str = "updatedAt", include_deleted: bool = False, **kwargs: Any - ) -> List[JSON]: - # pylint: disable=line-too-long + ) -> Any: """List grants. List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + If page is provided that takes precedence and the paginated response is returned. + + :keyword page: Page number to return. Default value is 1. + :paramtype page: int + :keyword page_size: Number of entries to return per page. Default value is 100. + :paramtype page_size: int :keyword limit: Number of entries to return. Default value is 1000. :paramtype limit: int :keyword offset: Number of entries to skip. Default value is 0. @@ -3514,75 +3529,9 @@ def list_grants( :paramtype order_by: str :keyword include_deleted: Include deleted entries. Default value is False. :paramtype include_deleted: bool - :return: list of JSON object - :rtype: list[JSON] + :return: any + :rtype: any :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == [ - { - "amount": 0.0, # The amount to grant. Should be a positive number. - Required. - "createdAt": "2020-02-20 00:00:00", # The date and time the resource - was created. Required. - "effectiveAt": "2020-02-20 00:00:00", # Effective date for grants - and anchor for recurring grants. Provided value will be ceiled to metering - windowSize (minute). Required. - "entitlementId": "str", # The unique entitlement ULID that the grant - is associated with. Required. - "expiration": { - "count": 0, # The expiration period count like 12 months. - Required. - "duration": "str" # The expiration period duration like - month. Required. Known values are: "HOUR", "DAY", "WEEK", "MONTH", and - "YEAR". - }, - "id": "str", # Readonly unique ULID identifier. Required. - "updatedAt": "2020-02-20 00:00:00", # The date and time the resource - was last updated. The initial value is the same as createdAt. Required. - "deletedAt": "2020-02-20 00:00:00", # Optional. The date and time - the resource was deleted. - "expiresAt": "2020-02-20 00:00:00", # Optional. The expiration date - of the grant. - "maxRolloverAmount": 0, # Optional. Default value is 0. Grants are - rolled over at reset, after which they can have a different balance compared - to what they had before the reset. Balance after the reset is calculated as: - Balance_After_Reset = MIN(MaxRolloverAmount, MAX(Balance_Before_Reset, - MinRolloverAmount)). - "metadata": { - "str": "str" # Optional. Dictionary of :code:``. - }, - "minRolloverAmount": 0, # Optional. Default value is 0. Grants are - rolled over at reset, after which they can have a different balance compared - to what they had before the reset. Balance after the reset is calculated as: - Balance_After_Reset = MIN(MaxRolloverAmount, MAX(Balance_Before_Reset, - MinRolloverAmount)). - "nextRecurrence": "2020-02-20 00:00:00", # Optional. The next time - the grant will recurr. - "priority": 1, # Optional. Default value is 1. The priority of the - grant. Grants with higher priority are applied first. Priority is a positive - decimal numbers. With lower numbers indicating higher importance. For - example, a priority of 1 is more urgent than a priority of 2. When there are - several grants available for the same subject, the system selects the grant - with the highest priority. In cases where grants share the same priority - level, the grant closest to its expiration will be used first. In the case of - two grants have identical priorities and expiration dates, the system will - use the grant that was created first. - "recurrence": { - "anchor": "2020-02-20 00:00:00", # An arbitrary anchor to - base the recurring period on. Required. - "interval": "str" # List of pre-defined periods that can be - used for recurring & scheduling. DAY: Every day WEEK: Every - week MONTH: Every month YEAR: Every year. Required. Known values - are: "DAY", "WEEK", "MONTH", and "YEAR". - }, - "voidedAt": "2020-02-20 00:00:00" # Optional. The date and time the - grant was voided (cannot be used after that). - } - ] """ error_map = { 404: ResourceNotFoundError, @@ -3595,9 +3544,11 @@ def list_grants( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[JSON]] = kwargs.pop("cls", None) + cls: ClsType[Any] = kwargs.pop("cls", None) _request = build_list_grants_request( + page=page, + page_size=page_size, limit=limit, offset=offset, order_by=order_by, @@ -3626,9 +3577,9 @@ def list_grants( deserialized = None if cls: - return cls(pipeline_response, cast(List[JSON], deserialized), {}) # type: ignore + return cls(pipeline_response, cast(Any, deserialized), {}) # type: ignore - return cast(List[JSON], deserialized) # type: ignore + return cast(Any, deserialized) # type: ignore @distributed_trace def void_grant(self, grant_id: str, **kwargs: Any) -> Optional[JSON]: diff --git a/api/client/python/src/openmeter/aio/_operations/_operations.py b/api/client/python/src/openmeter/aio/_operations/_operations.py index 7782a697c..416b99c86 100644 --- a/api/client/python/src/openmeter/aio/_operations/_operations.py +++ b/api/client/python/src/openmeter/aio/_operations/_operations.py @@ -1904,13 +1904,25 @@ async def query_portal_meter( @distributed_trace_async async def list_entitlements( - self, *, limit: int = 1000, offset: int = 0, order_by: str = "createdAt", **kwargs: Any - ) -> List[JSON]: + self, + *, + page: int = 1, + page_size: int = 100, + limit: int = 1000, + offset: int = 0, + order_by: str = "createdAt", + **kwargs: Any + ) -> Any: """List entitlements. List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + If page is provided that takes precedence and the paginated response is returned. + :keyword page: Page number to return. Default value is 1. + :paramtype page: int + :keyword page_size: Number of entries to return per page. Default value is 100. + :paramtype page_size: int :keyword limit: Number of entries to return. Default value is 1000. :paramtype limit: int :keyword offset: Number of entries to skip. Default value is 0. @@ -1918,17 +1930,9 @@ async def list_entitlements( :keyword order_by: Order by field. Known values are: "createdAt" and "updatedAt". Default value is "createdAt". :paramtype order_by: str - :return: list of JSON object - :rtype: list[JSON] + :return: any + :rtype: any :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == [ - {} - ] """ error_map = { 404: ResourceNotFoundError, @@ -1942,9 +1946,11 @@ async def list_entitlements( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[JSON]] = kwargs.pop("cls", None) + cls: ClsType[Any] = kwargs.pop("cls", None) _request = build_list_entitlements_request( + page=page, + page_size=page_size, limit=limit, offset=offset, order_by=order_by, @@ -1972,25 +1978,31 @@ async def list_entitlements( deserialized = None if cls: - return cls(pipeline_response, cast(List[JSON], deserialized), {}) # type: ignore + return cls(pipeline_response, cast(Any, deserialized), {}) # type: ignore - return cast(List[JSON], deserialized) # type: ignore + return cast(Any, deserialized) # type: ignore @distributed_trace_async async def list_features( self, *, + page: int = 1, + page_size: int = 100, limit: int = 1000, offset: int = 0, order_by: str = "updatedAt", include_archived: bool = False, **kwargs: Any - ) -> List[JSON]: - # pylint: disable=line-too-long + ) -> Any: """List features. - List all features. + List all features. If page is provided that takes precedence and the paginated response is + returned. + :keyword page: Page number to return. Default value is 1. + :paramtype page: int + :keyword page_size: Number of entries to return per page. Default value is 100. + :paramtype page_size: int :keyword limit: Number of entries to return. Default value is 1000. :paramtype limit: int :keyword offset: Number of entries to skip. Default value is 0. @@ -2000,47 +2012,9 @@ async def list_features( :paramtype order_by: str :keyword include_archived: Include archived features. Default value is False. :paramtype include_archived: bool - :return: list of JSON object - :rtype: list[JSON] + :return: any + :rtype: any :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == [ - { - "createdAt": "2020-02-20 00:00:00", # The date and time the resource - was created. Required. - "id": "str", # Readonly unique ULID identifier. Required. - "key": "str", # The key is an immutable unique identifier of the - feature used throughout the API, for example when interacting with a - subject's entitlements. The key has to be unique across all active features, - but archived features can share the same key. The key should consist of - lowercase alphanumeric characters and dashes. Required. - "name": "str", # The name of the feature. Required. - "updatedAt": "2020-02-20 00:00:00", # The date and time the resource - was last updated. The initial value is the same as createdAt. Required. - "archivedAt": "2020-02-20 00:00:00", # Optional. If the feature is - archived, no new entitlements can be created for it. - "deletedAt": "2020-02-20 00:00:00", # Optional. The date and time - the resource was deleted. - "metadata": { - "str": "str" # Optional. Additional metadata for the - feature, useful for syncing with external systems and annotating custom - fields. - }, - "meterGroupByFilters": { - "str": "str" # Optional. Optional meter group by filters. - Useful if the meter scope is broader than what feature tracks. Example - scenario would be a meter tracking all token use with groupBy fields for - the model, then the feature could filter for model=gpt-4. - }, - "meterSlug": "str" # Optional. The meter that the feature is - associated with and and based on which usage is calculated. The meter - selected must have SUM or COUNT aggregation. - } - ] """ error_map = { 404: ResourceNotFoundError, @@ -2054,9 +2028,11 @@ async def list_features( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[JSON]] = kwargs.pop("cls", None) + cls: ClsType[Any] = kwargs.pop("cls", None) _request = build_list_features_request( + page=page, + page_size=page_size, limit=limit, offset=offset, order_by=order_by, @@ -2085,9 +2061,9 @@ async def list_features( deserialized = None if cls: - return cls(pipeline_response, cast(List[JSON], deserialized), {}) # type: ignore + return cls(pipeline_response, cast(Any, deserialized), {}) # type: ignore - return cast(List[JSON], deserialized) # type: ignore + return cast(Any, deserialized) # type: ignore @overload async def create_feature(self, body: JSON, *, content_type: str = "application/json", **kwargs: Any) -> JSON: @@ -2509,19 +2485,26 @@ async def delete_feature( # pylint: disable=inconsistent-return-statements async def list_grants( self, *, + page: int = 1, + page_size: int = 100, limit: int = 1000, offset: int = 0, order_by: str = "updatedAt", include_deleted: bool = False, **kwargs: Any - ) -> List[JSON]: - # pylint: disable=line-too-long + ) -> Any: """List grants. List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + If page is provided that takes precedence and the paginated response is returned. + + :keyword page: Page number to return. Default value is 1. + :paramtype page: int + :keyword page_size: Number of entries to return per page. Default value is 100. + :paramtype page_size: int :keyword limit: Number of entries to return. Default value is 1000. :paramtype limit: int :keyword offset: Number of entries to skip. Default value is 0. @@ -2531,75 +2514,9 @@ async def list_grants( :paramtype order_by: str :keyword include_deleted: Include deleted entries. Default value is False. :paramtype include_deleted: bool - :return: list of JSON object - :rtype: list[JSON] + :return: any + :rtype: any :raises ~azure.core.exceptions.HttpResponseError: - - Example: - .. code-block:: python - - # response body for status code(s): 200 - response == [ - { - "amount": 0.0, # The amount to grant. Should be a positive number. - Required. - "createdAt": "2020-02-20 00:00:00", # The date and time the resource - was created. Required. - "effectiveAt": "2020-02-20 00:00:00", # Effective date for grants - and anchor for recurring grants. Provided value will be ceiled to metering - windowSize (minute). Required. - "entitlementId": "str", # The unique entitlement ULID that the grant - is associated with. Required. - "expiration": { - "count": 0, # The expiration period count like 12 months. - Required. - "duration": "str" # The expiration period duration like - month. Required. Known values are: "HOUR", "DAY", "WEEK", "MONTH", and - "YEAR". - }, - "id": "str", # Readonly unique ULID identifier. Required. - "updatedAt": "2020-02-20 00:00:00", # The date and time the resource - was last updated. The initial value is the same as createdAt. Required. - "deletedAt": "2020-02-20 00:00:00", # Optional. The date and time - the resource was deleted. - "expiresAt": "2020-02-20 00:00:00", # Optional. The expiration date - of the grant. - "maxRolloverAmount": 0, # Optional. Default value is 0. Grants are - rolled over at reset, after which they can have a different balance compared - to what they had before the reset. Balance after the reset is calculated as: - Balance_After_Reset = MIN(MaxRolloverAmount, MAX(Balance_Before_Reset, - MinRolloverAmount)). - "metadata": { - "str": "str" # Optional. Dictionary of :code:``. - }, - "minRolloverAmount": 0, # Optional. Default value is 0. Grants are - rolled over at reset, after which they can have a different balance compared - to what they had before the reset. Balance after the reset is calculated as: - Balance_After_Reset = MIN(MaxRolloverAmount, MAX(Balance_Before_Reset, - MinRolloverAmount)). - "nextRecurrence": "2020-02-20 00:00:00", # Optional. The next time - the grant will recurr. - "priority": 1, # Optional. Default value is 1. The priority of the - grant. Grants with higher priority are applied first. Priority is a positive - decimal numbers. With lower numbers indicating higher importance. For - example, a priority of 1 is more urgent than a priority of 2. When there are - several grants available for the same subject, the system selects the grant - with the highest priority. In cases where grants share the same priority - level, the grant closest to its expiration will be used first. In the case of - two grants have identical priorities and expiration dates, the system will - use the grant that was created first. - "recurrence": { - "anchor": "2020-02-20 00:00:00", # An arbitrary anchor to - base the recurring period on. Required. - "interval": "str" # List of pre-defined periods that can be - used for recurring & scheduling. DAY: Every day WEEK: Every - week MONTH: Every month YEAR: Every year. Required. Known values - are: "DAY", "WEEK", "MONTH", and "YEAR". - }, - "voidedAt": "2020-02-20 00:00:00" # Optional. The date and time the - grant was voided (cannot be used after that). - } - ] """ error_map = { 404: ResourceNotFoundError, @@ -2612,9 +2529,11 @@ async def list_grants( _headers = kwargs.pop("headers", {}) or {} _params = kwargs.pop("params", {}) or {} - cls: ClsType[List[JSON]] = kwargs.pop("cls", None) + cls: ClsType[Any] = kwargs.pop("cls", None) _request = build_list_grants_request( + page=page, + page_size=page_size, limit=limit, offset=offset, order_by=order_by, @@ -2643,9 +2562,9 @@ async def list_grants( deserialized = None if cls: - return cls(pipeline_response, cast(List[JSON], deserialized), {}) # type: ignore + return cls(pipeline_response, cast(Any, deserialized), {}) # type: ignore - return cast(List[JSON], deserialized) # type: ignore + return cast(Any, deserialized) # type: ignore @distributed_trace_async async def void_grant(self, grant_id: str, **kwargs: Any) -> Optional[JSON]: diff --git a/api/client/web/src/client/openapi.ts b/api/client/web/src/client/openapi.ts index 77774ec49..a018c184f 100644 --- a/api/client/web/src/client/openapi.ts +++ b/api/client/web/src/client/openapi.ts @@ -3,6 +3,17 @@ * Do not make direct changes to the file. */ +/** OneOf type helpers */ +type Without = { [P in Exclude]?: never } +type XOR = T | U extends object + ? (Without & U) | (Without & T) + : T | U +type OneOf = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? OneOf<[XOR, ...Rest]> + : never + export interface paths { '/api/v1/events': { /** @@ -127,13 +138,14 @@ export interface paths { /** * List entitlements * @description List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + * If page is provided that takes precedence and the paginated response is returned. */ get: operations['listEntitlements'] } '/api/v1/features': { /** * List features - * @description List all features. + * @description List all features. If page is provided that takes precedence and the paginated response is returned. */ get: operations['listFeatures'] /** @@ -161,6 +173,8 @@ export interface paths { /** * List grants * @description List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + * + * If page is provided that takes precedence and the paginated response is returned. */ get: operations['listGrants'] } @@ -610,6 +624,30 @@ export interface components { archivedAt?: string } & components['schemas']['FeatureCreateInputs'] & components['schemas']['SharedMetaFields'] + ListFeatureResponse: OneOf< + [ + components['schemas']['Feature'][], + { + /** + * @description Total number of features. + * @example 500 + */ + totalCount: number + /** + * @description Current page number. + * @example 1 + */ + page: number + /** + * @description Number of features per page. + * @example 100 + */ + pageSize: number + /** @description List of features. */ + items: components['schemas']['Feature'][] + }, + ] + > /** @description Limited representation of a feature resource which includes only its unique identifiers (id, key). */ FeatureMeta: { /** @@ -754,6 +792,30 @@ export interface components { | components['schemas']['EntitlementMetered'] | components['schemas']['EntitlementStatic'] | components['schemas']['EntitlementBoolean'] + ListEntitlementResponse: OneOf< + [ + components['schemas']['Entitlement'][], + { + /** + * @description Total number of entitlements. + * @example 500 + */ + totalCount: number + /** + * @description Current page number. + * @example 1 + */ + page: number + /** + * @description Number of entitlements per page. + * @example 100 + */ + pageSize: number + /** @description List of entitlements. */ + items: components['schemas']['Entitlement'][] + }, + ] + > /** * @description A segment of the grant burn down history. * @@ -994,6 +1056,30 @@ export interface components { voidedAt?: string recurrence?: components['schemas']['RecurringPeriod'] } + ListEntitlementGrantResponse: OneOf< + [ + components['schemas']['EntitlementGrant'][], + { + /** + * @description Total number of grants. + * @example 500 + */ + totalCount: number + /** + * @description Current page number. + * @example 1 + */ + page: number + /** + * @description Number of grants per page. + * @example 100 + */ + pageSize: number + /** @description List of grants. */ + items: components['schemas']['EntitlementGrant'][] + }, + ] + > EntitlementValue: { /** * @description Whether the subject has access to the feature. Shared accross all entitlement types. @@ -1640,6 +1726,10 @@ export interface components { entitlementIdOrFeatureKey: string /** @description Include deleted entries. */ includeDeleted?: boolean + /** @description Page number to return */ + queryPage?: number + /** @description Number of entries to return per page */ + queryPageSize?: number /** @description Number of entries to return */ queryLimit?: number /** @description Number of entries to skip */ @@ -2105,10 +2195,13 @@ export interface operations { /** * List entitlements * @description List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + * If page is provided that takes precedence and the paginated response is returned. */ listEntitlements: { parameters: { query?: { + page?: components['parameters']['queryPage'] + pageSize?: components['parameters']['queryPageSize'] limit?: components['parameters']['queryLimit'] offset?: components['parameters']['queryOffset'] /** @description Order by field */ @@ -2116,10 +2209,10 @@ export interface operations { } } responses: { - /** @description List of entitlements. */ + /** @description List of entitlements. If page is provided that takes precedence and the paginated response is returned. */ 200: { content: { - 'application/json': components['schemas']['Entitlement'][] + 'application/json': components['schemas']['ListEntitlementResponse'] } } 400: components['responses']['BadRequestProblemResponse'] @@ -2129,11 +2222,13 @@ export interface operations { } /** * List features - * @description List all features. + * @description List all features. If page is provided that takes precedence and the paginated response is returned. */ listFeatures: { parameters: { query?: { + page?: components['parameters']['queryPage'] + pageSize?: components['parameters']['queryPageSize'] limit?: components['parameters']['queryLimit'] offset?: components['parameters']['queryOffset'] /** @description Order by field */ @@ -2143,10 +2238,10 @@ export interface operations { } } responses: { - /** @description List of features. */ + /** @description List of features. If page is provided that takes precedence and the paginated response is returned. */ 200: { content: { - 'application/json': components['schemas']['Feature'][] + 'application/json': components['schemas']['ListFeatureResponse'] } } 400: components['responses']['BadRequestProblemResponse'] @@ -2226,10 +2321,14 @@ export interface operations { /** * List grants * @description List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + * + * If page is provided that takes precedence and the paginated response is returned. */ listGrants: { parameters: { query?: { + page?: components['parameters']['queryPage'] + pageSize?: components['parameters']['queryPageSize'] limit?: components['parameters']['queryLimit'] offset?: components['parameters']['queryOffset'] /** @description Order by field */ @@ -2238,10 +2337,10 @@ export interface operations { } } responses: { - /** @description List of grants. */ + /** @description List of grants. If page is provided that takes precedence and the paginated response is returned. */ 200: { content: { - 'application/json': components['schemas']['EntitlementGrant'][] + 'application/json': components['schemas']['ListEntitlementGrantResponse'] } } 401: components['responses']['UnauthorizedProblemResponse'] diff --git a/api/openapi.yaml b/api/openapi.yaml index 9413e317c..79ab1d619 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -640,10 +640,13 @@ paths: summary: List entitlements description: | List all entitlements regardless of subject. This endpoint is intended for administrative purposes. + If page is provided that takes precedence and the paginated response is returned. tags: - Entitlements (Experimental) parameters: # TODO: add search capabilities + - $ref: "#/components/parameters/queryPage" + - $ref: "#/components/parameters/queryPageSize" - $ref: "#/components/parameters/queryLimit" - $ref: "#/components/parameters/queryOffset" - name: orderBy @@ -658,13 +661,13 @@ paths: default: createdAt responses: "200": - description: List of entitlements. + description: | + List of entitlements. If page is provided that takes precedence and the paginated response is returned. content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/Entitlement" + $ref: "#/components/schemas/ListEntitlementResponse" + "400": $ref: "#/components/responses/BadRequestProblemResponse" "401": @@ -677,10 +680,12 @@ paths: operationId: listFeatures summary: List features description: | - List all features. + List all features. If page is provided that takes precedence and the paginated response is returned. tags: - Entitlements (Experimental) parameters: + - $ref: "#/components/parameters/queryPage" + - $ref: "#/components/parameters/queryPageSize" - $ref: "#/components/parameters/queryLimit" - $ref: "#/components/parameters/queryOffset" - name: orderBy @@ -703,13 +708,13 @@ paths: default: false responses: "200": - description: List of features. + description: | + List of features. If page is provided that takes precedence and the paginated response is returned. content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/Feature" + $ref: "#/components/schemas/ListFeatureResponse" + "400": $ref: "#/components/responses/BadRequestProblemResponse" "401": @@ -795,9 +800,13 @@ paths: summary: List grants description: | List all grants for all the subjects and entitlements. This endpoint is intended for administrative purposes only. To fetch the grants of a specific entitlement please use the /api/v1/subjects/{subjectKeyOrID}/entitlements/{entitlementOrFeatureID}/grants endpoint. + + If page is provided that takes precedence and the paginated response is returned. tags: - Entitlements (Experimental) parameters: + - $ref: "#/components/parameters/queryPage" + - $ref: "#/components/parameters/queryPageSize" - $ref: "#/components/parameters/queryLimit" - $ref: "#/components/parameters/queryOffset" - name: orderBy @@ -814,13 +823,12 @@ paths: - $ref: "#/components/parameters/includeDeleted" responses: "200": - description: List of grants. + description: | + List of grants. If page is provided that takes precedence and the paginated response is returned. content: application/json: schema: - type: array - items: - $ref: "#/components/schemas/EntitlementGrant" + $ref: "#/components/schemas/ListEntitlementGrantResponse" "401": $ref: "#/components/responses/UnauthorizedProblemResponse" default: @@ -1860,6 +1868,36 @@ components: - $ref: "#/components/schemas/FeatureCreateInputs" - $ref: "#/components/schemas/SharedMetaFields" + ListFeatureResponse: + oneOf: + - type: array + items: + $ref: "#/components/schemas/Feature" + - type: object + required: + - totalCount + - page + - pageSize + - items + properties: + totalCount: + type: integer + description: Total number of features. + example: 500 + page: + type: integer + description: Current page number. + example: 1 + pageSize: + type: integer + description: Number of features per page. + example: 100 + items: + description: List of features. + type: array + items: + $ref: "#/components/schemas/Feature" + FeatureMeta: type: object description: | @@ -2070,6 +2108,35 @@ components: metered: "#/components/schemas/EntitlementMetered" static: "#/components/schemas/EntitlementStatic" boolean: "#/components/schemas/EntitlementBoolean" + ListEntitlementResponse: + oneOf: + - type: array + items: + $ref: "#/components/schemas/Entitlement" + - type: object + required: + - totalCount + - page + - pageSize + - items + properties: + totalCount: + type: integer + description: Total number of entitlements. + example: 500 + page: + type: integer + description: Current page number. + example: 1 + pageSize: + type: integer + description: Number of entitlements per page. + example: 100 + items: + description: List of entitlements. + type: array + items: + $ref: "#/components/schemas/Entitlement" # Might be changed later GrantBurnDownHistorySegment: type: object @@ -2357,6 +2424,35 @@ components: readOnly: true recurrence: $ref: "#/components/schemas/RecurringPeriod" + ListEntitlementGrantResponse: + oneOf: + - type: array + items: + $ref: "#/components/schemas/EntitlementGrant" + - type: object + required: + - totalCount + - page + - pageSize + - items + properties: + totalCount: + type: integer + description: Total number of grants. + example: 500 + page: + type: integer + description: Current page number. + example: 1 + pageSize: + type: integer + description: Number of grants per page. + example: 100 + items: + description: List of grants. + type: array + items: + $ref: "#/components/schemas/EntitlementGrant" EntitlementValue: type: object required: @@ -3213,6 +3309,26 @@ components: type: boolean default: false example: true + queryPage: + name: page + in: query + required: false + description: Page number to return + schema: + type: integer + minimum: 1 + default: 1 + example: 1 + queryPageSize: + name: pageSize + in: query + required: false + description: Number of entries to return per page + schema: + type: integer + minimum: 1 + maximum: 1000 + default: 100 queryLimit: name: limit in: query diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index f41bc23db..02304cf13 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -730,7 +730,9 @@ func TestCredit(t *testing.T) { require.NoError(t, err) require.Equal(t, http.StatusOK, featureListResp.StatusCode()) require.NotNil(t, featureListResp.JSON200) - require.Len(t, *featureListResp.JSON200, 1) + features, err := featureListResp.JSON200.AsListFeatureResponse0() + require.NoError(t, err) + require.Len(t, features, 1) resp, err := client.GetEntitlementValueWithResponse(context.Background(), subject, *entitlementId, &api.GetEntitlementValueParams{ Time: convert.ToPointer(eCreatedAt.Add(time.Minute * 2)), @@ -765,7 +767,9 @@ func TestCredit(t *testing.T) { require.NoError(t, err) require.Equal(t, http.StatusOK, featureListResp.StatusCode()) require.NotNil(t, featureListResp.JSON200) - require.Len(t, *featureListResp.JSON200, 1) + features, err := featureListResp.JSON200.AsListFeatureResponse0() + require.NoError(t, err) + require.Len(t, features, 1) // Reset usage resetResp, err := client.ResetEntitlementUsageWithResponse(context.Background(), subject, *entitlementId, api.ResetEntitlementUsageJSONRequestBody{ diff --git a/internal/credit/grant_connector.go b/internal/credit/grant_connector.go index 0b1b03706..9ab263461 100644 --- a/internal/credit/grant_connector.go +++ b/internal/credit/grant_connector.go @@ -8,6 +8,7 @@ import ( "github.com/openmeterio/openmeter/pkg/clock" "github.com/openmeterio/openmeter/pkg/framework/entutils" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" "github.com/openmeterio/openmeter/pkg/recurrence" ) @@ -25,7 +26,7 @@ type CreateGrantInput struct { type GrantConnector interface { CreateGrant(ctx context.Context, owner NamespacedGrantOwner, grant CreateGrantInput) (*Grant, error) VoidGrant(ctx context.Context, grantID models.NamespacedID) error - ListGrants(ctx context.Context, params ListGrantsParams) ([]Grant, error) + ListGrants(ctx context.Context, params ListGrantsParams) (pagination.PagedResponse[Grant], error) ListActiveGrantsBetween(ctx context.Context, owner NamespacedGrantOwner, from, to time.Time) ([]Grant, error) GetGrant(ctx context.Context, grantID models.NamespacedID) (Grant, error) } @@ -44,9 +45,12 @@ type ListGrantsParams struct { Namespace string OwnerID *GrantOwner IncludeDeleted bool - Offset int - Limit int + Page pagination.Page OrderBy GrantOrderBy + // will be deprecated + Limit int + // will be deprecated + Offset int } type GrantRepoCreateGrantInput struct { @@ -66,7 +70,8 @@ type GrantRepoCreateGrantInput struct { type GrantRepo interface { CreateGrant(ctx context.Context, grant GrantRepoCreateGrantInput) (*Grant, error) VoidGrant(ctx context.Context, grantID models.NamespacedID, at time.Time) error - ListGrants(ctx context.Context, params ListGrantsParams) ([]Grant, error) + // For bw compatibility, if pagination is not provided we + ListGrants(ctx context.Context, params ListGrantsParams) (pagination.PagedResponse[Grant], error) // ListActiveGrantsBetween returns all grants that are active at any point between the given time range. ListActiveGrantsBetween(ctx context.Context, owner NamespacedGrantOwner, from, to time.Time) ([]Grant, error) GetGrant(ctx context.Context, grantID models.NamespacedID) (Grant, error) @@ -185,7 +190,7 @@ func (m *grantConnector) VoidGrant(ctx context.Context, grantID models.Namespace return err } -func (m *grantConnector) ListGrants(ctx context.Context, params ListGrantsParams) ([]Grant, error) { +func (m *grantConnector) ListGrants(ctx context.Context, params ListGrantsParams) (pagination.PagedResponse[Grant], error) { return m.grantRepo.ListGrants(ctx, params) } diff --git a/internal/credit/httpdriver/grant.go b/internal/credit/httpdriver/grant.go index 30d0a5322..96f295908 100644 --- a/internal/credit/httpdriver/grant.go +++ b/internal/credit/httpdriver/grant.go @@ -14,6 +14,7 @@ import ( "github.com/openmeterio/openmeter/pkg/framework/commonhttp" "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" ) type GrantHandler interface { @@ -39,11 +40,11 @@ func NewGrantHandler( } } -type ListGrantsHandlerRequest struct { - params credit.ListGrantsParams -} type ( - ListGrantsHandlerResponse = []api.EntitlementGrant + ListGrantsHandlerRequest struct { + params credit.ListGrantsParams + } + ListGrantsHandlerResponse = commonhttp.Union[[]api.EntitlementGrant, pagination.PagedResponse[api.EntitlementGrant]] ListGrantsHandlerParams struct { Params api.ListGrantsParams } @@ -51,7 +52,7 @@ type ( type ListGrantsHandler httptransport.HandlerWithArgs[ListGrantsHandlerRequest, ListGrantsHandlerResponse, ListGrantsHandlerParams] func (h *grantHandler) ListGrants() ListGrantsHandler { - return httptransport.NewHandlerWithArgs[ListGrantsHandlerRequest, []api.EntitlementGrant, ListGrantsHandlerParams]( + return httptransport.NewHandlerWithArgs[ListGrantsHandlerRequest, ListGrantsHandlerResponse, ListGrantsHandlerParams]( func(ctx context.Context, r *http.Request, params ListGrantsHandlerParams) (ListGrantsHandlerRequest, error) { ns, err := h.resolveNamespace(ctx) if err != nil { @@ -62,23 +63,32 @@ func (h *grantHandler) ListGrants() ListGrantsHandler { params: credit.ListGrantsParams{ Namespace: ns, IncludeDeleted: defaultx.WithDefault(params.Params.IncludeDeleted, false), - Offset: defaultx.WithDefault(params.Params.Offset, 0), - Limit: defaultx.WithDefault(params.Params.Limit, 1000), - OrderBy: credit.GrantOrderBy(defaultx.WithDefault((*string)(params.Params.OrderBy), string(credit.GrantOrderByCreatedAt))), + Page: pagination.Page{ + PageSize: defaultx.WithDefault(params.Params.PageSize, 0), + PageNumber: defaultx.WithDefault(params.Params.Page, 0), + }, + Limit: defaultx.WithDefault(params.Params.Limit, commonhttp.DefaultPageSize), + Offset: defaultx.WithDefault(params.Params.Offset, 0), + OrderBy: credit.GrantOrderBy(defaultx.WithDefault((*string)(params.Params.OrderBy), string(credit.GrantOrderByCreatedAt))), }, }, nil }, - func(ctx context.Context, request ListGrantsHandlerRequest) ([]api.EntitlementGrant, error) { + func(ctx context.Context, request ListGrantsHandlerRequest) (ListGrantsHandlerResponse, error) { + // due to backward compatibility, if pagination is not provided we return a simple array + response := ListGrantsHandlerResponse{ + Option1: &[]api.EntitlementGrant{}, + Option2: &pagination.PagedResponse[api.EntitlementGrant]{}, + } grants, err := h.grantConnector.ListGrants(ctx, request.params) if err != nil { - return nil, err + return response, err } - apiGrants := make([]api.EntitlementGrant, 0, len(grants)) - for _, grant := range grants { + apiGrants := make([]api.EntitlementGrant, 0, len(grants.Items)) + for _, grant := range grants.Items { entitlementGrant, err := meteredentitlement.GrantFromCreditGrant(grant) if err != nil { - return nil, err + return response, err } // FIXME: not elegant but good for now, entitlement grants are all we have... apiGrant := entitlement_httpdriver.MapEntitlementGrantToAPI(nil, entitlementGrant) @@ -86,9 +96,20 @@ func (h *grantHandler) ListGrants() ListGrantsHandler { apiGrants = append(apiGrants, apiGrant) } - return apiGrants, nil + if request.params.Page.IsZero() { + response.Option1 = &apiGrants + } else { + response.Option1 = nil + response.Option2 = &pagination.PagedResponse[api.EntitlementGrant]{ + Items: apiGrants, + TotalCount: grants.TotalCount, + Page: grants.Page, + } + } + + return response, nil }, - commonhttp.JSONResponseEncoder[[]api.EntitlementGrant], + commonhttp.JSONResponseEncoder[ListGrantsHandlerResponse], httptransport.AppendOptions( h.options, httptransport.WithErrorEncoder(func(ctx context.Context, err error, w http.ResponseWriter, _ *http.Request) bool { diff --git a/internal/credit/postgresadapter/grant.go b/internal/credit/postgresadapter/grant.go index 8e1594906..8104aeab1 100644 --- a/internal/credit/postgresadapter/grant.go +++ b/internal/credit/postgresadapter/grant.go @@ -9,6 +9,7 @@ import ( db_grant "github.com/openmeterio/openmeter/internal/ent/db/grant" "github.com/openmeterio/openmeter/pkg/convert" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" "github.com/openmeterio/openmeter/pkg/recurrence" ) @@ -61,7 +62,7 @@ func (g *grantDBADapter) VoidGrant(ctx context.Context, grantID models.Namespace return command.Exec(ctx) } -func (g *grantDBADapter) ListGrants(ctx context.Context, params credit.ListGrantsParams) ([]credit.Grant, error) { +func (g *grantDBADapter) ListGrants(ctx context.Context, params credit.ListGrantsParams) (pagination.PagedResponse[credit.Grant], error) { query := g.db.Grant.Query().Where(db_grant.Namespace(params.Namespace)) if params.OwnerID != nil { @@ -87,25 +88,47 @@ func (g *grantDBADapter) ListGrants(ctx context.Context, params credit.ListGrant } } - if params.Limit > 0 { - query = query.Limit(params.Limit) + response := pagination.PagedResponse[credit.Grant]{ + Page: params.Page, } - if params.Offset > 0 { - query = query.Offset(params.Offset) + // we're using limit and offset + if params.Page.IsZero() { + if params.Limit > 0 { + query = query.Limit(params.Limit) + } + if params.Offset > 0 { + query = query.Offset(params.Offset) + } + + entities, err := query.All(ctx) + if err != nil { + return response, err + } + + grants := make([]credit.Grant, 0, len(entities)) + for _, entity := range entities { + grants = append(grants, mapGrantEntity(entity)) + } + + response.Items = grants + return response, nil } - entities, err := query.All(ctx) + paged, err := query.Paginate(ctx, params.Page) if err != nil { - return nil, err + return response, err } - grants := make([]credit.Grant, 0, len(entities)) - for _, entity := range entities { + grants := make([]credit.Grant, 0, len(paged.Items)) + for _, entity := range paged.Items { grants = append(grants, mapGrantEntity(entity)) } - return grants, nil + response.Items = grants + response.TotalCount = paged.TotalCount + + return response, nil } func (g *grantDBADapter) ListActiveGrantsBetween(ctx context.Context, owner credit.NamespacedGrantOwner, from, to time.Time) ([]credit.Grant, error) { diff --git a/internal/ent/db/paginate.go b/internal/ent/db/paginate.go new file mode 100644 index 000000000..4a9a6a747 --- /dev/null +++ b/internal/ent/db/paginate.go @@ -0,0 +1,250 @@ +// Code generated by ent, DO NOT EDIT. + +package db + +import ( + "context" + "fmt" + + "github.com/openmeterio/openmeter/pkg/pagination" +) + +// Paginate runs the query and returns a paginated response. +// If page is its 0 value then it will return all the items and populate the response page accordingly. +func (bs *BalanceSnapshotQuery) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*BalanceSnapshot], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + bs.ctx.Offset = &zero + bs.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := bs.Clone() + pagedQuery := bs + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*BalanceSnapshot]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err +} + +// type check +var _ pagination.Paginator[*BalanceSnapshot] = (*BalanceSnapshotQuery)(nil) + +// Paginate runs the query and returns a paginated response. +// If page is its 0 value then it will return all the items and populate the response page accordingly. +func (e *EntitlementQuery) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*Entitlement], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + e.ctx.Offset = &zero + e.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := e.Clone() + pagedQuery := e + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*Entitlement]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err +} + +// type check +var _ pagination.Paginator[*Entitlement] = (*EntitlementQuery)(nil) + +// Paginate runs the query and returns a paginated response. +// If page is its 0 value then it will return all the items and populate the response page accordingly. +func (f *FeatureQuery) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*Feature], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + f.ctx.Offset = &zero + f.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := f.Clone() + pagedQuery := f + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*Feature]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err +} + +// type check +var _ pagination.Paginator[*Feature] = (*FeatureQuery)(nil) + +// Paginate runs the query and returns a paginated response. +// If page is its 0 value then it will return all the items and populate the response page accordingly. +func (gr *GrantQuery) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*Grant], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + gr.ctx.Offset = &zero + gr.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := gr.Clone() + pagedQuery := gr + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*Grant]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err +} + +// type check +var _ pagination.Paginator[*Grant] = (*GrantQuery)(nil) + +// Paginate runs the query and returns a paginated response. +// If page is its 0 value then it will return all the items and populate the response page accordingly. +func (ur *UsageResetQuery) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*UsageReset], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + ur.ctx.Offset = &zero + ur.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := ur.Clone() + pagedQuery := ur + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*UsageReset]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err +} + +// type check +var _ pagination.Paginator[*UsageReset] = (*UsageResetQuery)(nil) diff --git a/internal/ent/generate.go b/internal/ent/generate.go index 35df44611..3fba8263d 100644 --- a/internal/ent/generate.go +++ b/internal/ent/generate.go @@ -1,3 +1,3 @@ package entdb -//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate --target ./db --feature sql/upsert --feature sql/lock --feature sql/versioned-migration --template ../../pkg/framework/entutils/expose.tpl ./schema +//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate --target ./db --feature sql/upsert --feature sql/lock --feature sql/versioned-migration --template ../../pkg/framework/entutils/expose.tpl --template ../../pkg/framework/entutils/paginate.tpl ./schema diff --git a/internal/entitlement/connector.go b/internal/entitlement/connector.go index acec355ab..314abfdde 100644 --- a/internal/entitlement/connector.go +++ b/internal/entitlement/connector.go @@ -9,6 +9,7 @@ import ( "github.com/openmeterio/openmeter/internal/productcatalog" "github.com/openmeterio/openmeter/pkg/framework/entutils" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" ) type ListEntitlementsOrderBy string @@ -23,10 +24,13 @@ type ListEntitlementsParams struct { SubjectKey string FeatureIDs []string FeatureKeys []string - Limit int - Offset int OrderBy ListEntitlementsOrderBy IncludeDeleted bool + Page pagination.Page + // will be deprecated + Limit int + // will be deprecated + Offset int } type Connector interface { @@ -37,7 +41,7 @@ type Connector interface { GetEntitlementValue(ctx context.Context, namespace string, subjectKey string, idOrFeatureKey string, at time.Time) (EntitlementValue, error) GetEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey models.SubjectKey) ([]Entitlement, error) - ListEntitlements(ctx context.Context, params ListEntitlementsParams) ([]Entitlement, error) + ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.PagedResponse[Entitlement], error) } type entitlementConnector struct { @@ -150,7 +154,7 @@ func (c *entitlementConnector) GetEntitlementValue(ctx context.Context, namespac return connector.GetValue(ent, at) } -func (c *entitlementConnector) ListEntitlements(ctx context.Context, params ListEntitlementsParams) ([]Entitlement, error) { +func (c *entitlementConnector) ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.PagedResponse[Entitlement], error) { return c.entitlementRepo.ListEntitlements(ctx, params) } diff --git a/internal/entitlement/httpdriver/entitlement.go b/internal/entitlement/httpdriver/entitlement.go index 1284f3394..79173ac5f 100644 --- a/internal/entitlement/httpdriver/entitlement.go +++ b/internal/entitlement/httpdriver/entitlement.go @@ -15,6 +15,7 @@ import ( "github.com/openmeterio/openmeter/pkg/framework/commonhttp" "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" "github.com/openmeterio/openmeter/pkg/recurrence" ) @@ -249,7 +250,7 @@ func (h *entitlementHandler) GetEntitlementsOfSubjectHandler() GetEntitlementsOf type ( ListEntitlementsHandlerRequest = entitlement.ListEntitlementsParams - ListEntitlementsHandlerResponse = []api.Entitlement + ListEntitlementsHandlerResponse = commonhttp.Union[[]api.Entitlement, pagination.PagedResponse[api.Entitlement]] ListEntitlementsHandlerParams = api.ListEntitlementsParams ) @@ -265,8 +266,12 @@ func (h *entitlementHandler) ListEntitlements() ListEntitlementsHandler { p := entitlement.ListEntitlementsParams{ Namespaces: []string{ns}, - Limit: defaultx.WithDefault(params.Limit, 1000), - Offset: defaultx.WithDefault(params.Offset, 0), + Page: pagination.Page{ + PageSize: defaultx.WithDefault(params.PageSize, 0), + PageNumber: defaultx.WithDefault(params.Page, 0), + }, + Limit: defaultx.WithDefault(params.Limit, commonhttp.DefaultPageSize), + Offset: defaultx.WithDefault(params.Offset, 0), } switch defaultx.WithDefault(params.OrderBy, "") { @@ -281,21 +286,39 @@ func (h *entitlementHandler) ListEntitlements() ListEntitlementsHandler { return p, nil }, func(ctx context.Context, request ListEntitlementsHandlerRequest) (ListEntitlementsHandlerResponse, error) { - entitlements, err := h.connector.ListEntitlements(ctx, request) + // due to backward compatibility, if pagination is not provided we return a simple array + response := ListEntitlementsHandlerResponse{ + Option1: &[]api.Entitlement{}, + Option2: &pagination.PagedResponse[api.Entitlement]{}, + } + paged, err := h.connector.ListEntitlements(ctx, request) if err != nil { - return nil, err + return response, err } - res := make([]api.Entitlement, 0, len(entitlements)) + entitlements := paged.Items + + mapped := make([]api.Entitlement, 0, len(entitlements)) for _, e := range entitlements { ent, err := Parser.ToAPIGeneric(&e) if err != nil { - return nil, err + return response, err } - res = append(res, *ent) + mapped = append(mapped, *ent) } - return res, nil + if request.Page.IsZero() { + response.Option1 = &mapped + } else { + response.Option1 = nil + response.Option2 = &pagination.PagedResponse[api.Entitlement]{ + Items: mapped, + TotalCount: paged.TotalCount, + Page: paged.Page, + } + } + + return response, nil }, commonhttp.JSONResponseEncoder[ListEntitlementsHandlerResponse], httptransport.AppendOptions( diff --git a/internal/entitlement/metered/entitlement_grant.go b/internal/entitlement/metered/entitlement_grant.go index c5481fb4e..c40cb09dd 100644 --- a/internal/entitlement/metered/entitlement_grant.go +++ b/internal/entitlement/metered/entitlement_grant.go @@ -70,8 +70,8 @@ func (e *connector) ListEntitlementGrants(ctx context.Context, namespace string, return nil, err } - ents := make([]EntitlementGrant, 0, len(grants)) - for _, grant := range grants { + ents := make([]EntitlementGrant, 0, len(grants.Items)) + for _, grant := range grants.Items { g, err := GrantFromCreditGrant(grant) if err != nil { return nil, err diff --git a/internal/entitlement/postgresadapter/entitlement.go b/internal/entitlement/postgresadapter/entitlement.go index c2b016c55..64285955b 100644 --- a/internal/entitlement/postgresadapter/entitlement.go +++ b/internal/entitlement/postgresadapter/entitlement.go @@ -14,6 +14,7 @@ import ( "github.com/openmeterio/openmeter/pkg/clock" "github.com/openmeterio/openmeter/pkg/convert" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" "github.com/openmeterio/openmeter/pkg/recurrence" ) @@ -140,7 +141,7 @@ func (a *entitlementDBAdapter) GetEntitlementsOfSubject(ctx context.Context, nam return result, nil } -func (a *entitlementDBAdapter) ListEntitlements(ctx context.Context, params entitlement.ListEntitlementsParams) ([]entitlement.Entitlement, error) { +func (a *entitlementDBAdapter) ListEntitlements(ctx context.Context, params entitlement.ListEntitlementsParams) (pagination.PagedResponse[entitlement.Entitlement], error) { query := a.db.Entitlement.Query() if len(params.Namespaces) > 0 { @@ -165,13 +166,6 @@ func (a *entitlementDBAdapter) ListEntitlements(ctx context.Context, params enti query = query.Where(db_entitlement.Or(db_entitlement.DeletedAtGT(clock.Now()), db_entitlement.DeletedAtIsNil())) } - if params.Limit > 0 { - query = query.Limit(params.Limit) - } - if params.Offset > 0 { - query = query.Offset(params.Offset) - } - switch params.OrderBy { case entitlement.ListEntitlementsOrderByCreatedAt: query = query.Order(db_entitlement.ByCreatedAt()) @@ -179,17 +173,47 @@ func (a *entitlementDBAdapter) ListEntitlements(ctx context.Context, params enti query = query.Order(db_entitlement.ByUpdatedAt()) } - entities, err := query.All(ctx) + response := pagination.PagedResponse[entitlement.Entitlement]{ + Page: params.Page, + } + + // we're using limit and offset + if params.Page.IsZero() { + if params.Limit > 0 { + query = query.Limit(params.Limit) + } + if params.Offset > 0 { + query = query.Offset(params.Offset) + } + + entities, err := query.All(ctx) + if err != nil { + return response, err + } + + mapped := make([]entitlement.Entitlement, 0, len(entities)) + for _, entity := range entities { + mapped = append(mapped, *mapEntitlementEntity(entity)) + } + + response.Items = mapped + return response, nil + } + + paged, err := query.Paginate(ctx, params.Page) if err != nil { - return nil, err + return response, err } - result := make([]entitlement.Entitlement, 0, len(entities)) - for _, e := range entities { + result := make([]entitlement.Entitlement, 0, len(paged.Items)) + for _, e := range paged.Items { result = append(result, *mapEntitlementEntity(e)) } - return result, nil + response.TotalCount = paged.TotalCount + response.Items = result + + return response, nil } func mapEntitlementEntity(e *db.Entitlement) *entitlement.Entitlement { diff --git a/internal/entitlement/repository.go b/internal/entitlement/repository.go index 0705f2cc0..31e12682b 100644 --- a/internal/entitlement/repository.go +++ b/internal/entitlement/repository.go @@ -6,6 +6,7 @@ import ( "github.com/openmeterio/openmeter/pkg/framework/entutils" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" "github.com/openmeterio/openmeter/pkg/recurrence" ) @@ -22,7 +23,7 @@ type EntitlementRepo interface { GetEntitlementOfSubject(ctx context.Context, namespace string, subjectKey string, idOrFeatureKey string) (*Entitlement, error) DeleteEntitlement(ctx context.Context, entitlementID models.NamespacedID) error - ListEntitlements(ctx context.Context, params ListEntitlementsParams) ([]Entitlement, error) + ListEntitlements(ctx context.Context, params ListEntitlementsParams) (pagination.PagedResponse[Entitlement], error) // FIXME: This is a terrbile hack LockEntitlementForTx(ctx context.Context, entitlementID models.NamespacedID) error diff --git a/internal/productcatalog/feature_connector.go b/internal/productcatalog/feature_connector.go index a9c37f7e0..611b0cdae 100644 --- a/internal/productcatalog/feature_connector.go +++ b/internal/productcatalog/feature_connector.go @@ -7,6 +7,7 @@ import ( "github.com/openmeterio/openmeter/internal/meter" "github.com/openmeterio/openmeter/pkg/framework/entutils" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" ) type CreateFeatureInputs struct { @@ -23,7 +24,7 @@ type FeatureConnector interface { CreateFeature(ctx context.Context, feature CreateFeatureInputs) (Feature, error) // Should just use deletedAt, there's no real "archiving" ArchiveFeature(ctx context.Context, featureID models.NamespacedID) error - ListFeatures(ctx context.Context, params ListFeaturesParams) ([]Feature, error) + ListFeatures(ctx context.Context, params ListFeaturesParams) (pagination.PagedResponse[Feature], error) GetFeature(ctx context.Context, namespace string, idOrKey string, includeArchived IncludeArchivedFeature) (*Feature, error) } @@ -45,15 +46,18 @@ type ListFeaturesParams struct { Namespace string MeterSlug string IncludeArchived bool - Offset int - Limit int + Page pagination.Page OrderBy FeatureOrderBy + // will be deprecated + Limit int + // will be deprecated + Offset int } type FeatureRepo interface { CreateFeature(ctx context.Context, feature CreateFeatureInputs) (Feature, error) ArchiveFeature(ctx context.Context, featureID models.NamespacedID) error - ListFeatures(ctx context.Context, params ListFeaturesParams) ([]Feature, error) + ListFeatures(ctx context.Context, params ListFeaturesParams) (pagination.PagedResponse[Feature], error) GetByIdOrKey(ctx context.Context, namespace string, idOrKey string, includeArchived bool) (*Feature, error) entutils.TxCreator @@ -127,7 +131,7 @@ func (c *featureConnector) ArchiveFeature(ctx context.Context, featureID models. return c.featureRepo.ArchiveFeature(ctx, featureID) } -func (c *featureConnector) ListFeatures(ctx context.Context, params ListFeaturesParams) ([]Feature, error) { +func (c *featureConnector) ListFeatures(ctx context.Context, params ListFeaturesParams) (pagination.PagedResponse[Feature], error) { return c.featureRepo.ListFeatures(ctx, params) } diff --git a/internal/productcatalog/httpdriver/feature.go b/internal/productcatalog/httpdriver/feature.go index 182e24c67..8bbbafa10 100644 --- a/internal/productcatalog/httpdriver/feature.go +++ b/internal/productcatalog/httpdriver/feature.go @@ -15,6 +15,7 @@ import ( "github.com/openmeterio/openmeter/pkg/framework/operation" "github.com/openmeterio/openmeter/pkg/framework/transport/httptransport" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" ) type FeatureHandler interface { @@ -119,7 +120,7 @@ func (h *featureHandlers) CreateFeature() CreateFeatureHandler { type ( ListFeaturesHandlerRequest = productcatalog.ListFeaturesParams - ListFeaturesHandlerResponse = []productcatalog.Feature + ListFeaturesHandlerResponse = commonhttp.Union[[]api.Feature, pagination.PagedResponse[api.Feature]] ListFeaturesHandlerParams = api.ListFeaturesParams ) @@ -135,13 +136,17 @@ func (h *featureHandlers) ListFeatures() ListFeaturesHandler { params := productcatalog.ListFeaturesParams{ Namespace: ns, IncludeArchived: defaultx.WithDefault(apiParams.IncludeArchived, false), - Offset: defaultx.WithDefault(apiParams.Offset, 0), - Limit: defaultx.WithDefault(apiParams.Limit, 0), - OrderBy: defaultx.WithDefault((*productcatalog.FeatureOrderBy)(apiParams.OrderBy), productcatalog.FeatureOrderByUpdatedAt), + Page: pagination.Page{ + PageSize: defaultx.WithDefault(apiParams.PageSize, 0), + PageNumber: defaultx.WithDefault(apiParams.Page, 0), + }, + Limit: defaultx.WithDefault(apiParams.Limit, commonhttp.DefaultPageSize), + Offset: defaultx.WithDefault(apiParams.Offset, 0), + OrderBy: defaultx.WithDefault((*productcatalog.FeatureOrderBy)(apiParams.OrderBy), productcatalog.FeatureOrderByUpdatedAt), } // TODO: standardize - if params.Limit > 1000 { + if params.Page.PageSize > 1000 { return params, commonhttp.NewHTTPError( http.StatusBadRequest, fmt.Errorf("limit must be less than or equal to %d", 1000), @@ -150,8 +155,34 @@ func (h *featureHandlers) ListFeatures() ListFeaturesHandler { return params, nil }, - func(ctx context.Context, params ListFeaturesHandlerRequest) ([]productcatalog.Feature, error) { - return h.connector.ListFeatures(ctx, params) + func(ctx context.Context, params ListFeaturesHandlerRequest) (ListFeaturesHandlerResponse, error) { + response := ListFeaturesHandlerResponse{ + Option1: &[]api.Feature{}, + Option2: &pagination.PagedResponse[api.Feature]{}, + } + + paged, err := h.connector.ListFeatures(ctx, params) + if err != nil { + return response, err + } + + mapped := make([]api.Feature, 0, len(paged.Items)) + for _, f := range paged.Items { + mapped = append(mapped, MaptFeatureToResponse(f)) + } + + if params.Page.IsZero() { + response.Option1 = &mapped + } else { + response.Option1 = nil + response.Option2 = &pagination.PagedResponse[api.Feature]{ + Items: mapped, + TotalCount: paged.TotalCount, + Page: paged.Page, + } + } + + return response, err }, commonhttp.JSONResponseEncoder, httptransport.AppendOptions( diff --git a/internal/productcatalog/httpdriver/parser.go b/internal/productcatalog/httpdriver/parser.go new file mode 100644 index 000000000..b323d58b8 --- /dev/null +++ b/internal/productcatalog/httpdriver/parser.go @@ -0,0 +1,22 @@ +package httpdriver + +import ( + "github.com/openmeterio/openmeter/api" + "github.com/openmeterio/openmeter/internal/productcatalog" + "github.com/openmeterio/openmeter/pkg/convert" +) + +func MaptFeatureToResponse(f productcatalog.Feature) api.Feature { + return api.Feature{ + CreatedAt: &f.CreatedAt, + DeletedAt: nil, + UpdatedAt: &f.UpdatedAt, + Id: &f.ID, + Key: f.Key, + Metadata: convert.MapToPointer(f.Metadata), + Name: f.Name, + ArchivedAt: f.ArchivedAt, + MeterGroupByFilters: convert.MapToPointer(f.MeterGroupByFilters), + MeterSlug: f.MeterSlug, + } +} diff --git a/internal/productcatalog/postgresadapter/feature.go b/internal/productcatalog/postgresadapter/feature.go index 7283c4f57..04c6448a6 100644 --- a/internal/productcatalog/postgresadapter/feature.go +++ b/internal/productcatalog/postgresadapter/feature.go @@ -11,6 +11,7 @@ import ( "github.com/openmeterio/openmeter/internal/productcatalog" "github.com/openmeterio/openmeter/pkg/clock" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" ) // Adapter implements remote connector interface as driven port. @@ -87,7 +88,7 @@ func (c *featureDBAdapter) ArchiveFeature(ctx context.Context, featureID models. return nil } -func (c *featureDBAdapter) ListFeatures(ctx context.Context, params productcatalog.ListFeaturesParams) ([]productcatalog.Feature, error) { +func (c *featureDBAdapter) ListFeatures(ctx context.Context, params productcatalog.ListFeaturesParams) (pagination.PagedResponse[productcatalog.Feature], error) { query := c.db.Feature.Query(). Where(db_feature.Namespace(params.Namespace)) @@ -99,14 +100,6 @@ func (c *featureDBAdapter) ListFeatures(ctx context.Context, params productcatal query = query.Where(db_feature.Or(db_feature.ArchivedAtIsNil(), db_feature.ArchivedAtGT(clock.Now()))) } - if params.Limit > 0 { - query = query.Limit(params.Limit) - } - - if params.Offset > 0 { - query = query.Offset(params.Offset) - } - switch params.OrderBy { case productcatalog.FeatureOrderByCreatedAt: query = query.Order(db_feature.ByCreatedAt()) @@ -116,18 +109,48 @@ func (c *featureDBAdapter) ListFeatures(ctx context.Context, params productcatal query = query.Order(db_feature.ByCreatedAt()) } - entities, err := query.All(ctx) + response := pagination.PagedResponse[productcatalog.Feature]{ + Page: params.Page, + } + + // we're using limit and offset + if params.Page.IsZero() { + if params.Limit > 0 { + query = query.Limit(params.Limit) + } + if params.Offset > 0 { + query = query.Offset(params.Offset) + } + + entities, err := query.All(ctx) + if err != nil { + return response, err + } + + mapped := make([]productcatalog.Feature, 0, len(entities)) + for _, entity := range entities { + mapped = append(mapped, mapFeatureEntity(entity)) + } + + response.Items = mapped + return response, nil + } + + paged, err := query.Paginate(ctx, params.Page) if err != nil { - return nil, fmt.Errorf("failed to list entities: %w", err) + return response, err } - list := make([]productcatalog.Feature, 0, len(entities)) - for _, entity := range entities { + list := make([]productcatalog.Feature, 0, len(paged.Items)) + for _, entity := range paged.Items { feature := mapFeatureEntity(entity) list = append(list, feature) } - return list, nil + response.Items = list + response.TotalCount = paged.TotalCount + + return response, nil } // mapFeatureEntity maps a database feature entity to a feature model. diff --git a/internal/productcatalog/postgresadapter/feature_test.go b/internal/productcatalog/postgresadapter/feature_test.go index 948cdfb3f..606cd653d 100644 --- a/internal/productcatalog/postgresadapter/feature_test.go +++ b/internal/productcatalog/postgresadapter/feature_test.go @@ -15,6 +15,7 @@ import ( "github.com/openmeterio/openmeter/internal/productcatalog/postgresadapter" "github.com/openmeterio/openmeter/internal/testutils" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" ) func TestCreateFeature(t *testing.T) { @@ -115,30 +116,36 @@ func TestCreateFeature(t *testing.T) { }) assert.NoError(t, err) - assert.Len(t, features, 2) - assert.Equal(t, "feature-3", features[0].Name) + assert.Len(t, features.Items, 2) + assert.Equal(t, "feature-3", features.Items[0].Name) features, err = connector.ListFeatures(ctx, productcatalog.ListFeaturesParams{ Namespace: namespace, - Limit: 1, + Page: pagination.Page{ + PageSize: 1, + PageNumber: 1, + }, }) assert.NoError(t, err) - assert.Len(t, features, 1) - assert.Equal(t, "feature-3", features[0].Name) + assert.Len(t, features.Items, 1) + assert.Equal(t, "feature-3", features.Items[0].Name) features, err = connector.ListFeatures(ctx, productcatalog.ListFeaturesParams{ Namespace: namespace, - Offset: 1, + Page: pagination.Page{ + PageSize: 1, + PageNumber: 2, + }, }) assert.NoError(t, err) - assert.Len(t, features, 1) - assert.Equal(t, "feature-2", features[0].Name) + assert.Len(t, features.Items, 1) + assert.Equal(t, "feature-2", features.Items[0].Name) err = connector.ArchiveFeature(ctx, models.NamespacedID{ Namespace: namespace, - ID: features[0].ID, + ID: features.Items[0].ID, }) assert.NoError(t, err) @@ -148,7 +155,7 @@ func TestCreateFeature(t *testing.T) { }) assert.NoError(t, err) - assert.Len(t, features, 2) + assert.Len(t, features.Items, 2) features, err = connector.ListFeatures(ctx, productcatalog.ListFeaturesParams{ Namespace: namespace, @@ -156,8 +163,8 @@ func TestCreateFeature(t *testing.T) { }) assert.NoError(t, err) - assert.Len(t, features, 1) - assert.Equal(t, "feature-3", features[0].Name) + assert.Len(t, features.Items, 1) + assert.Equal(t, "feature-3", features.Items[0].Name) }, }, { diff --git a/pkg/framework/commonhttp/pagination.go b/pkg/framework/commonhttp/pagination.go new file mode 100644 index 000000000..933147c63 --- /dev/null +++ b/pkg/framework/commonhttp/pagination.go @@ -0,0 +1,10 @@ +package commonhttp + +const ( + // DefaultPageSize is the default page size for pagination. + DefaultPageSize = 100 + // MaxPageSize is the maximum page size for pagination. + MaxPageSize = 1000 + // DefaultPage is the default page number for pagination. + DefaultPage = 1 +) diff --git a/pkg/framework/commonhttp/union.go b/pkg/framework/commonhttp/union.go new file mode 100644 index 000000000..f0d11c717 --- /dev/null +++ b/pkg/framework/commonhttp/union.go @@ -0,0 +1,22 @@ +package commonhttp + +import ( + "encoding/json" +) + +type Union[Primary any, Secondary any] struct { + Option1 *Primary + Option2 *Secondary +} + +// Implements json.Marshaler with primary having precedence. +func (u Union[Primary, Secondary]) MarshalJSON() ([]byte, error) { + if u.Option1 != nil { + return json.Marshal(u.Option1) + } + if u.Option2 != nil { + return json.Marshal(u.Option2) + } + // if nothing is set we return empty + return []byte{}, nil +} diff --git a/pkg/framework/entutils/paginate.tpl b/pkg/framework/entutils/paginate.tpl new file mode 100644 index 000000000..c43f5cf8f --- /dev/null +++ b/pkg/framework/entutils/paginate.tpl @@ -0,0 +1,65 @@ +{{/* + This template attaches simple type safe options to run window functions on a query. +*/}} +{{ define "paginate" }} + + +{{/* Add the base header for the generated file */}} +{{ $pkg := base $.Config.Package }} +{{ template "header" $ }} + +{{/* Loop over all nodes and implement "pagination.Paginator" for "XQuery" and "XSelect" */}} +{{ range $n := $.Nodes }} + {{ $receiver := $n.Receiver }} + // Paginate runs the query and returns a paginated response. + // If page is its 0 value then it will return all the items and populate the response page accordingly. + func ({{ $receiver }} *{{ $n.QueryName }}) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*{{ $n.Name }}], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + {{ $receiver }}.ctx.Offset = &zero + {{ $receiver }}.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := {{ $receiver }}.Clone() + pagedQuery := {{ $receiver }} + + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*{{ $n.Name }}]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err + } + + // type check + var _ pagination.Paginator[*{{ $n.Name }}] = (*{{ $n.QueryName }})(nil) +{{ end }} + +{{ end }} diff --git a/pkg/framework/entutils/paginate_test.go b/pkg/framework/entutils/paginate_test.go new file mode 100644 index 000000000..cadb84d17 --- /dev/null +++ b/pkg/framework/entutils/paginate_test.go @@ -0,0 +1,131 @@ +package entutils_test + +import ( + "context" + "fmt" + "testing" + + "entgo.io/ent/dialect/sql" + "github.com/stretchr/testify/assert" + + "github.com/openmeterio/openmeter/internal/testutils" + "github.com/openmeterio/openmeter/pkg/framework/entutils/testutils/ent1/db" + db_example "github.com/openmeterio/openmeter/pkg/framework/entutils/testutils/ent1/db/example1" + "github.com/openmeterio/openmeter/pkg/pagination" +) + +func TestPaginate(t *testing.T) { + assert := assert.New(t) + + // create isolated pg db for tests + driver := testutils.InitPostgresDB(t) + + // build db clients + dbClient := db.NewClient(db.Driver(driver)) + defer dbClient.Close() + + if err := dbClient.Schema.Create(context.Background()); err != nil { + t.Fatalf("failed to migrate database %s", err) + } + + // insert items + ctx := context.Background() + for i := 0; i < 10; i++ { + _, err := dbClient.Example1.Create(). + SetID(fmt.Sprintf("%v", i)). + SetExampleValue1(fmt.Sprintf("%v", i)). + Save(ctx) + if err != nil { + t.Fatalf("failed to insert item %d: %s", i, err) + } + } + // total + total, err := dbClient.Example1.Query().Count(ctx) + if err != nil { + t.Fatalf("failed to count: %s", err) + } + assert.Equal(10, total) + + t.Run("Should return first item", func(t *testing.T) { + paged, err := dbClient.Example1.Query().Order(db_example.ByID(sql.OrderAsc())).Paginate(ctx, pagination.Page{ + PageSize: 1, + PageNumber: 1, + }) + if err != nil { + t.Fatalf("failed to paginate: %s", err) + } + + assert.Equal(1, len(paged.Items)) + assert.Equal(10, paged.TotalCount) + assert.Equal("0", paged.Items[0].ID) + }) + + t.Run("Should respect ordering", func(t *testing.T) { + paged, err := dbClient.Example1.Query().Order(db_example.ByID(sql.OrderDesc())).Paginate(ctx, pagination.Page{ + PageSize: 1, + PageNumber: 1, + }) + if err != nil { + t.Fatalf("failed to paginate: %s", err) + } + + assert.Equal(1, len(paged.Items)) + assert.Equal(10, paged.TotalCount) + assert.Equal("9", paged.Items[0].ID) + }) + + t.Run("Should respect filtering", func(t *testing.T) { + paged, err := dbClient.Example1.Query().Where(db_example.IDContainsFold("1")).Paginate(ctx, pagination.Page{ + PageSize: 1, + PageNumber: 1, + }) + if err != nil { + t.Fatalf("failed to paginate: %s", err) + } + + assert.Equal(1, len(paged.Items)) + assert.Equal(1, paged.TotalCount) + assert.Equal("1", paged.Items[0].ID) + }) + + t.Run("Should page", func(t *testing.T) { + paged, err := dbClient.Example1.Query().Order(db_example.ByID(sql.OrderAsc())).Paginate(ctx, pagination.Page{ + PageSize: 3, + PageNumber: 2, + }) + if err != nil { + t.Fatalf("failed to paginate: %s", err) + } + + assert.Equal(3, len(paged.Items)) + assert.Equal(10, paged.TotalCount) + assert.Equal(3, paged.Page.PageSize) + assert.Equal(2, paged.Page.PageNumber) + assert.Equal("3", paged.Items[0].ID) + assert.Equal("4", paged.Items[1].ID) + assert.Equal("5", paged.Items[2].ID) + }) + + t.Run("Should return empty page", func(t *testing.T) { + paged, err := dbClient.Example1.Query().Order(db_example.ByID(sql.OrderAsc())).Paginate(ctx, pagination.Page{ + PageSize: 3, + PageNumber: 10, + }) + if err != nil { + t.Fatalf("failed to paginate: %s", err) + } + + assert.Equal(0, len(paged.Items)) + assert.Equal(10, paged.TotalCount) + }) + + t.Run("Should return all items", func(t *testing.T) { + paged, err := dbClient.Example1.Query().Order(db_example.ByID(sql.OrderAsc())).Paginate(ctx, pagination.Page{}) + if err != nil { + t.Fatalf("failed to paginate: %s", err) + } + + assert.Equal(10, len(paged.Items)) + assert.Equal(10, paged.TotalCount) + }) +} diff --git a/pkg/framework/entutils/testutils/ent1/db/paginate.go b/pkg/framework/entutils/testutils/ent1/db/paginate.go new file mode 100644 index 000000000..7d00f1726 --- /dev/null +++ b/pkg/framework/entutils/testutils/ent1/db/paginate.go @@ -0,0 +1,58 @@ +// Code generated by ent, DO NOT EDIT. + +package db + +import ( + "context" + "fmt" + + "github.com/openmeterio/openmeter/pkg/pagination" +) + +// Paginate runs the query and returns a paginated response. +// If page is its 0 value then it will return all the items and populate the response page accordingly. +func (e *Example1Query) Paginate(ctx context.Context, page pagination.Page) (pagination.PagedResponse[*Example1], error) { + // Get the limit and offset + limit, offset := page.Limit(), page.Offset() + + // Unset previous pagination settings + zero := 0 + e.ctx.Offset = &zero + e.ctx.Limit = &zero + + // Create duplicate of the query to run for + countQuery := e.Clone() + pagedQuery := e + + // Unset ordering for count query + countQuery.order = nil + + pagedResponse := pagination.PagedResponse[*Example1]{ + Page: page, + } + + // Get the total count + count, err := countQuery.Count(ctx) + if err != nil { + return pagedResponse, fmt.Errorf("failed to get count: %w", err) + } + pagedResponse.TotalCount = count + + // If page is its 0 value then return all the items + if page.IsZero() { + offset = 0 + limit = count + } + + // Set the limit and offset + pagedQuery.ctx.Limit = &limit + pagedQuery.ctx.Offset = &offset + + // Get the paged items + items, err := pagedQuery.All(ctx) + pagedResponse.Items = items + return pagedResponse, err +} + +// type check +var _ pagination.Paginator[*Example1] = (*Example1Query)(nil) diff --git a/pkg/framework/entutils/testutils/ent1/generate.go b/pkg/framework/entutils/testutils/ent1/generate.go index 5bdff4545..47726fadc 100644 --- a/pkg/framework/entutils/testutils/ent1/generate.go +++ b/pkg/framework/entutils/testutils/ent1/generate.go @@ -1,3 +1,3 @@ package ent1 -//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate --target ./db --feature sql/upsert --feature sql/lock --feature sql/versioned-migration ./schema --template ../../expose.tpl +//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate --target ./db --feature sql/upsert --feature sql/lock --feature sql/versioned-migration ./schema --template ../../expose.tpl --template ../../paginate.tpl diff --git a/pkg/pagination/pagination.go b/pkg/pagination/pagination.go new file mode 100644 index 000000000..551519fa1 --- /dev/null +++ b/pkg/pagination/pagination.go @@ -0,0 +1,47 @@ +package pagination + +import ( + "context" + "encoding/json" +) + +type Page struct { + PageSize int `json:"pageSize"` + PageNumber int `json:"page"` +} + +func (p Page) Offset() int { + return p.PageSize * (p.PageNumber - 1) +} + +func (p Page) Limit() int { + return p.PageSize +} + +func (p Page) IsZero() bool { + return p.PageSize == 0 && p.PageNumber == 0 +} + +type PagedResponse[T any] struct { + Page Page `json:"-"` + TotalCount int `json:"totalCount"` + Items []T `json:"items"` +} + +// Implement json.Marshaler interface to flatten the Page struct +func (p PagedResponse[T]) MarshalJSON() ([]byte, error) { + type Alias PagedResponse[T] + return json.Marshal(&struct { + PageSize int `json:"pageSize"` + PageNumber int `json:"page"` + *Alias + }{ + PageSize: p.Page.PageSize, + PageNumber: p.Page.PageNumber, + Alias: (*Alias)(&p), + }) +} + +type Paginator[T any] interface { + Paginate(ctx context.Context, page Page) (PagedResponse[T], error) +} diff --git a/pkg/pagination/pagination_test.go b/pkg/pagination/pagination_test.go new file mode 100644 index 000000000..e986bd785 --- /dev/null +++ b/pkg/pagination/pagination_test.go @@ -0,0 +1,38 @@ +package pagination_test + +import ( + "bytes" + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/openmeterio/openmeter/pkg/pagination" +) + +func TestShouldFlattenPageInfoWhenMarshalling(t *testing.T) { + assert := assert.New(t) + pagedRes := pagination.PagedResponse[int]{ + Items: []int{1, 2, 3}, + TotalCount: 3, + Page: pagination.Page{ + PageSize: 10, + PageNumber: 1, + }, + } + + expected := `{"pageSize":10,"page":1,"totalCount":3,"items":[1,2,3]} +` + + buf := &bytes.Buffer{} + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(true) + + if err := enc.Encode(pagedRes); err != nil { + t.Fatalf("failed to marshal paged response: %v", err) + } + + assert.JSONEq(expected, buf.String()) + // enforces ordering + assert.Equal(expected, buf.String()) +} diff --git a/test/entitlement/regression/scenario_test.go b/test/entitlement/regression/scenario_test.go index a079d1bd0..5408ced60 100644 --- a/test/entitlement/regression/scenario_test.go +++ b/test/entitlement/regression/scenario_test.go @@ -14,6 +14,7 @@ import ( "github.com/openmeterio/openmeter/pkg/clock" "github.com/openmeterio/openmeter/pkg/convert" "github.com/openmeterio/openmeter/pkg/models" + "github.com/openmeterio/openmeter/pkg/pagination" "github.com/openmeterio/openmeter/pkg/recurrence" ) @@ -319,14 +320,16 @@ func TestBalanceCalculationsAfterVoiding(t *testing.T) { grants, err := deps.GrantConnector.ListGrants(ctx, credit.ListGrantsParams{ Namespace: "namespace-1", IncludeDeleted: true, - Offset: 0, - Limit: 100, - OrderBy: credit.GrantOrderByCreatedAt, + Page: pagination.Page{ + PageSize: 100, + PageNumber: 1, + }, + OrderBy: credit.GrantOrderByCreatedAt, }) assert.NoError(err) - assert.Len(grants, 1) + assert.Len(grants.Items, 1) - grant1 := &grants[0] + grant1 := &grants.Items[0] // Let's create another grant clock.SetTime(testutils.GetRFC3339Time(t, "2024-07-09T12:09:40Z"))