openmeter / subscription /apply.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 6)
d6f631f verified
Raw
History Blame Contribute Delete
2.48 kB
package subscription
import (
"fmt"
"time"
"github.com/samber/lo"
"github.com/openmeterio/openmeter/pkg/models"
)
// The spec is the core object of Subscriptions being manipulated.
// Different resources like Patches, Addons, etc... can apply themselves to the spec.
type ApplyContext struct {
CurrentTime time.Time
}
// Things can apply themselves to the spec
type AppliesToSpec interface {
// This method should only ever be invoked by SubscriptionSpec (spec.ApplyX), so subsequent validations and logic are always guaranteed to run
// FIXME(galexi): this can be enforced by making it private, but that will require rewriting all patches & addons
ApplyTo(spec *SubscriptionSpec, actx ApplyContext) error
}
const (
// Some errors are allowed during applying individual things to the spec, but still mean the Spec as a whole is invalid
subscriptionPatchErrAttrNameAllowedDuringApplyingToSpecError = "allowed_during_applying_to_spec_error"
)
func AllowedDuringApplyingToSpecError() models.ValidationIssueOption {
return models.WithAttribute(subscriptionPatchErrAttrNameAllowedDuringApplyingToSpecError, true)
}
func NewAppliesToSpec(fn func(spec *SubscriptionSpec, actx ApplyContext) error) AppliesToSpec {
return &someAppliesToSpec{
Fn: fn,
}
}
var _ AppliesToSpec = &someAppliesToSpec{}
type someAppliesToSpec struct {
Fn func(spec *SubscriptionSpec, actx ApplyContext) error
}
func (s *someAppliesToSpec) ApplyTo(spec *SubscriptionSpec, actx ApplyContext) error {
return s.Fn(spec, actx)
}
// NewAggregateAppliesToSpec aggregates multiple applies to spec into a single applies to spec, and also validates the spec after applying all the patches
func NewAggregateAppliesToSpec(applieses []AppliesToSpec) AppliesToSpec {
return NewAppliesToSpec(func(spec *SubscriptionSpec, actx ApplyContext) error {
for i, applies := range applieses {
if err := spec.Apply(applies, actx); err != nil {
wrapError := func(err error) error {
return models.ErrorWithComponent(models.ComponentName(fmt.Sprintf("patch at idx %d", i)), err)
}
issues, err := models.AsValidationIssues(err)
if err != nil {
return wrapError(err)
}
if lo.EveryBy(issues, func(issue models.ValidationIssue) bool {
return IsValidationIssueWithBoolAttr(issue, subscriptionPatchErrAttrNameAllowedDuringApplyingToSpecError)
}) {
continue
}
// Otherwise we return with the error
return wrapError(err)
}
}
return nil
})
}