File size: 2,558 Bytes
d6f631f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package streaming

import (
	"errors"
	"slices"
	"time"

	"github.com/samber/lo"

	"github.com/openmeterio/openmeter/openmeter/meter"
	"github.com/openmeterio/openmeter/pkg/filter"
	"github.com/openmeterio/openmeter/pkg/models"
)

type QueryParams struct {
	ClientID       *string
	From           *time.Time
	To             *time.Time
	FilterCustomer []Customer
	FilterSubject  []string
	FilterGroupBy  map[string]filter.FilterString
	FilterStoredAt *filter.FilterTimeUnix
	GroupBy        []string
	WindowSize     *meter.WindowSize
	WindowTimeZone *time.Location
}

// Validate validates query params focusing on `from` and `to` being aligned with query and meter window sizes
func (p *QueryParams) Validate() error {
	var errs []error

	// If provided, cannot be an empty string
	if p.ClientID != nil && len(*p.ClientID) == 0 {
		errs = append(errs, errors.New("client id cannot be empty"))
	}

	// Check that from and to are consistent
	if p.From != nil && p.To != nil {
		if p.From.Equal(*p.To) {
			errs = append(errs, errors.New("from and to cannot be equal"))
		}

		if p.From.After(*p.To) {
			errs = append(errs, errors.New("from must be before to"))
		}
	}

	// This is required because otherwise the response would be ambiguous
	if len(p.FilterSubject) > 1 && !slices.Contains(p.GroupBy, "subject") {
		errs = append(errs, errors.New("multiple subject filters are only allowed with subject group by"))
	}

	// This is required because otherwise the response would be ambiguous
	if len(p.FilterCustomer) > 1 && !slices.Contains(p.GroupBy, "customer_id") {
		errs = append(errs, errors.New("multiple customer filters are only allowed with customer_id group by"))
	}

	// This is required for now because we don't support customer_id without a filter
	// To support this we need to map all subjects to customer_ids
	if slices.Contains(p.GroupBy, "customer_id") && len(p.FilterCustomer) == 0 {
		errs = append(errs, errors.New("customer filter is required with customer_id group by"))
	}

	if err := errors.Join(lo.Map(p.FilterCustomer, func(c Customer, _ int) error {
		return c.GetUsageAttribution().Validate()
	})...); err != nil {
		errs = append(errs, err)
	}

	// Validate the group by filters
	for _, filter := range p.FilterGroupBy {
		if err := filter.Validate(); err != nil {
			errs = append(errs, err)
		}
	}

	if p.FilterStoredAt != nil {
		if err := p.FilterStoredAt.Validate(); err != nil {
			errs = append(errs, err)
		}
	}

	if len(errs) > 0 {
		return models.NewNillableGenericValidationError(errors.Join(errs...))
	}

	return nil
}