Commit 9eae1060 authored by Adam Hegyi's avatar Adam Hegyi

Add filtering by recorded at date to measurements

This change adds filtering capabilities by recorded at to instance
statistics measurements GraphQL api.
parent 37ff491b
......@@ -13,10 +13,20 @@ module Resolvers
required: true,
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!
::Analytics::InstanceStatistics::Measurement
.recorded_after(recorded_after)
.recorded_before(recorded_before)
.with_identifier(identifier)
.order_by_latest
end
......
......@@ -36,6 +36,8 @@ module Analytics
scope :order_by_latest, -> { order(recorded_at: :desc) }
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
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 {
Returns the last _n_ elements from the list.
"""
last: Int
"""
Measurement recorded after this date
"""
recordedAfter: Time
"""
Measurement recorded before this date
"""
recordedBefore: Time
): InstanceStatisticsMeasurementConnection
"""
......
......@@ -47741,6 +47741,26 @@
},
"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",
"description": "Returns the elements in the list that come after the specified cursor.",
......@@ -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_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 'as an admin user' do
......@@ -40,6 +42,24 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
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
context 'when requesting pipeline counts by pipeline status' do
......
......@@ -45,6 +45,34 @@ RSpec.describe Analytics::InstanceStatistics::Measurement, type: :model do
it { is_expected.to match_array([measurement_1, measurement_2]) }
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
describe '#measurement_identifier_values' 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_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
post_graphql(query, current_user: current_user)
......@@ -21,4 +22,14 @@ RSpec.describe 'InstanceStatisticsMeasurements' do
{ "count" => 5, 'identifier' => 'PROJECTS' }
])
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
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