| package meter |
|
|
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "slices" |
| "time" |
|
|
| "github.com/openmeterio/openmeter/pkg/filter" |
| "github.com/openmeterio/openmeter/pkg/models" |
| "github.com/openmeterio/openmeter/pkg/pagination" |
| "github.com/openmeterio/openmeter/pkg/sortx" |
| ) |
|
|
| |
| |
| const maxListMeterFilterDepth = 2 |
|
|
| |
| type Service interface { |
| ListMeters(ctx context.Context, params ListMetersParams) (pagination.Result[Meter], error) |
| GetMeterByIDOrSlug(ctx context.Context, input GetMeterInput) (Meter, error) |
| } |
|
|
| |
| type ManageService interface { |
| Service |
|
|
| CreateMeter(ctx context.Context, input CreateMeterInput) (Meter, error) |
| UpdateMeter(ctx context.Context, input UpdateMeterInput) (Meter, error) |
| DeleteMeter(ctx context.Context, input DeleteMeterInput) error |
|
|
| |
| |
| RegisterPreUpdateMeterHook(hook PreUpdateMeterHook) error |
| } |
|
|
| |
| type PreUpdateMeterHook = func(context.Context, UpdateMeterInput) error |
|
|
| |
| type GetMeterInput struct { |
| Namespace string |
| IDOrSlug string |
| } |
|
|
| |
| func (i GetMeterInput) Validate() error { |
| var errs []error |
|
|
| if i.Namespace == "" { |
| errs = append(errs, errors.New("namespace is required")) |
| } |
|
|
| if i.IDOrSlug == "" { |
| errs = append(errs, errors.New("id or slug is required")) |
| } |
|
|
| return errors.Join(errs...) |
| } |
|
|
| |
| type ListMetersParams struct { |
| pagination.Page |
|
|
| OrderBy OrderBy |
| Order sortx.Order |
|
|
| Namespace string |
|
|
| |
| Key *filter.FilterString `json:"key,omitempty"` |
| Name *filter.FilterString `json:"name,omitempty"` |
|
|
| IDFilter *[]string |
|
|
| |
| |
| |
| WithoutNamespace bool |
|
|
| |
| IncludeDeleted bool |
|
|
| |
| EventTypes *[]string |
| } |
|
|
| |
| func (p ListMetersParams) Validate() error { |
| var errs []error |
|
|
| if p.Namespace == "" && !p.WithoutNamespace { |
| errs = append(errs, errors.New("namespace is required")) |
| } |
|
|
| if p.OrderBy != "" && !slices.Contains(OrderBy("").Values(), p.OrderBy) { |
| errs = append(errs, fmt.Errorf("invalid order by: %s", p.OrderBy)) |
| } |
|
|
| if p.Order != sortx.OrderNone && (p.Order != sortx.OrderAsc && p.Order != sortx.OrderDesc) { |
| errs = append(errs, fmt.Errorf("invalid order: %s", p.Order)) |
| } |
|
|
| if p.Key != nil { |
| if err := p.Key.ValidateWithComplexity(maxListMeterFilterDepth); err != nil { |
| errs = append(errs, fmt.Errorf("invalid key filter: %w", err)) |
| } |
| } |
|
|
| if p.Name != nil { |
| if err := p.Name.ValidateWithComplexity(maxListMeterFilterDepth); err != nil { |
| errs = append(errs, fmt.Errorf("invalid name filter: %w", err)) |
| } |
| } |
|
|
| if p.IDFilter != nil { |
| for _, id := range *p.IDFilter { |
| if id == "" { |
| errs = append(errs, errors.New("id filter must not contain empty string")) |
| } |
| } |
| } |
|
|
| if p.EventTypes != nil { |
| for _, eventType := range *p.EventTypes { |
| if eventType == "" { |
| errs = append(errs, errors.New("event type filter must not contain empty string")) |
| } |
| } |
| } |
|
|
| return errors.Join(errs...) |
| } |
|
|
| type inputOptions struct { |
| AllowReservedEventTypes bool |
| } |
|
|
| var ( |
| _ models.Validator = (*CreateMeterInput)(nil) |
| _ models.CustomValidator[CreateMeterInput] = (*CreateMeterInput)(nil) |
| ) |
|
|
| |
| type CreateMeterInput struct { |
| Namespace string |
| Name string |
| Key string |
| Description *string |
| Aggregation MeterAggregation |
| EventType string |
| EventFrom *time.Time |
| ValueProperty *string |
| GroupBy map[string]string |
| Metadata models.Metadata |
| Annotations models.Annotations |
|
|
| inputOptions |
| } |
|
|
| func (i CreateMeterInput) ValidateWith(validators ...models.ValidatorFunc[CreateMeterInput]) error { |
| return models.Validate(i, validators...) |
| } |
|
|
| |
| func (i CreateMeterInput) Validate() error { |
| var errs []error |
|
|
| if i.Namespace == "" { |
| errs = append(errs, errors.New("namespace is required")) |
| } |
|
|
| if i.Name == "" { |
| errs = append(errs, errors.New("name is required")) |
| } |
|
|
| if i.Key == "" { |
| errs = append(errs, errors.New("key is required")) |
| } |
|
|
| if i.Description != nil && *i.Description == "" { |
| errs = append(errs, errors.New("description must not be empty string")) |
| } |
|
|
| if i.Aggregation == "" { |
| errs = append(errs, errors.New("meter aggregation is required")) |
| } |
|
|
| if i.EventType == "" { |
| errs = append(errs, errors.New("meter event type is required")) |
| } |
|
|
| if i.EventFrom != nil && i.EventFrom.IsZero() { |
| errs = append(errs, errors.New("meter event from must not be zero")) |
| } |
|
|
| |
| if err := validateMeterAggregation(i.ValueProperty, i.Aggregation); err != nil { |
| errs = append(errs, fmt.Errorf("invalid meter aggregation: %w", err)) |
| } |
|
|
| |
| if err := validateMeterGroupBy(i.ValueProperty, i.GroupBy); err != nil { |
| errs = append(errs, fmt.Errorf("invalid meter group by: %w", err)) |
| } |
|
|
| return models.NewNillableGenericValidationError(errors.Join(errs...)) |
| } |
|
|
| |
| type UpdateMeterInput struct { |
| ID models.NamespacedID |
| Name string |
| Description *string |
| GroupBy map[string]string |
| Metadata models.Metadata |
| Annotations *models.Annotations |
|
|
| inputOptions |
| } |
|
|
| |
| func (i UpdateMeterInput) Validate(valueProperty *string) error { |
| var errs []error |
|
|
| if err := i.ID.Validate(); err != nil { |
| errs = append(errs, fmt.Errorf("invalid meter id: %w", err)) |
| } |
|
|
| if i.Name == "" { |
| errs = append(errs, errors.New("name is required")) |
| } |
|
|
| if i.Description != nil && *i.Description == "" { |
| errs = append(errs, errors.New("description must not be empty string")) |
| } |
|
|
| err := validateMeterGroupBy(valueProperty, i.GroupBy) |
| if err != nil { |
| errs = append(errs, err) |
| } |
|
|
| return errors.Join(errs...) |
| } |
|
|
| |
| type DeleteMeterInput struct { |
| Namespace string |
| IDOrSlug string |
|
|
| inputOptions |
| } |
|
|
| |
| func (i DeleteMeterInput) Validate() error { |
| var errs []error |
|
|
| if i.Namespace == "" { |
| errs = append(errs, errors.New("namespace is required")) |
| } |
|
|
| if i.IDOrSlug == "" { |
| errs = append(errs, errors.New("id or slug is required")) |
| } |
|
|
| return errors.Join(errs...) |
| } |
|
|