| package ledger |
|
|
| import ( |
| "fmt" |
| "time" |
|
|
| "github.com/samber/mo" |
|
|
| "github.com/openmeterio/openmeter/pkg/models" |
| "github.com/openmeterio/openmeter/pkg/pagination/v2" |
| "github.com/openmeterio/openmeter/pkg/timeutil" |
| ) |
|
|
| type Query struct { |
| Namespace string |
|
|
| Cursor *pagination.Cursor |
|
|
| Filters Filters |
| } |
|
|
| func (p Query) Validate() error { |
| if p.Namespace == "" { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "namespace_required", |
| "namespace": p.Namespace, |
| }) |
| } |
|
|
| if p.Cursor != nil { |
| if err := p.Cursor.Validate(); err != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "cursor_invalid", |
| "cursor": p.Cursor, |
| "error": err, |
| }) |
| } |
| } |
|
|
| if p.Filters.TransactionID != nil && *p.Filters.TransactionID == "" { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "transaction_id_required", |
| "transaction_id": *p.Filters.TransactionID, |
| }) |
| } |
|
|
| if p.Filters.AccountID != nil && *p.Filters.AccountID == "" { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "account_id_required", |
| "account_id": *p.Filters.AccountID, |
| }) |
| } |
|
|
| if err := validateOptionalChargeIDFilter("source_charge_id", p.Filters.SourceChargeID); err != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "source_charge_id_invalid", |
| "error": err, |
| }) |
| } |
|
|
| if err := validateOptionalChargeIDFilter("spend_charge_id", p.Filters.SpendChargeID); err != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "spend_charge_id_invalid", |
| "error": err, |
| }) |
| } |
|
|
| if p.Filters.BookedAtPeriod != nil { |
| if err := p.Filters.BookedAtPeriod.Validate(); err != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "booked_at_period_invalid", |
| "booked_at_period": p.Filters.BookedAtPeriod, |
| "error": err, |
| }) |
| } |
| } |
|
|
| if p.Filters.After != nil { |
| if err := p.Filters.After.Validate(); err != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "after_invalid", |
| "after": p.Filters.After, |
| "error": err, |
| }) |
| } |
| } |
|
|
| if p.Filters.AsOf != nil && p.Filters.AsOf.IsZero() { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "as_of_invalid", |
| "as_of": p.Filters.AsOf, |
| "error": fmt.Errorf("as_of must not be zero"), |
| }) |
| } |
|
|
| if p.Filters.After != nil && p.Filters.AsOf != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "after_as_of_both_set", |
| }) |
| } |
|
|
| if _, err := p.Filters.Route.Normalize(); err != nil { |
| return ErrLedgerQueryInvalid.WithAttrs(models.Attributes{ |
| "reason": "route_invalid", |
| "route": p.Filters.Route, |
| "error": err, |
| }) |
| } |
|
|
| return nil |
| } |
|
|
| type Filters struct { |
| |
| BookedAtPeriod *timeutil.OpenPeriod |
| After *TransactionCursor |
| AsOf *time.Time |
| TransactionID *string |
| |
| AccountID *string |
| |
| |
| SourceChargeID mo.Option[*string] |
| |
| |
| SpendChargeID mo.Option[*string] |
| |
| |
| Route RouteFilter |
| } |
|
|
| func validateOptionalChargeIDFilter(name string, filter mo.Option[*string]) error { |
| if filter.IsAbsent() { |
| return nil |
| } |
|
|
| value, _ := filter.Get() |
| if value != nil && *value == "" { |
| return fmt.Errorf("%s must not be empty", name) |
| } |
|
|
| return nil |
| } |
|
|