This test case demonstrates the construction of a domain specific
language specific to the generation of OHDSI Cohorts. To get started,
we'll import some boilerplate definitions. This will create the
DataKnot called sp10
that represents our test database.
include("copybook.jl")
We implement the cohort definition as found in found in 1770676.sql
that was produced by the JSON found in 1770676.json
.
This cohort defines 3 concept sets: (a) a diagnosis of hypertension, (b) exposure to a hypertension drug, and (c) exposure to thiazide-like diuretic.
@define is_hypertensive =
iscoded("SNOMED", 38341003)
@define is_hypertension_drug =
iscoded("RxNorm", 149, 325646, 17767, 1091643, 11170,
644, 1202, 18867, 1520, 19484, 1808, 214354, 1998, 20352,
2409, 2599, 3443, 49276, 3827, 298869, 83515, 4316, 50166,
4603, 40114, 5470, 5487, 5764, 83818, 33910, 6185, 29046,
52175, 6876, 6916, 6918, 6984, 30131, 7226, 31555, 7396,
7417, 7435, 321064, 7973, 54552, 8332, 8629, 8787, 35208,
35296, 9997, 73494, 37798, 38413, 38454, 10763, 69749)
@define is_thiazine_diuretic =
iscoded("RxNorm", 6916, 5487, 5764, 2409)
The initial event is described as:
People having any of the following: a drug exposure of Thiazide or thiazide-like diuretic3 for the first time in the person's history
@define candidate_events = begin
person.keep(it)
first(begin
drug_exposure
filter(concept.is_thiazine_diuretic)
sort(start_date)
end)
keep(index_date => start_date)
end
@query sp10 candidate_events{ person, index_date }
#=>
│ person index_date │
──┼────────────────────┼
1 │ 1780 2009-03-02 │
2 │ 37455 2009-08-17 │
3 │ 72120 2009-02-25 │
4 │ 95538 2010-01-20 │
5 │ 107680 2009-07-06 │
=#
with continuous observation of at least 365 days prior and 0 days after event index date, and limit initial events to: earliest event per person
This can be written by creating a new interval from the index_date
which includes the prior 365 days.
@define with_continuous_observation = begin
keep(continuous_observation =>
person.observation_period.
filter(includes(index_date.and_previous(365days))).
is0to1())
filter(exists(continuous_observation))
end
@query sp10 begin
candidate_events
with_continuous_observation
{ person,
period_start => continuous_observation.start_date,
index_date,
period_end => continuous_observation.end_date }
end
#=>
│ person period_start index_date period_end │
──┼──────────────────────────────────────────────┼
1 │ 1780 2008-02-23 2009-03-02 2009-08-01 │
2 │ 37455 2008-01-15 2009-08-17 2010-09-30 │
3 │ 72120 2008-02-12 2009-02-25 2010-01-28 │
4 │ 95538 2008-02-22 2010-01-20 2010-05-19 │
5 │ 107680 2008-02-09 2009-07-06 2010-12-30 │
=#
Inclusion Criteria #1: has hypertension diagnosis in 1 yr prior to treatment having all of the following criteria: at least 1 occurrences of a condition occurrence of Hypertensive disorder where event starts between 365 days Before and 0 days After index start date
@define with_hypertension_diagnoses = begin
keep(hypertension_diagnoses =>
person.condition.filter(concept.is_hypertensive &&
start_date.during(index_date.and_previous(365days))))
filter(exists(hypertension_diagnoses))
end
@query sp10 begin
candidate_events
with_continuous_observation
with_hypertension_diagnoses
{ person, index_date,
hypertension_diagnoses =>
hypertension_diagnoses.start_date }
end
#=>
│ person index_date hypertension_diagnoses │
──┼────────────────────────────────────────────┼
1 │ 1780 2009-03-02 2008-11-22 │
2 │ 37455 2009-08-17 2008-10-30 │
3 │ 72120 2009-02-25 2008-12-15 │
4 │ 95538 2010-01-20 2009-09-02 │
5 │ 107680 2009-07-06 2009-06-07 │
=#
Inclusion Criteria #2: Has no prior antihypertensive drug exposures in medical history having all of the following criteria: exactly 0 occurrences of a drug exposure of Hypertension drugs where event starts between all days Before and 1 days Before index start date
@define no_prior_antihypertensive =
filter(!exists(
person.drug_exposure.filter(
concept.is_hypertension_drug &&
start_date < index_date)))
@query sp10 begin
candidate_events
with_continuous_observation
with_hypertension_diagnoses
no_prior_antihypertensive
{ person, index_date}
end
#=>
│ person index_date │
──┼────────────────────┼
1 │ 1780 2009-03-02 │
2 │ 37455 2009-08-17 │
3 │ 72120 2009-02-25 │
4 │ 95538 2010-01-20 │
5 │ 107680 2009-07-06 │
=#
Inclusion Criteria #3: Is only taking Thiazide as a monotherapy, with no concomitant combination treatments having all of the following criteria: exactly 1 distinct occurrences of a drug era of Hypertension drugs where event starts between 0 days Before and 7 days After index start date
@define with_monotherapy_7day_era = begin
keep(monotherapy_7day_era =>
person.drug_era.filter(
concept.is_hypertension_drug &&
start_date.during(index_date.and_subsequent(7days))))
filter(1 == count(monotherapy_7day_era))
keep(monotherapy_7day_era => monotherapy_7day_era.is1to1())
filter(monotherapy_7day_era.concept.is_thiazine_diuretic)
end
@query sp10 begin
candidate_events
with_continuous_observation
with_hypertension_diagnoses
no_prior_antihypertensive
with_monotherapy_7day_era
{ person, index_date,
era_start => monotherapy_7day_era.start_date,
era_end => monotherapy_7day_era.end_date }
end
#=>
│ person index_date era_start era_end │
──┼────────────────────────────────────────────┼
1 │ 1780 2009-03-02 2009-03-02 2009-04-01 │
2 │ 37455 2009-08-17 2009-08-17 2009-09-16 │
3 │ 72120 2009-02-25 2009-02-25 2009-03-27 │
4 │ 95538 2010-01-20 2010-01-20 2010-02-19 │
5 │ 107680 2009-07-06 2009-07-06 2009-08-05 │
=#
This strategy creates a drug era from the codes found in the specified concept set. If the index event is found within an era, the cohort end date will use the era's end date. Otherwise, it will use the observation period end date that contains the index event. Use the era end date of ACE inhibitors: allowing 30 days between exposures, adding 0 days after exposure end. Then, collapse cohort by era with a gap size of 0 days
The logic specified in the textual description above is unclear, by reverse engineering the SQL source, we come up with something like... which happens to give same results as previous.
@define with_custom_era =
keep(custom_era => begin
person.drug_exposure
filter((concept.is_thiazine_diuretic ||
source_concept.is_thiazine_diuretic) &&
start_date >= index_date)
{ start_date,
end_date => coalesce(end_date,
start_date + days_supply,
start_date + 1days) }
collapse_intervals(30days)
first()
end)
@query sp10 begin
candidate_events
with_continuous_observation
with_hypertension_diagnoses
no_prior_antihypertensive
with_monotherapy_7day_era
with_custom_era
{ person,
cohort_enter_date => custom_era.start_date,
cohort_exit_date => custom_era.end_date }
end
#=>
│ person cohort_enter_date cohort_exit_date │
──┼─────────────────────────────────────────────┼
1 │ 1780 2009-03-02 2009-04-01 │
2 │ 37455 2009-08-17 2009-09-16 │
3 │ 72120 2009-02-25 2009-03-27 │
4 │ 95538 2010-01-20 2010-02-19 │
5 │ 107680 2009-07-06 2009-08-05 │
=#