Skip to content

Commit

Permalink
feat(rounding): Expose rounding attributes to APIs (#2764)
Browse files Browse the repository at this point in the history
## Context

In addition to the [flexible
aggregation](https://github.com/119ef63110d2803db639f0db37a3b135?pvs=25),
some customers wants to round the output of the aggregation.

## Description

This PR exposes `rounding_function` and `rounding_precision` fields to
REST and GraphQL APIs. It also update `BillableMetrics#CreateService`
and `BillableMetrics#UpdateService`
  • Loading branch information
vincent-pochet authored Nov 4, 2024
1 parent e41b6eb commit e9e7970
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 20 deletions.
2 changes: 2 additions & 0 deletions app/controllers/api/v1/billable_metrics_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ def input_params
:recurring,
:field_name,
:expression,
:rounding_function,
:rounding_precision,
filters: [:key, {values: []}]
)
end
Expand Down
2 changes: 2 additions & 0 deletions app/graphql/types/billable_metrics/create_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class CreateInput < BaseInputObject
argument :field_name, String, required: false
argument :name, String, required: true
argument :recurring, Boolean, required: false
argument :rounding_function, Types::BillableMetrics::RoundingFunctionEnum, required: false
argument :rounding_precision, Integer, required: false
argument :weighted_interval, Types::BillableMetrics::WeightedIntervalEnum, required: false

argument :filters, [Types::BillableMetricFilters::Input], required: false
Expand Down
3 changes: 3 additions & 0 deletions app/graphql/types/billable_metrics/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class Object < Types::BaseObject
field :recurring, Boolean, null: false
field :subscriptions_count, Integer, null: false

field :rounding_function, Types::BillableMetrics::RoundingFunctionEnum, null: true
field :rounding_precision, Integer, null: true

field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :deleted_at, GraphQL::Types::ISO8601DateTime, null: true
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
Expand Down
11 changes: 11 additions & 0 deletions app/graphql/types/billable_metrics/rounding_function_enum.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module Types
module BillableMetrics
class RoundingFunctionEnum < Types::BaseEnum
BillableMetric::ROUNDING_FUNCTIONS.values.each do |type|
value type
end
end
end
end
2 changes: 2 additions & 0 deletions app/graphql/types/billable_metrics/update_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class UpdateInput < BaseInputObject
argument :field_name, String, required: false
argument :name, String, required: true
argument :recurring, Boolean, required: false
argument :rounding_function, Types::BillableMetrics::RoundingFunctionEnum, required: false
argument :rounding_precision, Integer, required: false
argument :weighted_interval, Types::BillableMetrics::WeightedIntervalEnum, required: false

argument :filters, [Types::BillableMetricFilters::Input], required: false
Expand Down
2 changes: 2 additions & 0 deletions app/serializers/v1/billable_metric_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ def serialize
aggregation_type: model.aggregation_type,
weighted_interval: model.weighted_interval,
recurring: model.recurring,
rounding_function: model.rounding_function,
rounding_precision: model.rounding_precision,
created_at: model.created_at.iso8601,
field_name: model.field_name,
expression: model.expression,
Expand Down
2 changes: 2 additions & 0 deletions app/services/billable_metrics/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def call
recurring: args[:recurring] || false,
aggregation_type: args[:aggregation_type]&.to_sym,
field_name: args[:field_name],
rounding_function: args[:rounding_function]&.to_sym,
rounding_precision: args[:rounding_precision],
weighted_interval: args[:weighted_interval]&.to_sym,
expression: args[:expression]
)
Expand Down
2 changes: 2 additions & 0 deletions app/services/billable_metrics/update_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def call
billable_metric.weighted_interval = params[:weighted_interval]&.to_sym if params.key?(:weighted_interval)
billable_metric.field_name = params[:field_name] if params.key?(:field_name)
billable_metric.recurring = params[:recurring] if params.key?(:recurring)
billable_metric.rounding_function = params[:rounding_function] if params.key?(:rounding_function)
billable_metric.rounding_precision = params[:rounding_precision] if params.key?(:rounding_precision)
billable_metric.weighted_interval = params[:weighted_interval]&.to_sym if params.key?(:weighted_interval)
billable_metric.expression = params[:expression] if params.key?(:expression)

Expand Down
12 changes: 12 additions & 0 deletions schema.graphql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 105 additions & 0 deletions schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions spec/graphql/types/billable_metrics/create_input_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
it { is_expected.to accept_argument(:field_name).of_type('String') }
it { is_expected.to accept_argument(:name).of_type('String!') }
it { is_expected.to accept_argument(:recurring).of_type('Boolean') }
it { is_expected.to accept_argument(:rounding_function).of_type('RoundingFunctionEnum') }
it { is_expected.to accept_argument(:rounding_precision).of_type('Int') }
it { is_expected.to accept_argument(:weighted_interval).of_type('WeightedIntervalEnum') }
it { is_expected.to accept_argument(:filters).of_type('[BillableMetricFiltersInput!]') }
end
2 changes: 2 additions & 0 deletions spec/graphql/types/billable_metrics/object_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@
it { is_expected.to have_field(:deleted_at).of_type('ISO8601DateTime') }
it { is_expected.to have_field(:updated_at).of_type('ISO8601DateTime!') }
it { is_expected.to have_field(:integration_mappings).of_type('[Mapping!]') }
it { is_expected.to have_field(:rounding_function).of_type('RoundingFunctionEnum') }
it { is_expected.to have_field(:rounding_precision).of_type('Int') }
end
2 changes: 2 additions & 0 deletions spec/graphql/types/billable_metrics/update_input_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
it { is_expected.to accept_argument(:field_name).of_type('String') }
it { is_expected.to accept_argument(:name).of_type('String!') }
it { is_expected.to accept_argument(:recurring).of_type('Boolean') }
it { is_expected.to accept_argument(:rounding_function).of_type('RoundingFunctionEnum') }
it { is_expected.to accept_argument(:rounding_precision).of_type('Int') }
it { is_expected.to accept_argument(:weighted_interval).of_type('WeightedIntervalEnum') }
it { is_expected.to accept_argument(:filters).of_type('[BillableMetricFiltersInput!]') }
end
11 changes: 6 additions & 5 deletions spec/requests/api/v1/billable_metrics_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
aggregation_type: 'sum_agg',
field_name: 'amount_sum',
expression: '1 + 2',
recurring: true
recurring: true,
rounding_function: 'round',
rounding_precision: 2
}
end

Expand All @@ -28,6 +30,8 @@
expect(json[:billable_metric][:created_at]).to be_present
expect(json[:billable_metric][:recurring]).to eq(create_params[:recurring])
expect(json[:billable_metric][:expression]).to eq(create_params[:expression])
expect(json[:billable_metric][:rounding_function]).to eq(create_params[:rounding_function])
expect(json[:billable_metric][:rounding_precision]).to eq(create_params[:rounding_precision])
expect(json[:billable_metric][:filters]).to eq([])
end

Expand All @@ -49,10 +53,7 @@

expect(response).to have_http_status(:success)
expect(json[:billable_metric][:lago_id]).to be_present
expect(json[:billable_metric][:recurring]).to eq(
create_params[:recurring
]
)
expect(json[:billable_metric][:recurring]).to eq(create_params[:recurring])
expect(json[:billable_metric][:aggregation_type]).to eq('weighted_sum_agg')
expect(json[:billable_metric][:weighted_interval]).to eq('seconds')
end
Expand Down
2 changes: 2 additions & 0 deletions spec/serializers/v1/billable_metric_serializer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
expect(result['billable_metric']['aggregation_type']).to eq(billable_metric.aggregation_type)
expect(result['billable_metric']['field_name']).to eq(billable_metric.field_name)
expect(result['billable_metric']['created_at']).to eq(billable_metric.created_at.iso8601)
expect(result['billable_metric']['rounding_function']).to eq(billable_metric.rounding_function)
expect(result['billable_metric']['rounding_precision']).to eq(billable_metric.rounding_precision)
expect(result['billable_metric']['weighted_interval']).to eq(billable_metric.weighted_interval)
expect(result['billable_metric']['expression']).to eq(billable_metric.expression)
expect(result['billable_metric']['active_subscriptions_count']).to eq(0)
Expand Down
2 changes: 2 additions & 0 deletions spec/services/billable_metrics/create_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
organization_id: organization.id,
aggregation_type: "count_agg",
expression: "1 + 2",
rounding_function: "ceil",
rounding_precision: 2,
recurring: false
}
end
Expand Down
35 changes: 20 additions & 15 deletions spec/services/billable_metrics/update_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,30 @@
description: 'New metric description',
aggregation_type: 'sum_agg',
field_name: 'field_value',
expression: '1 + 3'
expression: '1 + 3',
rounding_function: 'ceil',
rounding_precision: 2
}.tap do |p|
p[:filters] = filters unless filters.nil?
end
end
let(:filters) { nil }

describe '#call' do
it 'updates the billable metric' do
it 'updates the billable metric', aggregate_failures: true do
result = update_service.call

aggregate_failures do
expect(result).to be_success

metric = result.billable_metric
expect(metric.id).to eq(billable_metric.id)
expect(metric.name).to eq('New Metric')
expect(metric.code).to eq('new_metric')
expect(metric.aggregation_type).to eq('sum_agg')
expect(metric.expression).to eq('1 + 3')
end
expect(result).to be_success

metric = result.billable_metric
expect(metric).to have_attributes(
id: billable_metric.id,
name: 'New Metric',
code: 'new_metric',
aggregation_type: 'sum_agg',
rounding_function: 'ceil',
rounding_precision: 2,
expression: '1 + 3'
)
end

context 'with filters arguments' do
Expand Down Expand Up @@ -106,7 +109,7 @@

before { charge }

it 'updates only name and description' do
it 'updates only name and description', aggregate_failures: true do
result = update_service.call

aggregate_failures do
Expand All @@ -120,7 +123,9 @@
expect(result.billable_metric).not_to have_attributes(
code: 'new_metric',
aggregation_type: 'sum_agg',
field_name: 'field_value'
field_name: 'field_value',
rounding_function: 'ceil',
rounding_precision: 2
)
end
end
Expand Down

0 comments on commit e9e7970

Please sign in to comment.