Skip to content

Commit

Permalink
Add FormsFunnelQuery
Browse files Browse the repository at this point in the history
This will generate the data used for the eligibel and ineligible forms
funnels in the system admin dashboard
  • Loading branch information
fumimowdan committed Oct 2, 2023
1 parent 9db0f11 commit ff1ca9a
Show file tree
Hide file tree
Showing 2 changed files with 217 additions and 0 deletions.
131 changes: 131 additions & 0 deletions app/queries/forms_funnel_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
class FormsFunnelQuery
def self.call(...)
new(...).execute
end

def initialize(date_range: 24.hours.ago..Time.current)
@date_range = date_range
@entity_class = "Form"
@base_query = Event
.select(:entity_id)
.distinct
.where(entity_class: entity_class, created_at: date_range)
end

attr_reader :date_range, :entity_class, :base_query

def execute
data = StepFlow::STEPS.each_with_object({}) do |(route_key, step), hsh|
hsh[route_key] = query_dispatch(step)
hsh
end
data["submission"] = submission_query

data
end

def application_route_step_query(required_field)
other_query(required_field)
end

def school_details_step_query(required_field)
boolean_query(required_field)
end

def trainee_details_step_query(required_field)
boolean_query(required_field)
end

def contract_details_step_query(required_field)
boolean_query(required_field)
end

def start_date_step_query(required_field)
grouping = extract_dates(required_field)
.group_by do |(_id, start_date)|
Form::EligibilityCheck.new(Form.new).contract_start_date_eligible?(start_date.to_date)
end

count_grouping(grouping)
end

def subject_step_query(required_field)
other_query(required_field)
end

def visa_step_query(required_field)
other_query(required_field)
end

def entry_date_step_query(required_field)
date_of_entries = extract_dates(required_field)
start_dates = extract_dates("start_date")

form_dates = date_of_entries.each_with_object([]) do |(id, date_of_entry), list|
entry = start_dates.detect { |(sid, _)| sid == id }
list << [date_of_entry.to_date, entry.last.to_date]
list
end

grouping = form_dates.group_by do |(date_of_entry, start_date)|
Form::EligibilityCheck.new(Form.new).date_of_entry_eligible?(date_of_entry, start_date)
end

count_grouping(grouping)
end

def personal_details_step_query(required_field)
submitted_field_query(required_field)
end

def employment_details_step_query(required_field)
submitted_field_query(required_field)
end

def submission_query
{ eligible: base_query.where(action: :deleted).count }
end

private

def count_grouping(grouping)
{ eligible: grouping.fetch(true, []).count, ineligible: grouping.fetch(false, []).count }
end

def extract_dates(field)
base_query
.where("data->'#{field}' IS NOT NULL")
.pluck(:entity_id, Arel.sql("data->'#{field}'->1"))
end

def submitted_field_query(field)
eligible = base_query.where("data->'#{field}' IS NOT NULL").count

{ eligible: }
end

def boolean_query(field)
ineligible = base_query.where("data->'#{field}' @> ?", "[false]").count
eligible = base_query.where("data->'#{field}' @> ?", "[true]").count

{ eligible:, ineligible: }
end

def other_query(field)
total = base_query.where("data->'#{field}' IS NOT NULL").count
ineligible = base_query.where("data->'#{field}' @> ?", '["other"]')
.or(base_query.where("data->'#{field}' @> ?", '["Other"]'))
.count
eligible = total - ineligible

{ eligible:, ineligible: }
end

def query_dispatch(step)
method_name = "#{step.name.underscore}_query".to_sym
required_field = step::REQUIRED_FIELDS.first
return public_send(method_name, required_field) if respond_to?(method_name)

raise(NoMethodError, "You must define query method #{method_name}")
end
end
86 changes: 86 additions & 0 deletions spec/queries/forms_funnel_query_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
require "rails_helper"

RSpec.describe FormsFunnelQuery, type: :service do
subject(:forms_funnel) { described_class.new(date_range:) }

let(:date_range) { 1.day.ago..Time.current }

describe ".submission_query" do
before do
create_list(:form_submitted_event, 2)
end

let(:expected) { { eligible: 2 } }

it { expect(forms_funnel.submission_query).to eq(expected) }
end

describe ".employment_details_step_query" do
before do
create_list(:form_employment_details_event, 3)
end

let(:expected) { { eligible: 3 } }

it { expect(forms_funnel.employment_details_step_query("school_name")).to eq(expected) }
end

describe ".personal_details_step_query" do
before do
create_list(:form_personal_details_event, 4)
end

let(:expected) { { eligible: 4 } }

it { expect(forms_funnel.personal_details_step_query("given_name")).to eq(expected) }
end

describe ".entry_date_step_query" do
before do
old_start_date = create(:form_start_date_four_months_ago_event)
create(:ineligible_form_date_of_entry_event, entity_id: old_start_date.entity_id)
start_dates = create_list(:form_start_date_event, 6)
build_list(:form_date_of_entry_event, 5) do |event, i|
event.entity_id = start_dates[i].entity_id
event.save
end
end

let(:expected) { { eligible: 5, ineligible: 1 } }

it { expect(forms_funnel.entry_date_step_query("date_of_entry")).to eq(expected) }
end

describe ".start_date_step_query" do
before do
create_list(:form_start_date_event, 6)
create(:ineligible_form_start_date_event)
end

let(:expected) { { eligible: 6, ineligible: 1 } }

it { expect(forms_funnel.start_date_step_query("start_date")).to eq(expected) }
end

describe ".application_route_step_query" do
before do
create_list(:form_application_route_event, 6)
create(:ineligible_form_application_route_event)
end

let(:expected) { { eligible: 6, ineligible: 1 } }

it { expect(forms_funnel.application_route_step_query("application_route")).to eq(expected) }
end

describe ".school_details_step_query" do
before do
create_list(:form_school_details_event, 3)
create(:ineligible_form_school_details_event)
end

let(:expected) { { eligible: 3, ineligible: 1 } }

it { expect(forms_funnel.school_details_step_query("state_funded_secondary_school")).to eq(expected) }
end
end

0 comments on commit ff1ca9a

Please sign in to comment.