renalware-core 2.0.0.pre.rc8 → 2.0.0.pre.rc9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/renalware/modules/_clinical.scss +73 -0
- data/app/models/concerns/renalware/clinics/most_recent_measurement_scopes.rb.dead +43 -0
- data/app/models/renalware/clinics/clinic_visit.rb +2 -2
- data/app/models/renalware/clinics/current_observations.rb +57 -0
- data/app/models/renalware/letters/letter.rb +5 -1
- data/app/models/renalware/pathology/current_observation_set.rb +6 -0
- data/app/models/renalware/pathology/observation.rb +1 -0
- data/app/models/renalware/pathology/observation_request.rb +3 -0
- data/app/models/renalware/pathology/observations_jsonb_serializer.rb +7 -6
- data/app/models/renalware/pathology/{view_current_observation_results.rb → view_current_observation_results.rb.dead} +0 -0
- data/app/presenters/renalware/clinical/header_presenter.rb +33 -0
- data/app/presenters/renalware/letters/letter_presenter.rb +5 -1
- data/app/presenters/renalware/letters/part_class_filter.rb +36 -0
- data/app/presenters/renalware/renal/clinical_summary_presenter.rb +0 -1
- data/app/presenters/renalware/ukrdc/patient_presenter.rb +8 -2
- data/app/values/renalware/bmi.rb +20 -0
- data/app/views/renalware/admissions/consults/_table.html.slim +1 -1
- data/app/views/renalware/api/ukrdc/patients/_clinic_visit_observation.xml.builder +1 -1
- data/app/views/renalware/api/ukrdc/patients/_lab_orders.xml.builder +3 -3
- data/app/views/renalware/api/ukrdc/patients/_observations.xml.builder +3 -1
- data/app/views/renalware/api/ukrdc/patients/lab_orders/_lab_order.xml.builder +2 -2
- data/app/views/renalware/api/ukrdc/patients/lab_orders/_result_item.xml.builder +7 -2
- data/app/views/renalware/clinical/_header.html.slim +47 -0
- data/app/views/renalware/clinics/clinic_visits/_table.html.slim +0 -1
- data/app/views/renalware/clinics/visits/_table.html.slim +4 -1
- data/app/views/renalware/events/events/_event.html.slim +1 -1
- data/app/views/renalware/events/events/_table.html.slim +3 -0
- data/app/views/renalware/layouts/_patient.html.slim +1 -0
- data/app/views/renalware/letters/letters/_form.html.slim +1 -1
- data/app/views/renalware/letters/letters/_pathology.html.slim +0 -1
- data/app/views/renalware/mdm_patients/_table.html.slim +1 -1
- data/app/views/renalware/pathology/_navigation.html.slim +1 -1
- data/app/views/renalware/patients/patients/_table.html.slim +2 -2
- data/config/initializers/core_extensions.rb +1 -0
- data/config/initializers/inflections.rb +1 -0
- data/config/locales/renalware/clinical/allergies.en.yml +0 -2
- data/config/locales/renalware/clinical/{dry_weight.yml → dry_weight.en.yml} +0 -0
- data/config/locales/renalware/clinical/header.en.yml +14 -0
- data/db/functions/audit_view_as_json_v01.sql +25 -0
- data/db/functions/count_estimate_v01.sql +20 -0
- data/db/functions/generate_patient_secure_id_v01.sql +21 -0
- data/db/functions/generate_secure_id_v01.sql +18 -0
- data/db/functions/import_gps_csv_v01.sql +129 -0
- data/db/functions/import_practice_memberships_csv_v01.sql +48 -0
- data/db/functions/import_practices_csv_v01.sql +109 -0
- data/db/functions/preprocess_hl7_message_v01.sql +29 -0
- data/db/functions/preprocess_hl7_message_v02.sql +31 -0
- data/db/functions/refresh_all_matierialized_views_v01.sql +32 -0
- data/db/functions/refresh_current_observation_set_v01.sql +39 -0
- data/db/functions/update_current_observation_set_from_trigger_v01.sql +88 -0
- data/db/functions/update_current_observation_set_from_trigger_v02.sql +90 -0
- data/db/migrate/20161124152732_add_deleted_at_to_patient_bookmarks.rb +1 -1
- data/db/migrate/20170608135553_create_functions_to_generate_secure_patient_id.rb +4 -48
- data/db/migrate/20170705090219_create_refresh_all_materialized_views_fn.rb +2 -37
- data/db/migrate/20170707110155_rename_access_plans_to_access_plan_types.rb +1 -1
- data/db/migrate/20170831142819_enable_crosstab_extension.rb +2 -2
- data/db/migrate/20170911133224_add_type_to_messaging_messages.rb +1 -1
- data/db/migrate/20170915115228_add_schedule_diurnal_period_id_to_hd_profiles.rb +1 -1
- data/db/migrate/20171013145849_set_patients_secure_id.rb +1 -1
- data/db/migrate/20171101121130_create_function_to_render_audit_view_as_json.rb +2 -29
- data/db/migrate/20171127092158_create_function_to_import_practices.rb +4 -118
- data/db/migrate/20171127092359_create_fn_to_insert_gps.rb +3 -139
- data/db/migrate/20171206140738_create_fn_to_load_practice_memberships_csv.rb +2 -53
- data/db/migrate/20171213111513_create_fn_to_refresh_current_obs.rb +2 -43
- data/db/migrate/20171214141335_create_trigger_to_update_current_observation_sets.rb +3 -101
- data/db/migrate/20180119121243_create_trigger_to_preprocess_hl7_msg.rb +2 -41
- data/db/migrate/20180121115246_add_include_pathology_in_letter_to_letters_letterheads.rb +5 -0
- data/db/migrate/20180125201356_make_obs_set_trigger_change_updated_at.rb +2 -184
- data/db/migrate/20180130165803_add_deleted_at_indexes.rb +16 -0
- data/db/migrate/20180201090444_add_created_at_to_delayed_jobs_in_hl7_trig_fn.rb +9 -0
- data/db/migrate/20180207082540_create_count_estimate_function.rb +9 -0
- data/db/triggers/feed_messages_preprocessing_trigger_v01.sql +5 -0
- data/db/triggers/update_current_observation_set_trigger_v01.sql +7 -0
- data/lib/core_extensions/active_record/migration_helpers.rb +43 -0
- data/lib/renalware/engine.rb +6 -4
- data/lib/renalware/version.rb +1 -1
- data/spec/factories/pathology/observation_descriptions.rb +7 -1
- data/spec/support/shared_examples/accountable_examples.rb +6 -0
- data/spec/support/shared_examples/supersedable_examples.rb +12 -0
- metadata +33 -10
- data/app/models/renalware/letters/delivery/deliver_letter.rb.dead +0 -41
- data/app/models/renalware/pathology/current_key_observation_set.rb.dead +0 -10
- data/app/models/renalware/pathology/update_current_observations.rb.dead +0 -25
- data/app/presenters/renalware/pathology/current_observation_results.dead/presenter.rb.dead +0 -54
- data/app/views/renalware/letters/formatted_letters/show.rtf.slim.ol +0 -1
- data/app/views/renalware/patients/_prescriptions.html.slim.dead +0 -23
@@ -1,61 +1,10 @@
|
|
1
1
|
class CreateFnToLoadPracticeMembershipsCSV < ActiveRecord::Migration[5.1]
|
2
2
|
def up
|
3
|
-
sql
|
4
|
-
CREATE OR REPLACE FUNCTION renalware.import_practice_memberships_csv(file text) RETURNS void
|
5
|
-
AS $$
|
6
|
-
BEGIN
|
7
|
-
|
8
|
-
DROP TABLE IF EXISTS memberships_via_copy;
|
9
|
-
CREATE TEMP TABLE copied_memberships (
|
10
|
-
gp_code text NOT NULL,
|
11
|
-
practice_code text NOT NULL,
|
12
|
-
unused3 text,
|
13
|
-
unused4 text,
|
14
|
-
unused5 text,
|
15
|
-
unused7 text
|
16
|
-
);
|
17
|
-
|
18
|
-
-- Import the CSV file into copied_memberships - note there is no CSV header in this file
|
19
|
-
EXECUTE format ('COPY copied_memberships FROM %L DELIMITER %L CSV ', file, ',');
|
20
|
-
|
21
|
-
DROP TABLE IF EXISTS tmp_memberships;
|
22
|
-
CREATE TEMP TABLE tmp_memberships AS
|
23
|
-
SELECT
|
24
|
-
gp_code,
|
25
|
-
practice_code,
|
26
|
-
patient_primary_care_physicians.id primary_care_physician_id,
|
27
|
-
patient_practices.id as practice_id
|
28
|
-
from copied_memberships
|
29
|
-
INNER JOIN patient_practices on patient_practices.code = practice_code
|
30
|
-
INNER JOIN patient_primary_care_physicians on patient_primary_care_physicians.code = gp_code;
|
31
|
-
|
32
|
-
-- Insert any new memberships, ignoring any conflicts where the
|
33
|
-
-- practice_id + primary_care_physician_id already exists
|
34
|
-
INSERT INTO renalware.patient_practice_memberships
|
35
|
-
(practice_id, primary_care_physician_id, created_at, updated_at)
|
36
|
-
SELECT
|
37
|
-
practice_id,
|
38
|
-
primary_care_physician_id,
|
39
|
-
CURRENT_TIMESTAMP,
|
40
|
-
CURRENT_TIMESTAMP
|
41
|
-
FROM tmp_memberships
|
42
|
-
ON CONFLICT (practice_id, primary_care_physician_id) DO NOTHING;
|
43
|
-
|
44
|
-
-- Mark as deleted any memberships not in the latest uploaded data set - ie those gps have retired or moved on
|
45
|
-
UPDATE patient_practice_memberships mem
|
46
|
-
SET deleted_at = CURRENT_TIMESTAMP
|
47
|
-
WHERE NOT EXISTS (select 1 FROM tmp_memberships tmem
|
48
|
-
WHERE tmem.practice_id = mem.practice_id AND tmem.primary_care_physician_id = mem.primary_care_physician_id);
|
49
|
-
|
50
|
-
END;
|
51
|
-
$$ LANGUAGE plpgsql;
|
52
|
-
SQL
|
53
|
-
|
54
|
-
ActiveRecord::Base.connection.execute(sql)
|
3
|
+
load_function("import_practice_memberships_csv_v01.sql")
|
55
4
|
end
|
56
5
|
|
57
6
|
def down
|
58
|
-
|
7
|
+
connection.execute(
|
59
8
|
"DROP FUNCTION IF EXISTS import_practice_memberships_csv(file text);"
|
60
9
|
)
|
61
10
|
end
|
@@ -1,50 +1,9 @@
|
|
1
1
|
class CreateFnToRefreshCurrentObs < ActiveRecord::Migration[5.1]
|
2
2
|
def up
|
3
|
-
sql
|
4
|
-
CREATE OR REPLACE FUNCTION refresh_current_observation_set(a_patient_id integer)
|
5
|
-
-- Function to update the pathology_current_observation_set for a patient.
|
6
|
-
-- It stores the most recent results into the jsonb hash on that table.
|
7
|
-
-- To run for all patients, use
|
8
|
-
-- select refresh_current_observation_set(id) from patients;
|
9
|
-
--
|
10
|
-
RETURNS integer
|
11
|
-
LANGUAGE 'plpgsql'
|
12
|
-
as $$
|
13
|
-
BEGIN
|
14
|
-
with current_patient_obs as(
|
15
|
-
select
|
16
|
-
DISTINCT ON (p.id, obxd.id)
|
17
|
-
p.id as patient_id,
|
18
|
-
obxd.code,
|
19
|
-
json_build_object('result',(obx.result),'observed_at',obx.observed_at) as value
|
20
|
-
from patients p
|
21
|
-
inner join pathology_observation_requests obr on obr.patient_id = p.id
|
22
|
-
inner join pathology_observations obx on obx.request_id = obr.id
|
23
|
-
inner join pathology_observation_descriptions obxd on obx.description_id = obxd.id
|
24
|
-
where p.id = a_patient_id
|
25
|
-
order by p.id, obxd.id, obx.observed_at desc
|
26
|
-
),
|
27
|
-
current_patient_obs_as_jsonb as (
|
28
|
-
select patient_id,
|
29
|
-
jsonb_object_agg(code, value) as values,
|
30
|
-
CURRENT_TIMESTAMP,
|
31
|
-
CuRRENT_TIMESTAMP
|
32
|
-
from current_patient_obs
|
33
|
-
group by patient_id order by patient_id
|
34
|
-
)
|
35
|
-
insert into pathology_current_observation_sets (patient_id, values, created_at, updated_at)
|
36
|
-
select * from current_patient_obs_as_jsonb
|
37
|
-
ON conflict (patient_id)
|
38
|
-
DO UPDATE
|
39
|
-
SET values = excluded.values, updated_at = excluded.updated_at;
|
40
|
-
RETURN a_patient_id;
|
41
|
-
END
|
42
|
-
$$;
|
43
|
-
SQL
|
44
|
-
ActiveRecord::Base.connection.execute(sql)
|
3
|
+
load_function("refresh_current_observation_set_v01.sql")
|
45
4
|
end
|
46
5
|
|
47
6
|
def down
|
48
|
-
|
7
|
+
connection.execute("drop function if exists refresh_current_observation_set(integer)")
|
49
8
|
end
|
50
9
|
end
|
@@ -1,109 +1,11 @@
|
|
1
1
|
class CreateTriggerToUpdateCurrentObservationSets < ActiveRecord::Migration[5.1]
|
2
2
|
def up
|
3
|
-
sql
|
4
|
-
|
5
|
-
-- TC 14/12/2017
|
6
|
-
-- This function is called by a trigger when a row is inserted or updated in
|
7
|
-
-- pathology_observations. Its purpose is to keep current_observation_sets up to date
|
8
|
-
-- with the latest observations for any patient.
|
9
|
-
-- The current_observation_sets table maintains a jsonb hash into which we insert or replace
|
10
|
-
-- the observation, keyed by OBX code.
|
11
|
-
-- e.g. .. {"HGB": { "result": 123.1, "observed_at": '2017-12-12-01:01:01'}, ..
|
12
|
-
DECLARE
|
13
|
-
a_patient_id bigint;
|
14
|
-
a_code text;
|
15
|
-
current_observed_at timestamp;
|
16
|
-
current_result text;
|
17
|
-
new_observed_at timestamp;
|
18
|
-
BEGIN
|
19
|
-
RAISE NOTICE 'TRIGGER called on %',TG_TABLE_NAME ;
|
20
|
-
|
21
|
-
/*
|
22
|
-
If inserting or updating, we _could_ assume the last observation to be inserted is
|
23
|
-
the most 'recent' one (with the latest observed_at date).
|
24
|
-
However the order of incoming messages is not guaranteed, so we have two options:
|
25
|
-
1. Refresh the entire current_observation_set for the patient
|
26
|
-
2. Check the current observed_at date in the jsonb and only update if we have a more
|
27
|
-
recent one
|
28
|
-
We have gone for 2.
|
29
|
-
*/
|
30
|
-
|
31
|
-
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
|
32
|
-
|
33
|
-
-- Note we could re-generate the entire current pathology for the patient using
|
34
|
-
-- select refresh_current_observation_set(a_patient_id);
|
35
|
-
-- which is safer but uses more resources, so avoiding this for now.
|
36
|
-
|
37
|
-
-- Find and store patient_id into local variable
|
38
|
-
select request.patient_id into a_patient_id
|
39
|
-
from pathology_observation_requests request
|
40
|
-
where request.id = NEW.request_id;
|
41
|
-
|
42
|
-
-- Find and store the obx code into local variable
|
43
|
-
select description.code into a_code
|
44
|
-
from pathology_observation_descriptions description
|
45
|
-
where description.id = NEW.description_id;
|
46
|
-
|
47
|
-
-- Important! Create the observation_set if it doesn exist yet
|
48
|
-
-- ignore the error id the row already exists
|
49
|
-
insert into pathology_current_observation_sets (patient_id)
|
50
|
-
values (a_patient_id)
|
51
|
-
ON CONFLICT DO NOTHING;
|
52
|
-
|
53
|
-
-- We are going to compare the current and new observed_at dates
|
54
|
-
-- so need to cast them to a timestamp
|
55
|
-
select cast(New.observed_at as timestamp) into new_observed_at;
|
56
|
-
|
57
|
-
-- Get the most recent date and value for this observation
|
58
|
-
-- and store to variables.
|
59
|
-
select
|
60
|
-
cast(values -> a_code ->> 'observed_at' as timestamp),
|
61
|
-
values -> a_code ->> 'result'
|
62
|
-
into current_observed_at, current_result from
|
63
|
-
pathology_current_observation_sets
|
64
|
-
where patient_id = a_patient_id;
|
65
|
-
|
66
|
-
-- Output some info to helps us debug. This can be removed later.
|
67
|
-
RAISE NOTICE ' Request id % Patient id % Code %', NEW.request_id, a_patient_id, a_code;
|
68
|
-
RAISE NOTICE ' Last %: % at %', a_code, current_result, current_observed_at;
|
69
|
-
RAISE NOTICE ' New %: % at %', a_code, NEW.result, new_observed_at;
|
70
|
-
|
71
|
-
IF current_observed_at IS NULL OR new_observed_at >= current_observed_at THEN
|
72
|
-
-- The new pathology_observation row contain a more recent result that the old one.
|
73
|
-
-- (note there may not be an old one if the patient has neve had this obs before).
|
74
|
-
|
75
|
-
RAISE NOTICE ' Updating pathology_current_observation_sets..';
|
76
|
-
|
77
|
-
-- Update the values jsonb column with the new hash for this code, e.g.
|
78
|
-
-- .. {"HGB": { "result": 123.1, "observed_at": '2017-12-12-01:01:01'}, ..
|
79
|
-
-- Note the `set values` below actually reads in the jsonb, updates it,
|
80
|
-
-- and wites the whole thing back.
|
81
|
-
update pathology_current_observation_sets
|
82
|
-
set values = jsonb_set(
|
83
|
-
values,
|
84
|
-
('{'||a_code||'}')::text[], -- defined in the fn path::text[]
|
85
|
-
jsonb_build_object('result', NEW.result, 'observed_at', new_observed_at),
|
86
|
-
true)
|
87
|
-
where patient_id = a_patient_id;
|
88
|
-
END IF;
|
89
|
-
END IF;
|
90
|
-
RETURN NULL ;
|
91
|
-
END $body$ LANGUAGE plpgsql VOLATILE COST 100;
|
92
|
-
-- End function
|
93
|
-
|
94
|
-
-- Create the trigger which will call out function every time a row in pathology_observations
|
95
|
-
-- is inserted or updated
|
96
|
-
DROP TRIGGER IF EXISTS update_current_observation_set_trigger ON pathology_observations;
|
97
|
-
CREATE TRIGGER update_current_observation_set_trigger
|
98
|
-
AFTER INSERT OR UPDATE
|
99
|
-
ON pathology_observations
|
100
|
-
FOR EACH ROW EXECUTE PROCEDURE update_current_observation_set_from_trigger();
|
101
|
-
SQL
|
102
|
-
ActiveRecord::Base.connection.execute(sql)
|
3
|
+
load_function("update_current_observation_set_from_trigger_v01.sql")
|
4
|
+
load_trigger("update_current_observation_set_trigger_v01.sql")
|
103
5
|
end
|
104
6
|
|
105
7
|
def down
|
106
|
-
|
8
|
+
connection.execute("
|
107
9
|
DROP TRIGGER IF EXISTS update_current_observation_set_trigger ON pathology_observations;
|
108
10
|
DROP FUNCTION IF EXISTS update_current_observation_set_from_trigger();
|
109
11
|
")
|
@@ -1,46 +1,7 @@
|
|
1
1
|
class CreateTriggerToPreprocessHL7Msg < ActiveRecord::Migration[5.1]
|
2
2
|
def up
|
3
|
-
|
4
|
-
|
5
|
-
sql = <<-'SQL'
|
6
|
-
/* Create a function for the trigger to call */
|
7
|
-
CREATE FUNCTION preprocess_hl7_message() RETURNS trigger AS
|
8
|
-
$body$
|
9
|
-
BEGIN
|
10
|
-
/*
|
11
|
-
Mirth inserts a row into delayed job when a new HL7 message needs to be processed by Renalware.
|
12
|
-
The SQL it uses looks like this:
|
13
|
-
insert into renalware.delayed_jobs (handler, run_at)
|
14
|
-
values(E'--- !ruby/struct:FeedJob\nraw_message: |\n ' || REPLACE(${message.rawData},E'\r',E'\n '), NOW());
|
15
|
-
This works unless there is a 10^12 value in the unit of measurement segment for an OBX (e.g.
|
16
|
-
for WBC or HGB). Then Mirth encodes the ^ as \S\ because ^ is a significant character in Mirth
|
17
|
-
(field separator). Unfortunately this creates the combination
|
18
|
-
10\S\12 and S\12 is converted to \n when the handler's payload is loaded in by the delayed_job worker.
|
19
|
-
To get around this we need to convert instances of \S\ with another escape sequence eg «
|
20
|
-
and manually map this back to a ^ in the job handler ruby code.
|
21
|
-
|
22
|
-
So here, if this delayed_job is destined to be picked up by a Feed job handler
|
23
|
-
make sure we convert the Mirth escape sequence \S\ to \\S\\
|
24
|
-
*/
|
25
|
-
IF position('Feed' in NEW.handler) > 0 THEN
|
26
|
-
NEW.handler = replace(NEW.handler, E'\\S\\', E'\\\\S\\\\');
|
27
|
-
END IF;
|
28
|
-
|
29
|
-
RETURN NEW;
|
30
|
-
END
|
31
|
-
|
32
|
-
$body$
|
33
|
-
LANGUAGE plpgsql;
|
34
|
-
|
35
|
-
/* Create the trigger! */
|
36
|
-
CREATE TRIGGER feed_messages_preprocessing_trigger
|
37
|
-
BEFORE INSERT
|
38
|
-
ON delayed_jobs
|
39
|
-
FOR EACH ROW
|
40
|
-
EXECUTE PROCEDURE preprocess_hl7_message();
|
41
|
-
SQL
|
42
|
-
|
43
|
-
connection.execute(sql)
|
3
|
+
load_function("preprocess_hl7_message_v01.sql")
|
4
|
+
load_trigger("feed_messages_preprocessing_trigger_v01.sql")
|
44
5
|
end
|
45
6
|
|
46
7
|
def down
|
@@ -1,191 +1,9 @@
|
|
1
1
|
class MakeObsSetTriggerChangeUpdatedAt < ActiveRecord::Migration[5.1]
|
2
2
|
def up
|
3
|
-
sql
|
4
|
-
CREATE OR REPLACE FUNCTION update_current_observation_set_from_trigger() RETURNS TRIGGER AS $body$
|
5
|
-
-- TC 14/12/2017
|
6
|
-
-- This function is called by a trigger when a row is inserted or updated in
|
7
|
-
-- pathology_observations. Its purpose is to keep current_observation_sets up to date
|
8
|
-
-- with the latest observations for any patient.
|
9
|
-
-- The current_observation_sets table maintains a jsonb hash into which we insert or replace
|
10
|
-
-- the observation, keyed by OBX code.
|
11
|
-
-- e.g. .. {"HGB": { "result": 123.1, "observed_at": '2017-12-12-01:01:01'}, ..
|
12
|
-
DECLARE
|
13
|
-
a_patient_id bigint;
|
14
|
-
a_code text;
|
15
|
-
current_observed_at timestamp;
|
16
|
-
current_result text;
|
17
|
-
new_observed_at timestamp;
|
18
|
-
BEGIN
|
19
|
-
RAISE NOTICE 'TRIGGER called on %',TG_TABLE_NAME ;
|
20
|
-
|
21
|
-
/*
|
22
|
-
If inserting or updating, we _could_ assume the last observation to be inserted is
|
23
|
-
the most 'recent' one (with the latest observed_at date).
|
24
|
-
However the order of incoming messages is not guaranteed, so we have two options:
|
25
|
-
1. Refresh the entire current_observation_set for the patient
|
26
|
-
2. Check the current observed_at date in the jsonb and only update if we have a more
|
27
|
-
recent one
|
28
|
-
We have gone for 2.
|
29
|
-
*/
|
30
|
-
|
31
|
-
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
|
32
|
-
|
33
|
-
-- Note we could re-generate the entire current pathology for the patient using
|
34
|
-
-- select refresh_current_observation_set(a_patient_id);
|
35
|
-
-- which is safer but uses more resources, so avoiding this for now.
|
36
|
-
|
37
|
-
-- Find and store patient_id into local variable
|
38
|
-
select request.patient_id into a_patient_id
|
39
|
-
from pathology_observation_requests request
|
40
|
-
where request.id = NEW.request_id;
|
41
|
-
|
42
|
-
-- Find and store the obx code into local variable
|
43
|
-
select description.code into a_code
|
44
|
-
from pathology_observation_descriptions description
|
45
|
-
where description.id = NEW.description_id;
|
46
|
-
|
47
|
-
-- Important! Create the observation_set if it doesn't exist yet
|
48
|
-
-- ignore the error if the row already exists
|
49
|
-
insert into pathology_current_observation_sets (patient_id)
|
50
|
-
values (a_patient_id)
|
51
|
-
ON CONFLICT DO NOTHING;
|
52
|
-
|
53
|
-
-- We are going to compare the current and new observed_at dates
|
54
|
-
-- so need to cast them to a timestamp
|
55
|
-
select cast(New.observed_at as timestamp) into new_observed_at;
|
56
|
-
|
57
|
-
-- Get the most recent date and value for this observation
|
58
|
-
-- and store to variables.
|
59
|
-
select
|
60
|
-
cast(values -> a_code ->> 'observed_at' as timestamp),
|
61
|
-
values -> a_code ->> 'result'
|
62
|
-
into current_observed_at, current_result from
|
63
|
-
pathology_current_observation_sets
|
64
|
-
where patient_id = a_patient_id;
|
65
|
-
|
66
|
-
-- Output some info to helps us debug. This can be removed later.
|
67
|
-
RAISE NOTICE ' Request id % Patient id % Code %', NEW.request_id, a_patient_id, a_code;
|
68
|
-
RAISE NOTICE ' Last %: % at %', a_code, current_result, current_observed_at;
|
69
|
-
RAISE NOTICE ' New %: % at %', a_code, NEW.result, new_observed_at;
|
70
|
-
|
71
|
-
IF current_observed_at IS NULL OR new_observed_at >= current_observed_at THEN
|
72
|
-
-- The new pathology_observation row contain a more recent result that the old one.
|
73
|
-
-- (note there may not be an old one if the patient has neve had this obs before).
|
74
|
-
|
75
|
-
RAISE NOTICE ' Updating pathology_current_observation_sets..';
|
76
|
-
|
77
|
-
-- Update the values jsonb column with the new hash for this code, e.g.
|
78
|
-
-- .. {"HGB": { "result": 123.1, "observed_at": '2017-12-12-01:01:01'}, ..
|
79
|
-
-- Note the `set values` below actually reads in the jsonb, updates it,
|
80
|
-
-- and wites the whole thing back.
|
81
|
-
update pathology_current_observation_sets
|
82
|
-
set updated_at = CURRENT_TIMESTAMP,
|
83
|
-
values = jsonb_set(
|
84
|
-
values,
|
85
|
-
('{'||a_code||'}')::text[], -- defined in the fn path::text[]
|
86
|
-
jsonb_build_object('result', NEW.result, 'observed_at', new_observed_at),
|
87
|
-
true)
|
88
|
-
where patient_id = a_patient_id;
|
89
|
-
END IF;
|
90
|
-
END IF;
|
91
|
-
RETURN NULL ;
|
92
|
-
END $body$ LANGUAGE plpgsql VOLATILE COST 100;
|
93
|
-
-- End function
|
94
|
-
SQL
|
95
|
-
ActiveRecord::Base.connection.execute(sql)
|
3
|
+
load_function("update_current_observation_set_from_trigger_v02.sql")
|
96
4
|
end
|
97
5
|
|
98
6
|
def down
|
99
|
-
sql
|
100
|
-
CREATE OR REPLACE FUNCTION update_current_observation_set_from_trigger() RETURNS TRIGGER AS $body$
|
101
|
-
-- TC 14/12/2017
|
102
|
-
-- This function is called by a trigger when a row is inserted or updated in
|
103
|
-
-- pathology_observations. Its purpose is to keep current_observation_sets up to date
|
104
|
-
-- with the latest observations for any patient.
|
105
|
-
-- The current_observation_sets table maintains a jsonb hash into which we insert or replace
|
106
|
-
-- the observation, keyed by OBX code.
|
107
|
-
-- e.g. .. {"HGB": { "result": 123.1, "observed_at": '2017-12-12-01:01:01'}, ..
|
108
|
-
DECLARE
|
109
|
-
a_patient_id bigint;
|
110
|
-
a_code text;
|
111
|
-
current_observed_at timestamp;
|
112
|
-
current_result text;
|
113
|
-
new_observed_at timestamp;
|
114
|
-
BEGIN
|
115
|
-
RAISE NOTICE 'TRIGGER called on %',TG_TABLE_NAME ;
|
116
|
-
|
117
|
-
/*
|
118
|
-
If inserting or updating, we _could_ assume the last observation to be inserted is
|
119
|
-
the most 'recent' one (with the latest observed_at date).
|
120
|
-
However the order of incoming messages is not guaranteed, so we have two options:
|
121
|
-
1. Refresh the entire current_observation_set for the patient
|
122
|
-
2. Check the current observed_at date in the jsonb and only update if we have a more
|
123
|
-
recent one
|
124
|
-
We have gone for 2.
|
125
|
-
*/
|
126
|
-
|
127
|
-
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
|
128
|
-
|
129
|
-
-- Note we could re-generate the entire current pathology for the patient using
|
130
|
-
-- select refresh_current_observation_set(a_patient_id);
|
131
|
-
-- which is safer but uses more resources, so avoiding this for now.
|
132
|
-
|
133
|
-
-- Find and store patient_id into local variable
|
134
|
-
select request.patient_id into a_patient_id
|
135
|
-
from pathology_observation_requests request
|
136
|
-
where request.id = NEW.request_id;
|
137
|
-
|
138
|
-
-- Find and store the obx code into local variable
|
139
|
-
select description.code into a_code
|
140
|
-
from pathology_observation_descriptions description
|
141
|
-
where description.id = NEW.description_id;
|
142
|
-
|
143
|
-
-- Important! Create the observation_set if it doesn exist yet
|
144
|
-
-- ignore the error id the row already exists
|
145
|
-
insert into pathology_current_observation_sets (patient_id)
|
146
|
-
values (a_patient_id)
|
147
|
-
ON CONFLICT DO NOTHING;
|
148
|
-
|
149
|
-
-- We are going to compare the current and new observed_at dates
|
150
|
-
-- so need to cast them to a timestamp
|
151
|
-
select cast(New.observed_at as timestamp) into new_observed_at;
|
152
|
-
|
153
|
-
-- Get the most recent date and value for this observation
|
154
|
-
-- and store to variables.
|
155
|
-
select
|
156
|
-
cast(values -> a_code ->> 'observed_at' as timestamp),
|
157
|
-
values -> a_code ->> 'result'
|
158
|
-
into current_observed_at, current_result from
|
159
|
-
pathology_current_observation_sets
|
160
|
-
where patient_id = a_patient_id;
|
161
|
-
|
162
|
-
-- Output some info to helps us debug. This can be removed later.
|
163
|
-
RAISE NOTICE ' Request id % Patient id % Code %', NEW.request_id, a_patient_id, a_code;
|
164
|
-
RAISE NOTICE ' Last %: % at %', a_code, current_result, current_observed_at;
|
165
|
-
RAISE NOTICE ' New %: % at %', a_code, NEW.result, new_observed_at;
|
166
|
-
|
167
|
-
IF current_observed_at IS NULL OR new_observed_at >= current_observed_at THEN
|
168
|
-
-- The new pathology_observation row contain a more recent result that the old one.
|
169
|
-
-- (note there may not be an old one if the patient has neve had this obs before).
|
170
|
-
|
171
|
-
RAISE NOTICE ' Updating pathology_current_observation_sets..';
|
172
|
-
|
173
|
-
-- Update the values jsonb column with the new hash for this code, e.g.
|
174
|
-
-- .. {"HGB": { "result": 123.1, "observed_at": '2017-12-12-01:01:01'}, ..
|
175
|
-
-- Note the `set values` below actually reads in the jsonb, updates it,
|
176
|
-
-- and wites the whole thing back.
|
177
|
-
update pathology_current_observation_sets
|
178
|
-
set values = jsonb_set(
|
179
|
-
values,
|
180
|
-
('{'||a_code||'}')::text[], -- defined in the fn path::text[]
|
181
|
-
jsonb_build_object('result', NEW.result, 'observed_at', new_observed_at),
|
182
|
-
true)
|
183
|
-
where patient_id = a_patient_id;
|
184
|
-
END IF;
|
185
|
-
END IF;
|
186
|
-
RETURN NULL ;
|
187
|
-
END $body$ LANGUAGE plpgsql VOLATILE COST 100;
|
188
|
-
SQL
|
189
|
-
ActiveRecord::Base.connection.execute(sql)
|
7
|
+
load_function("update_current_observation_set_from_trigger_v01.sql")
|
190
8
|
end
|
191
9
|
end
|