package models import ( "errors" "fmt" "time" "github.com/openmeterio/openmeter/pkg/clock" "github.com/openmeterio/openmeter/pkg/equal" ) type ManagedUniqueResource struct { NamespacedModel `json:",inline" mapstructure:",squash"` ManagedModel `json:",inline" mapstructure:",squash"` // ID is the unique identifier for Resource. ID string `json:"id"` // Key is the unique key for Resource. Key string `json:"key"` } type ManagedResource struct { NamespacedModel `json:",inline" mapstructure:",squash"` ManagedModel `json:",inline" mapstructure:",squash"` // ID is the unique identifier for Resource. ID string `json:"id"` Description *string `json:"description,omitempty"` Name string `json:"name"` } func (m ManagedResource) GetID() string { return m.ID } func (m ManagedResource) GetDescription() *string { return m.Description } func (m ManagedResource) GetName() string { return m.Name } type ManagedResourceInput struct { ID string Namespace string CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time Name string Description *string } func (r ManagedResourceInput) Validate() error { if r.ID == "" { return errors.New("id is required") } if r.Namespace == "" { return errors.New("namespace is required") } if r.CreatedAt.IsZero() { return errors.New("created at is required") } if r.UpdatedAt.IsZero() { return errors.New("updated at is required") } return nil } func NewManagedResource(input ManagedResourceInput) ManagedResource { return ManagedResource{ ID: input.ID, NamespacedModel: NamespacedModel{ Namespace: input.Namespace, }, ManagedModel: ManagedModel{ CreatedAt: input.CreatedAt.UTC(), UpdatedAt: input.UpdatedAt.UTC(), DeletedAt: func() *time.Time { if input.DeletedAt == nil { return nil } deletedAt := input.DeletedAt.UTC() return &deletedAt }(), }, Name: input.Name, Description: input.Description, } } func (r ManagedResource) Validate() error { if err := r.NamespacedModel.Validate(); err != nil { return fmt.Errorf("error validating namespaced model: %w", err) } if err := r.ManagedModel.Validate(); err != nil { return fmt.Errorf("error validating managed model: %w", err) } if r.ID == "" { return errors.New("id is required") } if r.Name == "" { return errors.New("name is required") } return nil } type ManagedModel struct { CreatedAt time.Time `json:"createdAt"` // After creation the entity is considered updated. UpdatedAt time.Time `json:"updatedAt"` // Time of soft delete. If not null, the entity is considered deleted. DeletedAt *time.Time `json:"deletedAt,omitempty"` } func (m ManagedModel) Validate() error { if m.CreatedAt.IsZero() { return errors.New("created at is required") } if m.UpdatedAt.IsZero() { return errors.New("updated at is required") } return nil } func (m ManagedModel) IsDeleted() bool { return m.IsDeletedAt(clock.Now()) } func (m ManagedModel) IsDeletedAt(t time.Time) bool { if m.DeletedAt == nil { return false } return !m.DeletedAt.After(t) } func (m ManagedModel) Equal(other ManagedModel) bool { if !m.CreatedAt.Equal(other.CreatedAt) { return false } if !m.UpdatedAt.Equal(other.UpdatedAt) { return false } if !equal.PtrEqual(m.DeletedAt, other.DeletedAt) { return false } return true } func (m ManagedModel) GetCreatedAt() time.Time { return m.CreatedAt } func (m ManagedModel) GetUpdatedAt() time.Time { return m.UpdatedAt } func (m ManagedModel) GetDeletedAt() *time.Time { return m.DeletedAt } type ManagedModelWithID struct { ManagedModel `json:",inline" mapstructure:",squash"` ID string `json:"id"` } func (m ManagedModelWithID) GetID() string { return m.ID } func (m ManagedModelWithID) Equal(other ManagedModelWithID) bool { if m.ID != other.ID { return false } return m.ManagedModel.Equal(other.ManagedModel) } func (m ManagedModelWithID) Validate() error { if m.ID == "" { return errors.New("id is required") } return nil } type NamespacedModel struct { Namespace string `json:"namespace"` } func (m NamespacedModel) Validate() error { if m.Namespace == "" { return errors.New("namespace is required") } return nil } func (m NamespacedModel) GetNamespace() string { return m.Namespace } type Address struct { Country *CountryCode `json:"country,omitempty"` PostalCode *string `json:"postalCode,omitempty"` State *string `json:"state,omitempty"` City *string `json:"city,omitempty"` Line1 *string `json:"line1,omitempty"` Line2 *string `json:"line2,omitempty"` PhoneNumber *string `json:"phoneNumber,omitempty"` } // [ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) alpha-2 country code. type CountryCode string // VersionedModel represents a versionable entity. With each new version the sequence is incremented // while the key remains the same. Key + Version uniquely identifies an entity. type VersionedModel struct { // Key is the unique identifier of the entity across its versions. // Might be generated by the system or provided by the user. Key string `json:"key,omitempty"` // Version is the integer sequential version of the entity, starting from 1. Version int `json:"version,omitempty"` }