Skip to content

Commit d551e52

Browse files
aagrawalrtslAyushi Agrawal
andauthored
adding partitioned reporting_overdue_patients table (#5808)
**Story card:** [SIMPLEBACK-118](https://rtsl.atlassian.net/browse/SIMPLEBACK-118) ## Because We need to move a our mat views to partitioned table ## This addresses Creating a partitioned table reporting_overdue_patients under simple_reporting schema Both mat view and partitioned table version will exist for a small time for monitoring in prod ## Test instructions Suite test Co-authored-by: Ayushi Agrawal <ayushiagrawal@RTSL-P172G93770.local>
1 parent 70bfcdc commit d551e52

4 files changed

Lines changed: 562 additions & 1 deletion

File tree

app/models/reports/overdue_patient.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@ class OverduePatient < Reports::View
66
def self.materialized?
77
true
88
end
9+
10+
def self.partitioned?
11+
true
12+
end
913
end
1014
end
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
class CreatePartitionedTableReportingOverduePatients < ActiveRecord::Migration[6.1]
2+
def up
3+
execute <<~SQL
4+
CREATE TABLE IF NOT EXISTS simple_reporting.reporting_overdue_patients (
5+
month_date date,
6+
patient_id uuid,
7+
hypertension text,
8+
diabetes text,
9+
htn_care_state text,
10+
month double precision,
11+
quarter double precision,
12+
year double precision,
13+
month_string text,
14+
quarter_string text,
15+
assigned_facility_id uuid,
16+
assigned_facility_slug character varying,
17+
assigned_facility_region_id uuid,
18+
assigned_block_slug character varying,
19+
assigned_block_region_id uuid,
20+
assigned_district_slug character varying,
21+
assigned_district_region_id uuid,
22+
assigned_state_slug character varying,
23+
assigned_state_region_id uuid,
24+
assigned_organization_slug character varying,
25+
assigned_organization_region_id uuid,
26+
previous_appointment_id uuid,
27+
previous_appointment_date timestamp without time zone,
28+
previous_appointment_schedule_date date,
29+
visited_at_after_appointment timestamp without time zone,
30+
called_by_user_id uuid,
31+
next_called_at timestamp without time zone,
32+
previous_called_at timestamp without time zone,
33+
next_call_result_type character varying,
34+
next_call_removed_from_overdue_list_reason character varying,
35+
previous_call_result_type character varying,
36+
previous_call_removed_from_overdue_list_reason character varying,
37+
is_overdue text,
38+
has_called text,
39+
has_visited_following_call text,
40+
ltfu text,
41+
under_care text,
42+
has_phone text,
43+
removed_from_overdue_list text,
44+
removed_from_overdue_list_during_the_month text
45+
)
46+
PARTITION BY LIST (month_date);
47+
SQL
48+
49+
add_index "simple_reporting.reporting_overdue_patients", ["assigned_facility_region_id"], name: "overdue_patients_assigned_facility_region_id"
50+
add_index "simple_reporting.reporting_overdue_patients", ["patient_id"], name: "overdue_patients_patient_id"
51+
52+
execute <<~SQL
53+
CREATE OR REPLACE FUNCTION simple_reporting.reporting_overdue_patients_table_function(date) RETURNS SETOF simple_reporting.reporting_overdue_patients
54+
LANGUAGE plpgsql
55+
AS $_$
56+
BEGIN
57+
RETURN QUERY
58+
WITH patients_with_appointments AS (
59+
SELECT DISTINCT ON (rps.patient_id, rps.month_date)
60+
rps.month_date,
61+
rps.patient_id,
62+
rps.hypertension AS hypertension,
63+
rps.diabetes AS diabetes,
64+
rps.htn_care_state,
65+
rps.month,
66+
rps.quarter,
67+
rps.year,
68+
rps.month_string,
69+
rps.quarter_string,
70+
rps.assigned_facility_id,
71+
rps.assigned_facility_slug,
72+
rps.assigned_facility_region_id,
73+
rps.assigned_block_slug,
74+
rps.assigned_block_region_id,
75+
rps.assigned_district_slug,
76+
rps.assigned_district_region_id,
77+
rps.assigned_state_slug,
78+
rps.assigned_state_region_id,
79+
rps.assigned_organization_slug,
80+
rps.assigned_organization_region_id,
81+
appointments.id AS previous_appointment_id,
82+
appointments.device_created_at AS previous_appointment_date,
83+
appointments.scheduled_date AS previous_appointment_schedule_date
84+
FROM
85+
reporting_patient_states rps
86+
LEFT JOIN appointments ON appointments.patient_id = rps.patient_id
87+
AND appointments.device_created_at < rps.month_date
88+
WHERE rps.status <> 'dead'
89+
AND rps.month_date = $1
90+
ORDER BY
91+
rps.patient_id,
92+
rps.month_date,
93+
appointments.device_created_at DESC
94+
),
95+
patients_with_appointments_and_visits AS (
96+
SELECT patients_with_appointments.*,
97+
visit_id,
98+
visited_at_after_appointment
99+
FROM patients_with_appointments
100+
LEFT JOIN lateral (
101+
SELECT
102+
DISTINCT ON (patient_id) id AS visit_id,
103+
patient_id,
104+
recorded_at AS visited_at_after_appointment
105+
FROM blood_sugars
106+
WHERE deleted_at IS NULL
107+
AND patient_id = patients_with_appointments.patient_id
108+
AND patients_with_appointments.previous_appointment_date < blood_sugars.recorded_at
109+
AND blood_sugars.recorded_at < patients_with_appointments.month_date + INTERVAL '1 month' + INTERVAL '15 days'
110+
UNION ALL (
111+
SELECT id AS visit_id,
112+
patient_id,
113+
recorded_at AS visited_at_after_appointment
114+
FROM blood_pressures
115+
WHERE deleted_at IS NULL
116+
AND patient_id = patients_with_appointments.patient_id
117+
AND patients_with_appointments.previous_appointment_date < blood_pressures.recorded_at
118+
AND blood_pressures.recorded_at < patients_with_appointments.month_date + INTERVAL '1 month' + INTERVAL '15 days'
119+
)
120+
UNION ALL (
121+
SELECT id AS visit_id,
122+
patient_id,
123+
device_created_at AS visited_at_after_appointment
124+
FROM appointments AS patients_with_appointments_visit
125+
WHERE deleted_at IS NULL
126+
AND patient_id = patients_with_appointments.patient_id
127+
AND patients_with_appointments.previous_appointment_date < patients_with_appointments_visit.device_created_at
128+
AND patients_with_appointments_visit.device_created_at < patients_with_appointments.month_date + INTERVAL '1 month' + INTERVAL '15 days'
129+
)
130+
UNION ALL (
131+
SELECT id AS visit_id,
132+
patient_id,
133+
device_created_at AS visited_at_after_appointment
134+
FROM prescription_drugs
135+
WHERE deleted_at IS NULL
136+
AND patient_id = patients_with_appointments.patient_id
137+
AND patients_with_appointments.previous_appointment_date < prescription_drugs.device_created_at
138+
AND prescription_drugs.device_created_at < patients_with_appointments.month_date + INTERVAL '1 month' + INTERVAL '15 days'
139+
)
140+
ORDER BY
141+
patient_id,
142+
visited_at_after_appointment
143+
) AS visits ON patients_with_appointments.patient_id = visits.patient_id
144+
),
145+
patient_with_call_results AS (
146+
SELECT
147+
DISTINCT ON (
148+
patients_with_appointments_and_visits.patient_id,
149+
patients_with_appointments_and_visits.month_date
150+
)
151+
patients_with_appointments_and_visits.*,
152+
previous_call_results.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE 'UTC' AS previous_called_at,
153+
previous_call_results.result_type AS previous_call_result_type,
154+
previous_call_results.remove_reason AS previous_call_removed_from_overdue_list_reason,
155+
next_call_results.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE 'UTC' AS next_called_at,
156+
next_call_results.result_type AS next_call_result_type,
157+
next_call_results.remove_reason as next_call_removed_from_overdue_list_reason,
158+
next_call_results.user_id AS called_by_user_id
159+
FROM
160+
patients_with_appointments_and_visits
161+
LEFT JOIN call_results previous_call_results ON patients_with_appointments_and_visits.patient_id = previous_call_results.patient_id
162+
AND previous_call_results.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')) < patients_with_appointments_and_visits.month_date
163+
AND previous_call_results.device_created_at > previous_appointment_schedule_date
164+
LEFT JOIN call_results next_call_results ON patients_with_appointments_and_visits.patient_id = next_call_results.patient_id
165+
AND next_call_results.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')) >= patients_with_appointments_and_visits.month_date
166+
AND next_call_results.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')) < patients_with_appointments_and_visits.month_date + INTERVAL '1 month'
167+
ORDER BY
168+
patients_with_appointments_and_visits.patient_id,
169+
patients_with_appointments_and_visits.month_date,
170+
next_call_results.device_created_at,
171+
previous_call_results.device_created_at DESC
172+
),
173+
patient_with_call_results_and_phone AS (
174+
SELECT
175+
DISTINCT ON (
176+
patient_with_call_results.patient_id,
177+
patient_with_call_results.month_date
178+
)
179+
patient_with_call_results.*,
180+
patient_phone_numbers.number AS patient_phone_number
181+
FROM
182+
patient_with_call_results
183+
LEFT JOIN patient_phone_numbers ON patient_phone_numbers.patient_id = patient_with_call_results.patient_id
184+
ORDER BY
185+
patient_with_call_results.patient_id,
186+
patient_with_call_results.month_date
187+
)
188+
SELECT
189+
month_date,
190+
patient_id,
191+
hypertension,
192+
diabetes,
193+
htn_care_state,
194+
month,
195+
quarter,
196+
year,
197+
month_string,
198+
quarter_string,
199+
assigned_facility_id,
200+
assigned_facility_slug,
201+
assigned_facility_region_id,
202+
assigned_block_slug,
203+
assigned_block_region_id,
204+
assigned_district_slug,
205+
assigned_district_region_id,
206+
assigned_state_slug,
207+
assigned_state_region_id,
208+
assigned_organization_slug,
209+
assigned_organization_region_id,
210+
previous_appointment_id,
211+
previous_appointment_date,
212+
previous_appointment_schedule_date,
213+
visited_at_after_appointment,
214+
called_by_user_id,
215+
next_called_at,
216+
previous_called_at,
217+
next_call_result_type,
218+
next_call_removed_from_overdue_list_reason,
219+
previous_call_result_type,
220+
previous_call_removed_from_overdue_list_reason,
221+
CASE
222+
WHEN previous_appointment_id IS NULL THEN 'no'
223+
WHEN (previous_appointment_schedule_date >= month_date) THEN 'no'
224+
WHEN (
225+
previous_appointment_schedule_date < month_date
226+
and visited_at_after_appointment < month_date
227+
) THEN 'no'
228+
ELSE 'yes'
229+
END AS is_overdue,
230+
CASE
231+
WHEN next_called_at IS NULL THEN 'no'
232+
ELSE 'yes'
233+
END AS has_called,
234+
CASE
235+
WHEN visited_at_after_appointment IS NULL
236+
OR next_called_at IS NULL THEN 'no'
237+
WHEN visited_at_after_appointment > next_called_at + INTERVAL '15 days' THEN 'no'
238+
ELSE 'yes'
239+
END AS has_visited_following_call,
240+
CASE
241+
WHEN htn_care_state = 'lost_to_follow_up' THEN 'yes'
242+
ELSE 'no'
243+
END AS ltfu,
244+
CASE
245+
WHEN htn_care_state = 'under_care' THEN 'yes'
246+
ELSE 'no'
247+
END AS under_care,
248+
CASE
249+
WHEN patient_phone_number IS NULL THEN 'no'
250+
ELSE 'yes'
251+
END AS has_phone,
252+
CASE
253+
WHEN previous_call_result_type = 'removed_from_overdue_list' THEN 'yes'
254+
ELSE 'no'
255+
END AS removed_from_overdue_list,
256+
CASE
257+
WHEN next_call_result_type = 'removed_from_overdue_list' THEN 'yes'
258+
ELSE 'no'
259+
END AS removed_from_overdue_list_during_the_month
260+
FROM
261+
patient_with_call_results_and_phone;
262+
END;
263+
$_$;
264+
SQL
265+
end
266+
267+
def down
268+
execute <<~SQL
269+
DROP FUNCTION IF EXISTS simple_reporting.reporting_overdue_patients_table_function(date);
270+
SQL
271+
272+
drop_table "simple_reporting.reporting_overdue_patients"
273+
end
274+
end

0 commit comments

Comments
 (0)