Commit a2c9a860 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch '268000-extend-graphql-measurements-api' into 'master'

Add filtering by recorded at date to measurements

See merge request gitlab-org/gitlab!46344
parents 1383abb6 9eae1060
...@@ -13,10 +13,20 @@ module Resolvers ...@@ -13,10 +13,20 @@ module Resolvers
required: true, required: true,
description: 'The type of measurement/statistics to retrieve' description: 'The type of measurement/statistics to retrieve'
def resolve(identifier:) argument :recorded_after, Types::TimeType,
required: false,
description: 'Measurement recorded after this date'
argument :recorded_before, Types::TimeType,
required: false,
description: 'Measurement recorded before this date'
def resolve(identifier:, recorded_before: nil, recorded_after: nil)
authorize! authorize!
::Analytics::InstanceStatistics::Measurement ::Analytics::InstanceStatistics::Measurement
.recorded_after(recorded_after)
.recorded_before(recorded_before)
.with_identifier(identifier) .with_identifier(identifier)
.order_by_latest .order_by_latest
end end
......
...@@ -36,6 +36,8 @@ module Analytics ...@@ -36,6 +36,8 @@ module Analytics
scope :order_by_latest, -> { order(recorded_at: :desc) } scope :order_by_latest, -> { order(recorded_at: :desc) }
scope :with_identifier, -> (identifier) { where(identifier: identifier) } scope :with_identifier, -> (identifier) { where(identifier: identifier) }
scope :recorded_after, -> (date) { where(self.model.arel_table[:recorded_at].gteq(date)) if date.present? }
scope :recorded_before, -> (date) { where(self.model.arel_table[:recorded_at].lteq(date)) if date.present? }
def self.measurement_identifier_values def self.measurement_identifier_values
identifiers.values identifiers.values
......
---
title: Add filtering by recorded date to instance statistics measurements GraphQL API
merge_request: 46344
author:
type: changed
...@@ -16452,6 +16452,16 @@ type Query { ...@@ -16452,6 +16452,16 @@ type Query {
Returns the last _n_ elements from the list. Returns the last _n_ elements from the list.
""" """
last: Int last: Int
"""
Measurement recorded after this date
"""
recordedAfter: Time
"""
Measurement recorded before this date
"""
recordedBefore: Time
): InstanceStatisticsMeasurementConnection ): InstanceStatisticsMeasurementConnection
""" """
......
...@@ -47741,6 +47741,26 @@ ...@@ -47741,6 +47741,26 @@
}, },
"defaultValue": null "defaultValue": null
}, },
{
"name": "recordedAfter",
"description": "Measurement recorded after this date",
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"defaultValue": null
},
{
"name": "recordedBefore",
"description": "Measurement recorded before this date",
"type": {
"kind": "SCALAR",
"name": "Time",
"ofType": null
},
"defaultValue": null
},
{ {
"name": "after", "name": "after",
"description": "Returns the elements in the list that come after the specified cursor.", "description": "Returns the elements in the list that come after the specified cursor.",
...@@ -14,7 +14,9 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso ...@@ -14,7 +14,9 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso
let_it_be(:project_measurement_new) { create(:instance_statistics_measurement, :project_count, recorded_at: 2.days.ago) } let_it_be(:project_measurement_new) { create(:instance_statistics_measurement, :project_count, recorded_at: 2.days.ago) }
let_it_be(:project_measurement_old) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago) } let_it_be(:project_measurement_old) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago) }
subject { resolve_measurements({ identifier: 'projects' }, { current_user: current_user }) } let(:arguments) { { identifier: 'projects' } }
subject { resolve_measurements(arguments, { current_user: current_user }) }
context 'when requesting project count measurements' do context 'when requesting project count measurements' do
context 'as an admin user' do context 'as an admin user' do
...@@ -40,6 +42,24 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso ...@@ -40,6 +42,24 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end end
end end
context 'when filtering by recorded_after and recorded_before' do
before do
arguments[:recorded_after] = 4.days.ago
arguments[:recorded_before] = 1.day.ago
end
it { is_expected.to match_array([project_measurement_new]) }
context 'when "incorrect" values are passed' do
before do
arguments[:recorded_after] = 1.day.ago
arguments[:recorded_before] = 4.days.ago
end
it { is_expected.to be_empty }
end
end
end end
context 'when requesting pipeline counts by pipeline status' do context 'when requesting pipeline counts by pipeline status' do
......
...@@ -45,6 +45,34 @@ RSpec.describe Analytics::InstanceStatistics::Measurement, type: :model do ...@@ -45,6 +45,34 @@ RSpec.describe Analytics::InstanceStatistics::Measurement, type: :model do
it { is_expected.to match_array([measurement_1, measurement_2]) } it { is_expected.to match_array([measurement_1, measurement_2]) }
end end
describe '.recorded_after' do
subject { described_class.recorded_after(8.days.ago) }
it { is_expected.to match_array([measurement_2, measurement_3]) }
context 'when nil is given' do
subject { described_class.recorded_after(nil) }
it 'does not apply filtering' do
expect(subject).to match_array([measurement_1, measurement_2, measurement_3])
end
end
end
describe '.recorded_before' do
subject { described_class.recorded_before(4.days.ago) }
it { is_expected.to match_array([measurement_1, measurement_3]) }
context 'when nil is given' do
subject { described_class.recorded_after(nil) }
it 'does not apply filtering' do
expect(subject).to match_array([measurement_1, measurement_2, measurement_3])
end
end
end
end end
describe '#measurement_identifier_values' do describe '#measurement_identifier_values' do
......
...@@ -9,7 +9,8 @@ RSpec.describe 'InstanceStatisticsMeasurements' do ...@@ -9,7 +9,8 @@ RSpec.describe 'InstanceStatisticsMeasurements' do
let!(:instance_statistics_measurement_1) { create(:instance_statistics_measurement, :project_count, recorded_at: 20.days.ago, count: 5) } let!(:instance_statistics_measurement_1) { create(:instance_statistics_measurement, :project_count, recorded_at: 20.days.ago, count: 5) }
let!(:instance_statistics_measurement_2) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago, count: 10) } let!(:instance_statistics_measurement_2) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago, count: 10) }
let(:query) { graphql_query_for(:instanceStatisticsMeasurements, 'identifier: PROJECTS', 'nodes { count identifier }') } let(:arguments) { 'identifier: PROJECTS' }
let(:query) { graphql_query_for(:instanceStatisticsMeasurements, arguments, 'nodes { count identifier }') }
before do before do
post_graphql(query, current_user: current_user) post_graphql(query, current_user: current_user)
...@@ -21,4 +22,14 @@ RSpec.describe 'InstanceStatisticsMeasurements' do ...@@ -21,4 +22,14 @@ RSpec.describe 'InstanceStatisticsMeasurements' do
{ "count" => 5, 'identifier' => 'PROJECTS' } { "count" => 5, 'identifier' => 'PROJECTS' }
]) ])
end end
context 'with recorded_at filters' do
let(:arguments) { %(identifier: PROJECTS, recordedAfter: "#{15.days.ago.to_date}", recordedBefore: "#{5.days.ago.to_date}") }
it 'returns filtered measurement objects' do
expect(graphql_data.dig('instanceStatisticsMeasurements', 'nodes')).to eq([
{ "count" => 10, 'identifier' => 'PROJECTS' }
])
end
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment