Skip to content

Commit

Permalink
Merge pull request #1841 from openmeterio/feat/plan-api-impl
Browse files Browse the repository at this point in the history
refactor: JSON serialization
  • Loading branch information
chrisgacsal authored Nov 13, 2024
2 parents 63ec6ef + c955858 commit f542d27
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 272 deletions.
6 changes: 3 additions & 3 deletions openmeter/billing/httpdriver/invoiceline.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ func mapFlatPriceToAPI(p plan.FlatPrice) (api.RateCardUsageBasedPrice, error) {
err := out.FromFlatPriceWithPaymentTerm(api.FlatPriceWithPaymentTerm{
Amount: p.Amount.String(),
PaymentTerm: lo.ToPtr(api.PricePaymentTerm(p.PaymentTerm)),
Type: api.FlatPriceWithPaymentTermType(p.Type),
Type: api.FlatPriceWithPaymentTermType(plan.FlatPriceType),
})
if err != nil {
return api.RateCardUsageBasedPrice{}, fmt.Errorf("failed to map flat price: %w", err)
Expand All @@ -366,7 +366,7 @@ func mapUnitPriceToAPI(p plan.UnitPrice) (api.RateCardUsageBasedPrice, error) {
Amount: p.Amount.String(),
MaximumAmount: decimalPtrToStringPtr(p.MaximumAmount),
MinimumAmount: decimalPtrToStringPtr(p.MinimumAmount),
Type: api.UnitPriceWithCommitmentsType(p.Type),
Type: api.UnitPriceWithCommitmentsType(plan.UnitPriceType),
})
if err != nil {
return api.RateCardUsageBasedPrice{}, fmt.Errorf("failed to map unit price: %w", err)
Expand Down Expand Up @@ -404,7 +404,7 @@ func mapTieredPriceToAPI(p plan.TieredPrice) (api.RateCardUsageBasedPrice, error
Mode: api.TieredPriceMode(p.Mode),
MinimumAmount: decimalPtrToStringPtr(p.MinimumAmount),
MaximumAmount: decimalPtrToStringPtr(p.MaximumAmount),
Type: api.TieredPriceWithCommitmentsType(p.Type),
Type: api.TieredPriceWithCommitmentsType(plan.TieredPriceType),
})
if err != nil {
return api.RateCardUsageBasedPrice{}, fmt.Errorf("failed to map tiered price: %w", err)
Expand Down
12 changes: 0 additions & 12 deletions openmeter/productcatalog/plan/adapter/adapter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ var planV1Input = plan.CreatePlanInput{
Namespace: namespace,
},
Key: "trial-ratecard-1",
Type: plan.FlatFeeRateCardType,
Name: "Trial RateCard 1",
Description: lo.ToPtr("Trial RateCard 1"),
Metadata: map[string]string{"name": "trial-ratecard-1"},
Expand All @@ -66,9 +65,6 @@ var planV1Input = plan.CreatePlanInput{
},
BillingCadence: &MonthPeriod,
Price: plan.NewPriceFrom(plan.FlatPrice{
PriceMeta: plan.PriceMeta{
Type: plan.FlatPriceType,
},
Amount: decimal.NewFromInt(0),
PaymentTerm: plan.InArrearsPaymentTerm,
}),
Expand All @@ -91,7 +87,6 @@ var planV1Input = plan.CreatePlanInput{
Namespace: namespace,
},
Key: "pro-ratecard-1",
Type: plan.UsageBasedRateCardType,
Name: "Pro RateCard 1",
Description: lo.ToPtr("Pro RateCard 1"),
Metadata: map[string]string{"name": "pro-ratecard-1"},
Expand All @@ -105,9 +100,6 @@ var planV1Input = plan.CreatePlanInput{
},
BillingCadence: MonthPeriod,
Price: lo.ToPtr(plan.NewPriceFrom(plan.TieredPrice{
PriceMeta: plan.PriceMeta{
Type: plan.TieredPriceType,
},
Mode: plan.VolumeTieredPrice,
Tiers: []plan.PriceTier{
{
Expand Down Expand Up @@ -336,7 +328,6 @@ func TestPostgresAdapter(t *testing.T) {
Namespace: namespace,
},
Key: "team-ratecard-1",
Type: plan.UsageBasedRateCardType,
Name: "Team RateCard 1",
Description: lo.ToPtr("Team RateCard 1"),
Metadata: map[string]string{"name": "team-ratecard-1"},
Expand All @@ -350,9 +341,6 @@ func TestPostgresAdapter(t *testing.T) {
},
BillingCadence: MonthPeriod,
Price: lo.ToPtr(plan.NewPriceFrom(plan.TieredPrice{
PriceMeta: plan.PriceMeta{
Type: plan.TieredPriceType,
},
Mode: plan.VolumeTieredPrice,
Tiers: []plan.PriceTier{
{
Expand Down
1 change: 0 additions & 1 deletion openmeter/productcatalog/plan/adapter/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ func fromPlanRateCardRow(r entdb.PlanRateCard) (*plan.RateCard, error) {
DeletedAt: r.DeletedAt,
},
Key: r.Key,
Type: r.Type,
Name: r.Name,
Description: r.Description,
Metadata: r.Metadata,
Expand Down
1 change: 0 additions & 1 deletion openmeter/productcatalog/plan/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ func AssertRateCardEqual(t *testing.T, r1, r2 RateCard) {
require.NoErrorf(t, err, "AsMeta must not fail")

assert.Equalf(t, m1.Key, m2.Key, "key mismatch")
assert.Equalf(t, m1.Type, m2.Type, "type mismatch")
assert.Equalf(t, m1.Name, m2.Name, "name mismatch")
assert.Equalf(t, lo.FromPtrOr(m1.Description, ""), lo.FromPtrOr(m2.Description, ""), "description mismatch")
assert.Equalf(t, lo.FromPtrOr(m1.Description, ""), lo.FromPtrOr(m2.Description, ""), "description mismatch")
Expand Down
64 changes: 35 additions & 29 deletions openmeter/productcatalog/plan/entitlement.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,64 +36,81 @@ type EntitlementTemplate struct {
func (e *EntitlementTemplate) MarshalJSON() ([]byte, error) {
var b []byte
var err error
var serde interface{}

switch e.t {
case entitlement.EntitlementTypeMetered:
b, err = json.Marshal(e.metered)
if err != nil {
return nil, fmt.Errorf("failed to json marshal metered entitlement: %w", err)
serde = struct {
Type entitlement.EntitlementType `json:"type"`
*MeteredEntitlementTemplate
}{
Type: entitlement.EntitlementTypeMetered,
MeteredEntitlementTemplate: e.metered,
}
case entitlement.EntitlementTypeStatic:
b, err = json.Marshal(e.static)
if err != nil {
return nil, fmt.Errorf("failed to json marshal metered entitlement: %w", err)
serde = struct {
Type entitlement.EntitlementType `json:"type"`
*StaticEntitlementTemplate
}{
Type: entitlement.EntitlementTypeStatic,
StaticEntitlementTemplate: e.static,
}
case entitlement.EntitlementTypeBoolean:
b, err = json.Marshal(e.boolean)
if err != nil {
return nil, fmt.Errorf("failed to json marshal metered entitlement: %w", err)
serde = struct {
Type entitlement.EntitlementType `json:"type"`
*BooleanEntitlementTemplate
}{
Type: entitlement.EntitlementTypeBoolean,
BooleanEntitlementTemplate: e.boolean,
}
default:
return nil, fmt.Errorf("invalid entitlement type: %s", e.t)
return nil, fmt.Errorf("invalid Entitlement type: %s", e.t)
}

b, err = json.Marshal(serde)
if err != nil {
return nil, fmt.Errorf("failed to JSON serialize EntitlementTemplate: %w", err)
}

return b, nil
}

func (e *EntitlementTemplate) UnmarshalJSON(bytes []byte) error {
meta := &EntitlementTemplateMeta{}
serde := struct {
Type entitlement.EntitlementType `json:"type"`
}{}

if err := json.Unmarshal(bytes, meta); err != nil {
return fmt.Errorf("failed to json unmarshal entitlement template type: %w", err)
if err := json.Unmarshal(bytes, &serde); err != nil {
return fmt.Errorf("failed to JSON deserialize EntitlementTemplate type: %w", err)
}

switch meta.Type {
switch serde.Type {
case entitlement.EntitlementTypeMetered:
v := &MeteredEntitlementTemplate{}
if err := json.Unmarshal(bytes, v); err != nil {
return fmt.Errorf("failed to json unmarshal metered entitlement template: %w", err)
return fmt.Errorf("failed to JSON deserialize EntitlementTemplate: %w", err)
}

e.metered = v
e.t = entitlement.EntitlementTypeMetered
case entitlement.EntitlementTypeStatic:
v := &StaticEntitlementTemplate{}
if err := json.Unmarshal(bytes, v); err != nil {
return fmt.Errorf("failed to json unmarshal metered entitlement template: %w", err)
return fmt.Errorf("failed to JSON deserialize EntitlementTemplate: %w", err)
}

e.static = v
e.t = entitlement.EntitlementTypeStatic
case entitlement.EntitlementTypeBoolean:
v := &BooleanEntitlementTemplate{}
if err := json.Unmarshal(bytes, v); err != nil {
return fmt.Errorf("failed to json unmarshal boolean entitlement template: %w", err)
return fmt.Errorf("failed to JSON deserialize EntitlementTemplate: %w", err)
}

e.boolean = v
e.t = entitlement.EntitlementTypeBoolean
default:
return fmt.Errorf("invalid entitlement type: %s", meta.Type)
return fmt.Errorf("invalid EntitlementTemplate type: %s", serde.Type)
}

return nil
Expand Down Expand Up @@ -177,14 +194,7 @@ func NewEntitlementTemplateFrom[T MeteredEntitlementTemplate | StaticEntitlement
return *r
}

type EntitlementTemplateMeta struct {
// Type defines the type of the entitlement.Entitlement.
Type entitlement.EntitlementType `json:"type"`
}

type MeteredEntitlementTemplate struct {
EntitlementTemplateMeta

// Metadata a set of key/value pairs describing metadata for the RateCard.
Metadata map[string]string `json:"metadata,omitempty"`

Expand Down Expand Up @@ -215,8 +225,6 @@ func (t MeteredEntitlementTemplate) Validate() error {
}

type StaticEntitlementTemplate struct {
EntitlementTemplateMeta

// Metadata a set of key/value pairs describing metadata for the RateCard.
Metadata map[string]string `json:"metadata,omitempty"`

Expand All @@ -237,8 +245,6 @@ func (t StaticEntitlementTemplate) Validate() error {
}

type BooleanEntitlementTemplate struct {
EntitlementTemplateMeta

// Metadata a set of key/value pairs describing metadata for the RateCard.
Metadata map[string]string `json:"metadata,omitempty"`
}
Expand Down
66 changes: 66 additions & 0 deletions openmeter/productcatalog/plan/entitlement_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package plan

import (
"testing"

json "github.com/json-iterator/go"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/openmeterio/openmeter/pkg/datex"
)

func TestEntitlementTemplate_JSON(t *testing.T) {
tests := []struct {
Name string
EntitlementTemplate EntitlementTemplate
ExpectedError bool
}{
{
Name: "Metered",
EntitlementTemplate: NewEntitlementTemplateFrom(MeteredEntitlementTemplate{
Metadata: map[string]string{
"key": "value",
},
IsSoftLimit: true,
IssueAfterReset: lo.ToPtr(500.0),
IssueAfterResetPriority: lo.ToPtr[uint8](1),
PreserveOverageAtReset: lo.ToPtr(true),
UsagePeriod: datex.MustParse(t, "P1M"),
}),
},
{
Name: "Static",
EntitlementTemplate: NewEntitlementTemplateFrom(StaticEntitlementTemplate{
Metadata: map[string]string{
"key": "value",
},
Config: []byte(`{"key":"value"}`),
}),
},
{
Name: "Boolean",
EntitlementTemplate: NewEntitlementTemplateFrom(BooleanEntitlementTemplate{
Metadata: map[string]string{
"key": "value",
},
}),
},
}

for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
b, err := json.Marshal(&test.EntitlementTemplate)
require.NoError(t, err)

t.Logf("Serialized EntitlementTemplate: %s", string(b))

d := EntitlementTemplate{}
err = json.Unmarshal(b, &d)
require.NoError(t, err)

assert.Equal(t, test.EntitlementTemplate, d)
})
}
}
29 changes: 2 additions & 27 deletions openmeter/productcatalog/plan/httpdriver/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,6 @@ func AsFlatFeeRateCard(flat api.RateCardFlatFee, namespace string) (plan.FlatFee
DeletedAt: flat.DeletedAt,
},
Key: flat.Key,
Type: plan.FlatFeeRateCardType,
Name: flat.Name,
Description: flat.Description,
Metadata: lo.FromPtrOr(flat.Metadata, nil),
Expand Down Expand Up @@ -454,9 +453,6 @@ func AsFlatFeeRateCard(flat api.RateCardFlatFee, namespace string) (plan.FlatFee
}

flatPrice := plan.FlatPrice{
PriceMeta: plan.PriceMeta{
Type: plan.FlatPriceType,
},
Amount: amount,
PaymentTerm: paymentTerm,
}
Expand All @@ -479,7 +475,6 @@ func AsUsageBasedRateCard(usage api.RateCardUsageBased, namespace string) (plan.
DeletedAt: usage.DeletedAt,
},
Key: usage.Key,
Type: plan.UsageBasedRateCardType,
Name: usage.Name,
Description: usage.Description,
Metadata: lo.FromPtrOr(usage.Metadata, nil),
Expand Down Expand Up @@ -538,11 +533,7 @@ func AsPrice(p api.RateCardUsageBasedPrice) (plan.Price, error) {
return price, fmt.Errorf("failed to cast FlatPrice: %w", err)
}

flatPrice := plan.FlatPrice{
PriceMeta: plan.PriceMeta{
Type: plan.FlatPriceType,
},
}
flatPrice := plan.FlatPrice{}

flatPrice.Amount, err = decimal.NewFromString(flat.Amount)
if err != nil {
Expand All @@ -567,11 +558,7 @@ func AsPrice(p api.RateCardUsageBasedPrice) (plan.Price, error) {
return price, fmt.Errorf("failed to cast UnitPrice: %w", err)
}

unitPrice := plan.UnitPrice{
PriceMeta: plan.PriceMeta{
Type: plan.UnitPriceType,
},
}
unitPrice := plan.UnitPrice{}

unitPrice.Amount, err = decimal.NewFromString(unit.Amount)
if err != nil {
Expand Down Expand Up @@ -604,9 +591,6 @@ func AsPrice(p api.RateCardUsageBasedPrice) (plan.Price, error) {
}

tieredPrice := plan.TieredPrice{
PriceMeta: plan.PriceMeta{
Type: plan.TieredPriceType,
},
Tiers: nil,
}

Expand Down Expand Up @@ -711,9 +695,6 @@ func AsEntitlementTemplate(e api.RateCardEntitlement) (plan.EntitlementTemplate,
}

meteredTemplate := plan.MeteredEntitlementTemplate{
EntitlementTemplateMeta: plan.EntitlementTemplateMeta{
Type: entitlement.EntitlementTypeMetered,
},
Metadata: lo.FromPtrOr(metered.Metadata, nil),
IsSoftLimit: lo.FromPtrOr(metered.IsSoftLimit, false),
IssueAfterReset: metered.IssueAfterReset,
Expand All @@ -730,9 +711,6 @@ func AsEntitlementTemplate(e api.RateCardEntitlement) (plan.EntitlementTemplate,
}

staticTemplate := plan.StaticEntitlementTemplate{
EntitlementTemplateMeta: plan.EntitlementTemplateMeta{
Type: entitlement.EntitlementTypeMetered,
},
Metadata: lo.FromPtrOr(static.Metadata, nil),
Config: static.Config,
}
Expand All @@ -745,9 +723,6 @@ func AsEntitlementTemplate(e api.RateCardEntitlement) (plan.EntitlementTemplate,
}

booleanTemplate := plan.BooleanEntitlementTemplate{
EntitlementTemplateMeta: plan.EntitlementTemplateMeta{
Type: entitlement.EntitlementTypeMetered,
},
Metadata: lo.FromPtrOr(boolean.Metadata, nil),
}

Expand Down
Loading

0 comments on commit f542d27

Please sign in to comment.