Skip to content

Commit 18c64e2

Browse files
aagrawalrtslAyushi Agrawal
andauthored
adding patitioned table for reporting_facility_appointment_scheduled_… (#5813)
…days **Story card:** [SIMPLEBACK-124](https://rtsl.atlassian.net/browse/SIMPLEBACK-124) ## Because We need to move a our mat views to partitioned table ## This addresses Creating a partitioned table reporting_facility_appointment_scheduled_days.rb 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 fe99315 commit 18c64e2

4 files changed

Lines changed: 197 additions & 1 deletion

File tree

app/models/reports/facility_appointment_scheduled_days.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@ class FacilityAppointmentScheduledDays < 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: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
class CreatePartitionedTableReportingFacilityAppointmentScheduledDays < ActiveRecord::Migration[6.1]
2+
def up
3+
execute <<~SQL
4+
CREATE TABLE IF NOT EXISTS simple_reporting.reporting_facility_appointment_scheduled_days (
5+
facility_id uuid,
6+
month_date date,
7+
htn_appts_scheduled_0_to_14_days integer,
8+
htn_appts_scheduled_15_to_31_days integer,
9+
htn_appts_scheduled_32_to_62_days integer,
10+
htn_appts_scheduled_more_than_62_days integer,
11+
htn_total_appts_scheduled integer,
12+
diabetes_appts_scheduled_0_to_14_days integer,
13+
diabetes_appts_scheduled_15_to_31_days integer,
14+
diabetes_appts_scheduled_32_to_62_days integer,
15+
diabetes_appts_scheduled_more_than_62_days integer,
16+
diabetes_total_appts_scheduled integer
17+
)
18+
PARTITION BY LIST (month_date);
19+
SQL
20+
21+
add_index "simple_reporting.reporting_facility_appointment_scheduled_days", ["facility_id"], name: "index_reporting_facility_appointment_scheduled_days_facility_id"
22+
23+
execute <<~SQL
24+
CREATE OR REPLACE FUNCTION simple_reporting.reporting_facility_appointment_scheduled_days_table_function(date) RETURNS SETOF simple_reporting.reporting_facility_appointment_scheduled_days
25+
LANGUAGE plpgsql
26+
AS $_$
27+
BEGIN
28+
RETURN QUERY
29+
WITH latest_medical_histories AS (
30+
SELECT DISTINCT ON (patient_id) mh.*
31+
FROM medical_histories mh
32+
WHERE mh.deleted_at IS NULL
33+
ORDER BY patient_id, mh.device_created_at DESC
34+
),
35+
latest_appointments_per_patient_per_month AS (
36+
SELECT DISTINCT ON (patient_id, month_date)
37+
a.*,
38+
lmh.hypertension,
39+
lmh.diabetes,
40+
to_char(a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')), 'YYYY-MM-01')::date AS month_date
41+
FROM appointments a
42+
INNER JOIN patients p ON p.id = a.patient_id
43+
INNER JOIN latest_medical_histories lmh ON lmh.patient_id = a.patient_id
44+
WHERE a.scheduled_date >= date_trunc('day', a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')))
45+
AND date_trunc('month', a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE'))) = $1
46+
AND date_trunc('month', a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE'))) > date_trunc('month', p.recorded_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')))
47+
AND p.deleted_at IS NULL
48+
AND p.diagnosed_confirmed_at IS NOT NULL
49+
AND a.deleted_at IS NULL
50+
AND (lmh.hypertension = 'yes' OR lmh.diabetes = 'yes')
51+
ORDER BY a.patient_id, month_date, a.device_created_at DESC
52+
),
53+
scheduled_days_distribution AS (
54+
SELECT
55+
month_date,
56+
width_bucket(
57+
extract('days' FROM (scheduled_date - date_trunc('day', device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')))))::integer,
58+
array[0, 15, 32, 63]
59+
) AS bucket,
60+
COUNT(*) AS number_of_appointments,
61+
hypertension,
62+
diabetes,
63+
creation_facility_id AS facility_id
64+
FROM latest_appointments_per_patient_per_month
65+
GROUP BY bucket, creation_facility_id, month_date, hypertension, diabetes
66+
)
67+
SELECT
68+
facility_id,
69+
month_date,
70+
(SUM(number_of_appointments) FILTER (WHERE bucket = 1 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_0_to_14_days,
71+
(SUM(number_of_appointments) FILTER (WHERE bucket = 2 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_15_to_31_days,
72+
(SUM(number_of_appointments) FILTER (WHERE bucket = 3 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_32_to_62_days,
73+
(SUM(number_of_appointments) FILTER (WHERE bucket = 4 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_more_than_62_days,
74+
(SUM(number_of_appointments) FILTER (WHERE hypertension = 'yes'))::integer AS htn_total_appts_scheduled,
75+
(SUM(number_of_appointments) FILTER (WHERE bucket = 1 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_0_to_14_days,
76+
(SUM(number_of_appointments) FILTER (WHERE bucket = 2 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_15_to_31_days,
77+
(SUM(number_of_appointments) FILTER (WHERE bucket = 3 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_32_to_62_days,
78+
(SUM(number_of_appointments) FILTER (WHERE bucket = 4 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_more_than_62_days,
79+
(SUM(number_of_appointments) FILTER (WHERE diabetes = 'yes'))::integer AS diabetes_total_appts_scheduled
80+
FROM scheduled_days_distribution
81+
GROUP BY facility_id, month_date;
82+
END;
83+
$_$;
84+
SQL
85+
end
86+
87+
def down
88+
execute <<~SQL
89+
DROP FUNCTION IF EXISTS simple_reporting.reporting_facility_appointment_scheduled_days_table_function(date);
90+
SQL
91+
92+
drop_table "simple_reporting.reporting_facility_appointment_scheduled_days"
93+
end
94+
end

db/structure.sql

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,91 @@ CREATE OR REPLACE FUNCTION simple_reporting.reporting_overdue_patients_table_fun
17271727
END;
17281728
$_$;
17291729

1730+
--
1731+
-- Name: reporting_facility_appointment_scheduled_days; Type: TABLE; Schema: simple_reporting; Owner: -
1732+
--
1733+
1734+
CREATE TABLE IF NOT EXISTS simple_reporting.reporting_facility_appointment_scheduled_days (
1735+
facility_id uuid,
1736+
month_date date,
1737+
htn_appts_scheduled_0_to_14_days integer,
1738+
htn_appts_scheduled_15_to_31_days integer,
1739+
htn_appts_scheduled_32_to_62_days integer,
1740+
htn_appts_scheduled_more_than_62_days integer,
1741+
htn_total_appts_scheduled integer,
1742+
diabetes_appts_scheduled_0_to_14_days integer,
1743+
diabetes_appts_scheduled_15_to_31_days integer,
1744+
diabetes_appts_scheduled_32_to_62_days integer,
1745+
diabetes_appts_scheduled_more_than_62_days integer,
1746+
diabetes_total_appts_scheduled integer
1747+
)
1748+
PARTITION BY LIST (month_date);
1749+
1750+
--
1751+
-- Name: reporting_facility_appointment_scheduled_days_table_function(date); Type: FUNCTION; Schema: simple_reporting; Owner: -
1752+
--
1753+
1754+
CREATE OR REPLACE FUNCTION simple_reporting.reporting_facility_appointment_scheduled_days_table_function(date) RETURNS SETOF simple_reporting.reporting_facility_appointment_scheduled_days
1755+
LANGUAGE plpgsql
1756+
AS $_$
1757+
BEGIN
1758+
RETURN QUERY
1759+
WITH latest_medical_histories AS (
1760+
SELECT DISTINCT ON (patient_id) mh.*
1761+
FROM medical_histories mh
1762+
WHERE mh.deleted_at IS NULL
1763+
ORDER BY patient_id, mh.device_created_at DESC
1764+
),
1765+
latest_appointments_per_patient_per_month AS (
1766+
SELECT DISTINCT ON (patient_id, month_date)
1767+
a.*,
1768+
lmh.hypertension,
1769+
lmh.diabetes,
1770+
to_char(a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')), 'YYYY-MM-01')::date AS month_date
1771+
FROM appointments a
1772+
INNER JOIN patients p ON p.id = a.patient_id
1773+
INNER JOIN latest_medical_histories lmh ON lmh.patient_id = a.patient_id
1774+
WHERE a.scheduled_date >= date_trunc('day', a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')))
1775+
AND date_trunc('month', a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE'))) = $1
1776+
AND date_trunc('month', a.device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE'))) > date_trunc('month', p.recorded_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')))
1777+
AND p.deleted_at IS NULL
1778+
AND p.diagnosed_confirmed_at IS NOT NULL
1779+
AND a.deleted_at IS NULL
1780+
AND (lmh.hypertension = 'yes' OR lmh.diabetes = 'yes')
1781+
ORDER BY a.patient_id, month_date, a.device_created_at DESC
1782+
),
1783+
scheduled_days_distribution AS (
1784+
SELECT
1785+
month_date,
1786+
width_bucket(
1787+
extract('days' FROM (scheduled_date - date_trunc('day', device_created_at AT TIME ZONE 'UTC' AT TIME ZONE (SELECT current_setting('TIMEZONE')))))::integer,
1788+
array[0, 15, 32, 63]
1789+
) AS bucket,
1790+
COUNT(*) AS number_of_appointments,
1791+
hypertension,
1792+
diabetes,
1793+
creation_facility_id AS facility_id
1794+
FROM latest_appointments_per_patient_per_month
1795+
GROUP BY bucket, creation_facility_id, month_date, hypertension, diabetes
1796+
)
1797+
SELECT
1798+
facility_id,
1799+
month_date,
1800+
(SUM(number_of_appointments) FILTER (WHERE bucket = 1 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_0_to_14_days,
1801+
(SUM(number_of_appointments) FILTER (WHERE bucket = 2 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_15_to_31_days,
1802+
(SUM(number_of_appointments) FILTER (WHERE bucket = 3 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_32_to_62_days,
1803+
(SUM(number_of_appointments) FILTER (WHERE bucket = 4 AND hypertension = 'yes'))::integer AS htn_appts_scheduled_more_than_62_days,
1804+
(SUM(number_of_appointments) FILTER (WHERE hypertension = 'yes'))::integer AS htn_total_appts_scheduled,
1805+
(SUM(number_of_appointments) FILTER (WHERE bucket = 1 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_0_to_14_days,
1806+
(SUM(number_of_appointments) FILTER (WHERE bucket = 2 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_15_to_31_days,
1807+
(SUM(number_of_appointments) FILTER (WHERE bucket = 3 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_32_to_62_days,
1808+
(SUM(number_of_appointments) FILTER (WHERE bucket = 4 AND diabetes = 'yes'))::integer AS diabetes_appts_scheduled_more_than_62_days,
1809+
(SUM(number_of_appointments) FILTER (WHERE diabetes = 'yes'))::integer AS diabetes_total_appts_scheduled
1810+
FROM scheduled_days_distribution
1811+
GROUP BY facility_id, month_date;
1812+
END;
1813+
$_$;
1814+
17301815
--
17311816
-- Name: accesses; Type: TABLE; Schema: public; Owner: -
17321817
--
@@ -8909,6 +8994,12 @@ CREATE INDEX overdue_patients_assigned_facility_region_id ON simple_reporting.re
89098994

89108995
CREATE INDEX overdue_patients_patient_id ON simple_reporting.reporting_overdue_patients USING btree (patient_id);
89118996

8997+
--
8998+
-- Name: index_reporting_facility_appointment_scheduled_days_facility_id; Type: INDEX; Schema: simple_reporting; Owner: -
8999+
--
9000+
9001+
CREATE INDEX index_reporting_facility_appointment_scheduled_days_facility_id ON simple_reporting.reporting_facility_appointment_scheduled_days USING btree (facility_id);
9002+
89129003
--
89139004
-- Name: patient_phone_numbers fk_rails_0145dd0b05; Type: FK CONSTRAINT; Schema: public; Owner: -
89149005
--
@@ -9482,6 +9573,7 @@ INSERT INTO "schema_migrations" (version) VALUES
94829573
('20260507063641'),
94839574
('20260513141718'),
94849575
('20260515103653'),
9485-
('20260521101357');
9576+
('20260521101357'),
9577+
('20260528053923');
94869578

94879579

spec/models/reports/facility_appointment_scheduled_days_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,10 @@
252252
expect(described_class.find_by(month_date: Period.current, facility: facility)).to be_nil
253253
end
254254
end
255+
256+
describe "#partitioned?" do
257+
it "returns true" do
258+
expect(described_class.partitioned?).to be(true)
259+
end
260+
end
255261
end

0 commit comments

Comments
 (0)