Skip to content

Commit d45eb6a

Browse files
authored
feat(Dr. Rai Reports): BP Fudging Indicator (#5729)
**Story card:** [sc-15924](https://app.shortcut.com/simpledotorg/story/15924/add-bp-fudging-indicator) ## Because BP Fudging has been identified as one of the key indicators we want to track in Simple. ## This addresses Adding "BP Fudging" as an indicator in Simple. This indicator is SQL-backed — like Statins (#5644) and Titration (#5643), and follow the same semantics. ## Test instructions suite tests
1 parent 4f7c0d8 commit d45eb6a

File tree

13 files changed

+244
-3
lines changed

13 files changed

+244
-3
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
module DrRai
2+
class BpFudgingIndicator < Indicator
3+
attr_reader :region
4+
5+
def datasource(region)
6+
@region = region
7+
@source ||= DrRai::Data::BpFudging.chartable
8+
@source[region.name]
9+
end
10+
11+
def display_name
12+
"BP Fudging"
13+
end
14+
15+
def target_type_frontend
16+
"percent"
17+
end
18+
19+
def numerator_key all: nil
20+
:numerator
21+
end
22+
23+
def denominator_key all: nil
24+
:denominator
25+
end
26+
27+
def action_passive
28+
"fudged"
29+
end
30+
31+
def action_active
32+
"Fudge"
33+
end
34+
35+
def unit
36+
"bps"
37+
end
38+
39+
def is_supported?(region)
40+
true
41+
end
42+
end
43+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class DrRai::Data::BpFudging < ApplicationRecord
2+
include DrRai::Chartable
3+
4+
QUARTERS = ->(timeline = 1.year.ago..Date.today) {
5+
Period.quarters_between(timeline.begin, timeline.end)
6+
.map(&:to_s)
7+
}
8+
9+
default_scope { where(quarter: QUARTERS.call(10.months.ago..2.months.from_now)) }
10+
scope :insert_window, ->(timeline) { where(quarter: QUARTERS.call(timeline)) }
11+
12+
chartable_internal_keys :numerator, :denominator, :ratio
13+
chartable_period_key :quarter
14+
chartable_outer_grouping :slug
15+
end

app/models/dr_rai/data/statin.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ class DrRai::Data::Statin < ApplicationRecord
22
include DrRai::Chartable
33

44
default_scope { where(month_date: 1.year.ago..Date.today) }
5+
scope :insert_window, ->(timeline) { where(month_date: timeline) }
56

67
chartable_internal_keys :eligible_patients, :patients_prescribed_statins
78
chartable_period_key :month_date

app/models/dr_rai/data/titration.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ class DrRai::Data::Titration < ApplicationRecord
22
include DrRai::Chartable
33

44
default_scope { where(month_date: 1.year.ago..Date.today) }
5+
scope :insert_window, ->(timeline) { where(month_date: timeline) }
56

67
chartable_internal_keys :follow_up_count, :titrated_count
78
chartable_period_key :month_date
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module DrRai
2+
class BpFudgingQueryFactory < QueryFactory
3+
INSERTER_SQL = "insert into #{DrRai::Data::BpFudging.table_name} (state, district, slug, quarter, numerator, denominator, ratio)".freeze
4+
5+
CONFLICT_HANDLER_SQL = <<~SQL
6+
on conflict (state, district, slug, quarter) do
7+
update set
8+
numerator = excluded.numerator,
9+
denominator = excluded.denominator,
10+
ratio = excluded.ratio,
11+
updated_at = now(); -- ...for good bookkeeping
12+
SQL
13+
14+
def inserter
15+
base_query(INSERTER_SQL, "") { |enhancement| enhancement }
16+
end
17+
18+
def updater
19+
base_query(INSERTER_SQL, CONFLICT_HANDLER_SQL) { |enhancement| enhancement }
20+
end
21+
22+
private
23+
24+
# This query is a modified version of what we use in Metabase; linked in Quick Links as well.
25+
# The modifications are thus
26+
# 1. Wide to Tall query on Quarter
27+
# 2. Added facility name to the mix, as "slug"
28+
# 3. Remove the filters on state and org
29+
def base_query inserter, conflict_handler
30+
<<~SQL
31+
#{yield inserter}
32+
(
33+
select
34+
reporting_facilities.state_name as "state",
35+
reporting_facilities.district_name "district",
36+
reporting_facilities.facility_name as "slug",
37+
to_char(bp.created_at, '"Q"q-yyyy') as "quarter",
38+
count(*) filter (where bp.systolic between 130 and 139) as "numerator",
39+
count(*) filter (where bp.systolic between 140 and 149) as "denominator",
40+
count(*) filter (where bp.systolic between 130 and 139) * 1.0 /
41+
nullif(count(*) filter (where bp.systolic between 140 and 149), 0) as "ratio"
42+
from blood_pressures bp
43+
join reporting_facilities on bp.facility_id = reporting_facilities.facility_id
44+
where 1 = 1
45+
and bp.created_at >= date_trunc('quarter', current_date - interval '12 months')
46+
group by
47+
1, 2, 3, 4
48+
)
49+
#{yield conflict_handler};
50+
SQL
51+
end
52+
end
53+
end

app/queries/dr_rai/query_factory.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ def for klazz, from: nil, to: nil
1919
instance = DrRai::TitrationQueryFactory.new(from, to)
2020
elsif klazz <= Data::Statin
2121
instance = DrRai::StatinsQueryFactory.new(from, to)
22+
elsif klazz <= Data::BpFudging
23+
instance = DrRai::BpFudgingQueryFactory.new(from, to)
2224
else
2325
raise "Unsupported"
2426
end

app/services/dr_rai/data_service.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def populate!
3030
private
3131

3232
def inserting?
33-
@klazz.where(month_date: @timeline).count == 0
33+
@klazz.insert_window(@timeline).count == 0
3434
end
3535
end
3636
end

config/schedule.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ def local(time)
9191
every :day, at: local("03:00 am"), roles: [:cron] do
9292
from = 1.month.ago.to_date.to_s
9393
to = Date.today.to_s
94-
rake "dr_rai:populate_titration_data[#{from}, #{to}]"
94+
%w[
95+
titration
96+
statins
97+
bp_fudging
98+
].each do |indicator|
99+
rake "dr_rai:populate_#{indicator}_data[#{from}, #{to}]"
100+
end
95101
end
96102

97103
every :day, at: local("01:00 am"), roles: [:cron] do
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class CreateDrRaiDataBpFudging < ActiveRecord::Migration[6.1]
2+
def change
3+
create_table :dr_rai_data_bp_fudgings do |t|
4+
t.string :state
5+
t.string :district
6+
t.string :slug
7+
t.string :quarter
8+
t.integer :numerator
9+
t.integer :denominator
10+
t.decimal :ratio, precision: 5, scale: 2
11+
t.datetime :deleted_at
12+
13+
t.timestamps default: -> { "CURRENT_TIMESTAMP" }, null: false
14+
end
15+
16+
add_index :dr_rai_data_bp_fudgings, [:state, :district, :slug, :quarter], unique: true, name: "index_dr_rai_data_bp_fudgings_on_state_district_slug_quarter"
17+
end
18+
end

db/structure.sql

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,44 @@ CREATE SEQUENCE public.dr_rai_actions_id_seq
10991099
ALTER SEQUENCE public.dr_rai_actions_id_seq OWNED BY public.dr_rai_actions.id;
11001100

11011101

1102+
--
1103+
-- Name: dr_rai_data_bp_fudgings; Type: TABLE; Schema: public; Owner: -
1104+
--
1105+
1106+
CREATE TABLE public.dr_rai_data_bp_fudgings (
1107+
id bigint NOT NULL,
1108+
state character varying,
1109+
district character varying,
1110+
slug character varying,
1111+
quarter character varying,
1112+
numerator integer,
1113+
denominator integer,
1114+
ratio numeric(5,2),
1115+
deleted_at timestamp without time zone,
1116+
created_at timestamp(6) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
1117+
updated_at timestamp(6) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
1118+
);
1119+
1120+
1121+
--
1122+
-- Name: dr_rai_data_bp_fudgings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
1123+
--
1124+
1125+
CREATE SEQUENCE public.dr_rai_data_bp_fudgings_id_seq
1126+
START WITH 1
1127+
INCREMENT BY 1
1128+
NO MINVALUE
1129+
NO MAXVALUE
1130+
CACHE 1;
1131+
1132+
1133+
--
1134+
-- Name: dr_rai_data_bp_fudgings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
1135+
--
1136+
1137+
ALTER SEQUENCE public.dr_rai_data_bp_fudgings_id_seq OWNED BY public.dr_rai_data_bp_fudgings.id;
1138+
1139+
11021140
--
11031141
-- Name: dr_rai_data_statins; Type: TABLE; Schema: public; Owner: -
11041142
--
@@ -8557,5 +8595,7 @@ INSERT INTO "schema_migrations" (version) VALUES
85578595
('20250923223358'),
85588596
('20250924101441'),
85598597
('20250924102156'),
8560-
('20250925094123');
8598+
('20250925094123'),
8599+
('20251125090819');
8600+
85618601

0 commit comments

Comments
 (0)