1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
|
-- ==============================================================
-- GNUmed database schema change script
--
-- License: GPL v2 or later
-- Author: karsten.hilbert@gmx.net
--
-- ==============================================================
\set ON_ERROR_STOP 1
--set default_transaction_read_only to off;
set check_function_bodies to on;
-- --------------------------------------------------------------
comment on column clin.substance_intake.comment_on_start is 'Comment (uncertainty level) on .clin_when = started. "?" = "entirely unknown".';
alter table clin.substance_intake
alter column comment_on_start
set default NULL;
alter table clin.substance_intake
drop constraint if exists clin_substance_intake_sane_start_comment;
alter table clin.substance_intake
add constraint clin_substance_intake_sane_start_comment check (
gm.is_null_or_non_empty_string(comment_on_start)
);
-- --------------------------------------------------------------
comment on column clin.substance_intake.harmful_use_type is
'NULL=not considered=medication, 0=no or not considered harmful, 1=presently harmful use, 2=presently addicted, 3=previously addicted';
alter table clin.substance_intake
drop constraint if exists clin_patient_sane_use_type;
alter table clin.substance_intake
add constraint clin_patient_sane_use_type check (
(harmful_use_type IS NULL)
OR
(harmful_use_type between 0 and 3)
);
-- --------------------------------------------------------------
-- .fk_substance / .fk_drug_component
drop function if exists clin.trf_update_intake_updates_all_drug_components() cascade;
drop function if exists clin.trf_upd_intake_updates_all_drug_components() cascade;
create or replace function clin.trf_upd_intake_updates_all_drug_components()
returns trigger
language 'plpgsql'
as '
DECLARE
_pk_brand integer;
_component_count integer;
_pk_patient integer;
BEGIN
-- which drug ?
select fk_brand into _pk_brand
from ref.lnk_substance2brand
where pk = NEW.fk_drug_component;
-- how many components therein ?
select count(1) into _component_count
from ref.lnk_substance2brand
where fk_brand = _pk_brand;
-- only one component ?
if _component_count = 1 then
return NEW;
end if;
-- which patient ?
select fk_patient into _pk_patient
from clin.encounter
where pk = NEW.fk_encounter;
-- update all substance instake fields shared by drug components ...
update clin.substance_intake set
clin_when = NEW.clin_when, -- started
fk_encounter = NEW.fk_encounter,
soap_cat = NEW.soap_cat,
schedule = NEW.schedule,
duration = NEW.duration,
intake_is_approved_of = NEW.intake_is_approved_of,
is_long_term = NEW.is_long_term,
discontinued = NEW.discontinued
where
-- ... which belong to this drug ...
fk_drug_component in (
select pk from ref.lnk_substance2brand where fk_brand = _pk_brand
)
AND
-- ... but are not THIS component ...
fk_drug_component != NEW.fk_drug_component
AND
-- ... this patient ...
fk_encounter in (
select pk from clin.encounter where fk_patient = _pk_patient
)
AND
-- ... are different in value (this will stop recursion as soon as all are equal)
(
clin_when is distinct from NEW.clin_when
OR
fk_encounter is distinct from NEW.fk_encounter
OR
soap_cat is distinct from NEW.soap_cat
OR
schedule is distinct from NEW.schedule
OR
duration is distinct from NEW.duration
OR
intake_is_approved_of is distinct from NEW.intake_is_approved_of
OR
is_long_term is distinct from NEW.is_long_term
OR
discontinued is distinct from NEW.discontinued
)
;
return NEW;
END;';
comment on function clin.trf_upd_intake_updates_all_drug_components() is
'If a drug component substance intake is updated all sibling components must receive some values thereof.';
create constraint trigger tr_upd_intake_updates_all_drug_components
after update on clin.substance_intake
deferrable
initially deferred
for each row when (
(pg_trigger_depth() = 0)
and
(NEW.fk_drug_component is not null)
)
execute procedure clin.trf_upd_intake_updates_all_drug_components();
-- --------------------------------------------------------------
drop function if exists clin.trf_insert_update_intake_prevent_duplicate_substance_links() cascade;
drop function if exists clin.trf_ins_upd_intake_prevent_duplicate_substance_links() cascade;
create or replace function clin.trf_ins_upd_intake_prevent_duplicate_substance_links()
returns trigger
language 'plpgsql'
as '
DECLARE
_pk_patient integer;
_link_count integer;
_msg text;
BEGIN
-- which patient ?
select fk_patient into _pk_patient
from clin.encounter
where pk = NEW.fk_encounter;
-- more than one link ?
select count(1) into _link_count
from clin.substance_intake
where
-- for this substance
fk_substance = NEW.fk_substance
and
-- either already linked as component OR
-- already linked as substance
fk_drug_component IS NOT DISTINCT FROM NEW.fk_drug_component
and
-- in this one patient
fk_encounter in (
select pk from clin.encounter where fk_patient = _pk_patient
)
;
if _link_count > 1 then
_msg := ''[clin.trf_ins_upd_intake_prevent_duplicate_substance_links]: substance ref.consumable_substance.pk=('' || NEW.fk_substance || '') ''
|| ''already linked to patient=('' || _pk_patient || '') '';
raise exception unique_violation using message = _msg;
end if;
return NEW;
END;';
comment on function clin.trf_ins_upd_intake_prevent_duplicate_substance_links() is
'Prevent patient from being put on a particular substance more than once.';
create constraint trigger tr_ins_upd_intake_prevent_duplicate_substance_links
after insert or update on clin.substance_intake
deferrable
initially deferred
for each row execute procedure clin.trf_ins_upd_intake_prevent_duplicate_substance_links()
;
-- --------------------------------------------------------------
drop function if exists clin.trf_ins_intake_set_substance_from_component() cascade;
create function clin.trf_ins_intake_set_substance_from_component()
returns trigger
language 'plpgsql'
as '
BEGIN
-- load fk_substance from drug_component table
select
r_ls2b.fk_substance into strict NEW.fk_substance
from
ref.lnk_substance2brand r_ls2b
where
r_ls2b.pk = NEW.fk_drug_component
;
return NEW;
END;';
comment on function clin.trf_ins_intake_set_substance_from_component() is
'On INSERT of a substance intake set fk_substance from fk_drug_component if the latter is NOT NULL.';
create trigger tr_ins_intake_set_substance_from_component
before INSERT on clin.substance_intake
for each row when (NEW.fk_drug_component is not null)
execute procedure clin.trf_ins_intake_set_substance_from_component();
-- --------------------------------------------------------------
drop function if exists clin.trf_upd_intake_set_substance_from_component() cascade;
create function clin.trf_upd_intake_set_substance_from_component()
returns trigger
language 'plpgsql'
as '
BEGIN
-- load fk_substance from drug_component table
select
r_ls2b.fk_substance into strict NEW.fk_substance
from
ref.lnk_substance2brand r_ls2b
where
r_ls2b.pk = NEW.fk_drug_component
;
return NEW;
END;';
comment on function clin.trf_upd_intake_set_substance_from_component() is
'On UPDATE of a substance intake set fk_substance from fk_drug_component if the latter changes.';
create trigger tr_upd_intake_set_substance_from_component
before UPDATE on clin.substance_intake
for each row when (
(NEW.fk_drug_component is not null)
and
(NEW.fk_drug_component is distinct from OLD.fk_drug_component)
)
execute procedure clin.trf_upd_intake_set_substance_from_component();
-- --------------------------------------------------------------
alter table clin.substance_intake
drop constraint if exists clin_subst_intake_either_drug_or_substance cascade;
-- --------------------------------------------------------------
-- normalize existing records
update clin.substance_intake set
fk_substance = (
select r_ls2b.fk_substance
from ref.lnk_substance2brand r_ls2b
where r_ls2b.pk = fk_drug_component
)
where
fk_substance is null
;
-- --------------------------------------------------------------
alter table clin.substance_intake
alter column fk_substance
set not null;
-- --------------------------------------------------------------
-- DELETE substance intake
drop function if exists clin.trf_delete_intake_document_deleted() cascade;
create function clin.trf_delete_intake_document_deleted()
returns trigger
language 'plpgsql'
as '
DECLARE
_row record;
_pk_episode integer;
BEGIN
select
* into _row
from
clin.v_substance_intake_journal
where
src_pk = OLD.pk;
_pk_episode := _row.pk_episode;
-- create episode if needed
if _pk_episode is null then
select pk into _pk_episode
from clin.episode
where
description = _(''Medication history'')
and
fk_encounter in (
select pk from clin.encounter where fk_patient = _row.pk_patient
);
if not found then
insert into clin.episode (
description,
is_open,
fk_encounter
) values (
_(''Medication history''),
FALSE,
OLD.fk_encounter
) returning pk into _pk_episode;
end if;
end if;
insert into clin.clin_narrative (
fk_encounter,
fk_episode,
soap_cat,
narrative
) values (
_row.pk_encounter,
_pk_episode,
NULL,
_(''Deletion of'') || '' '' || _row.narrative
);
return OLD;
END;';
comment on function clin.trf_delete_intake_document_deleted() is
'Document the deletion of a substance intake.';
create trigger tr_delete_intake_document_deleted
before delete on clin.substance_intake
for each row execute procedure clin.trf_delete_intake_document_deleted();
-- --------------------------------------------------------------
select gm.log_script_insertion('v21-clin-substance_intake-dynamic.sql', '21.0');
|