conceptql 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +226 -117
- data/LICENSE +21 -0
- data/README.md +35 -83
- data/bin/conceptql +2 -1
- data/bin/conceptql_utils +6 -0
- data/config/multiple_vocabularies.csv +4 -0
- data/config/provenance.yml +489 -0
- data/config/race.yml +50 -0
- data/config/vocabularies.csv +87 -0
- data/lib/conceptql/behaviors/code_lister.rb +23 -0
- data/lib/conceptql/behaviors/drugish.rb +17 -0
- data/lib/conceptql/behaviors/labish.rb +19 -0
- data/lib/conceptql/behaviors/metadatable.rb +226 -73
- data/lib/conceptql/behaviors/provenanceable.rb +26 -0
- data/lib/conceptql/behaviors/single_event.rb +11 -0
- data/lib/conceptql/behaviors/timeless.rb +11 -0
- data/lib/conceptql/behaviors/utilizable.rb +206 -0
- data/lib/conceptql/behaviors/windowable.rb +27 -0
- data/lib/conceptql/cli.rb +117 -108
- data/lib/conceptql/columnizer.rb +75 -0
- data/lib/conceptql/data_model/base.rb +462 -0
- data/lib/conceptql/data_model/gdm.rb +155 -0
- data/lib/conceptql/data_model/gdm_wide.rb +42 -0
- data/lib/conceptql/data_model/omopv4_plus.rb +12 -0
- data/lib/conceptql/data_model.rb +30 -0
- data/lib/conceptql/database.rb +214 -0
- data/lib/conceptql/date_adjuster.rb +66 -18
- data/lib/conceptql/diagram.rb +243 -0
- data/lib/conceptql/lexicon/lexicon_gdm.rb +47 -0
- data/lib/conceptql/lexicon/lexicon_no_db.rb +49 -0
- data/lib/conceptql/lexicon/lexicon_ohdsi.rb +63 -0
- data/lib/conceptql/lexicon/lexicon_strategy.rb +116 -0
- data/lib/conceptql/lexicon.rb +111 -0
- data/lib/conceptql/nodifier.rb +65 -24
- data/lib/conceptql/operators/after.rb +34 -14
- data/lib/conceptql/operators/any_overlap.rb +8 -6
- data/lib/conceptql/operators/before.rb +34 -10
- data/lib/conceptql/operators/binary_operator_operator.rb +66 -23
- data/lib/conceptql/operators/casting_operator.rb +51 -36
- data/lib/conceptql/operators/co_reported.rb +111 -0
- data/lib/conceptql/operators/concurrent_within.rb +69 -0
- data/lib/conceptql/operators/contains.rb +12 -8
- data/lib/conceptql/operators/count.rb +17 -9
- data/lib/conceptql/operators/date_range.rb +48 -14
- data/lib/conceptql/operators/death.rb +14 -4
- data/lib/conceptql/operators/dedup.rb +31 -0
- data/lib/conceptql/operators/during.rb +7 -12
- data/lib/conceptql/operators/episode.rb +146 -0
- data/lib/conceptql/operators/equal.rb +9 -3
- data/lib/conceptql/operators/ethnicity.rb +49 -0
- data/lib/conceptql/operators/except.rb +19 -12
- data/lib/conceptql/operators/filter.rb +23 -8
- data/lib/conceptql/operators/first.rb +16 -3
- data/lib/conceptql/operators/from.rb +52 -4
- data/lib/conceptql/operators/gender.rb +34 -11
- data/lib/conceptql/operators/hospice.rb +19 -0
- data/lib/conceptql/operators/hospitalization.rb +19 -0
- data/lib/conceptql/operators/information_periods.rb +36 -0
- data/lib/conceptql/operators/invalid.rb +35 -0
- data/lib/conceptql/operators/last.rb +16 -3
- data/lib/conceptql/operators/match.rb +91 -0
- data/lib/conceptql/operators/multiple_vocabularies.rb +172 -0
- data/lib/conceptql/operators/numeric.rb +65 -23
- data/lib/conceptql/operators/numeric_filter.rb +68 -0
- data/lib/conceptql/operators/occurrence.rb +153 -32
- data/lib/conceptql/operators/one_in_two_out.rb +237 -38
- data/lib/conceptql/operators/operator.rb +624 -178
- data/lib/conceptql/operators/pass_thru.rb +17 -3
- data/lib/conceptql/operators/person.rb +18 -6
- data/lib/conceptql/operators/person_filter.rb +9 -3
- data/lib/conceptql/operators/place_of_service_filter.rb +43 -0
- data/lib/conceptql/operators/provenance.rb +55 -0
- data/lib/conceptql/operators/provider_filter.rb +62 -0
- data/lib/conceptql/operators/race.rb +55 -7
- data/lib/conceptql/operators/read.rb +168 -0
- data/lib/conceptql/operators/recall.rb +49 -14
- data/lib/conceptql/operators/snf.rb +19 -0
- data/lib/conceptql/operators/sum.rb +29 -12
- data/lib/conceptql/operators/temporal_operator.rb +108 -16
- data/lib/conceptql/operators/time_window.rb +20 -32
- data/lib/conceptql/operators/trim_date.rb +71 -0
- data/lib/conceptql/operators/trim_date_end.rb +28 -40
- data/lib/conceptql/operators/trim_date_start.rb +28 -41
- data/lib/conceptql/operators/union.rb +67 -6
- data/lib/conceptql/operators/vocabulary.rb +151 -0
- data/lib/conceptql/paths.rb +41 -0
- data/lib/conceptql/query.rb +191 -26
- data/lib/conceptql/query_modifiers/gdm/admission_date_query_modifier.rb +46 -0
- data/lib/conceptql/query_modifiers/gdm/drug_query_modifier.rb +54 -0
- data/lib/conceptql/query_modifiers/gdm/lab_query_modifier.rb +57 -0
- data/lib/conceptql/query_modifiers/gdm/pos_query_modifier.rb +46 -0
- data/lib/conceptql/query_modifiers/gdm/provenance_query_modifier.rb +45 -0
- data/lib/conceptql/query_modifiers/gdm/provider_query_modifier.rb +53 -0
- data/lib/conceptql/query_modifiers/gdm_wide/admission_date_query_modifier.rb +42 -0
- data/lib/conceptql/query_modifiers/gdm_wide/drug_query_modifier.rb +52 -0
- data/lib/conceptql/query_modifiers/gdm_wide/lab_query_modifier.rb +55 -0
- data/lib/conceptql/query_modifiers/gdm_wide/pos_query_modifier.rb +37 -0
- data/lib/conceptql/query_modifiers/gdm_wide/provenance_query_modifier.rb +38 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/admission_date_query_modifier.rb +45 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/drug_query_modifier.rb +80 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/pos_query_modifier.rb +47 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/provenance_query_modifier.rb +45 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/provider_query_modifier.rb +26 -0
- data/lib/conceptql/query_modifiers/query_modifier.rb +20 -0
- data/lib/conceptql/rdbms/duckdb.rb +25 -0
- data/lib/conceptql/rdbms/generic.rb +120 -0
- data/lib/conceptql/rdbms/postgres.rb +51 -0
- data/lib/conceptql/rdbms/spark.rb +22 -0
- data/lib/conceptql/rdbms.rb +22 -0
- data/lib/conceptql/scope.rb +481 -31
- data/lib/conceptql/sql_formatters/formatter.rb +25 -0
- data/lib/conceptql/sql_formatters.rb +22 -0
- data/lib/conceptql/utils.rb +113 -0
- data/lib/conceptql/utils_cli.rb +17 -0
- data/lib/conceptql/version.rb +3 -1
- data/lib/conceptql/visitors/metadata_extractor.rb +54 -0
- data/lib/conceptql/vocabularies/behaviors/costish.rb +24 -0
- data/lib/conceptql/vocabularies/behaviors/gdmish.rb +19 -0
- data/lib/conceptql/vocabularies/behaviors/omopish.rb +32 -0
- data/lib/conceptql/vocabularies/dynamic_vocabularies.rb +63 -0
- data/lib/conceptql/vocabularies/entry.rb +138 -0
- data/lib/conceptql/vocabularies/vocabulary_class_factory.rb +85 -0
- data/lib/conceptql/window/base.rb +26 -0
- data/lib/conceptql/window/date_range.rb +25 -0
- data/lib/conceptql/window/table.rb +116 -0
- data/lib/conceptql/window.rb +72 -0
- data/lib/conceptql.rb +65 -2
- data/lib/sequel/extensions/pg_ctas_explain.rb +22 -0
- data/lib/sequel/extensions/pg_vacuum_table.rb +23 -0
- data/schemas/gdm.yml +882 -0
- data/schemas/gdm_wide.yml +757 -0
- data/schemas/ohdsi_vocabs.yml +143 -0
- data/schemas/omopv4_plus.yml +729 -0
- data/schemas/omopv4_plus_more_ignorables.tsv +13 -0
- metadata +267 -207
- data/.gitignore +0 -23
- data/Gemfile +0 -4
- data/Guardfile +0 -56
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -1
- data/conceptql.gemspec +0 -32
- data/doc/ConceptQL Specification (alpha).pdf +0 -0
- data/doc/diagram_0.png +0 -0
- data/doc/implementation_notes.md +0 -39
- data/doc/spec.md +0 -1344
- data/lib/conceptql/behaviors/debuggable.rb +0 -70
- data/lib/conceptql/behaviors/dottable.rb +0 -103
- data/lib/conceptql/behaviors/preppable.rb +0 -20
- data/lib/conceptql/converter.rb +0 -65
- data/lib/conceptql/debugger.rb +0 -48
- data/lib/conceptql/fake_grapher.rb +0 -20
- data/lib/conceptql/graph.rb +0 -52
- data/lib/conceptql/graph_nodifier.rb +0 -203
- data/lib/conceptql/logger.rb +0 -10
- data/lib/conceptql/operators/complement.rb +0 -38
- data/lib/conceptql/operators/concept.rb +0 -70
- data/lib/conceptql/operators/condition_type.rb +0 -71
- data/lib/conceptql/operators/cpt.rb +0 -25
- data/lib/conceptql/operators/drug_type_concept.rb +0 -21
- data/lib/conceptql/operators/from_seer_visits.rb +0 -23
- data/lib/conceptql/operators/hcpcs.rb +0 -25
- data/lib/conceptql/operators/icd10.rb +0 -28
- data/lib/conceptql/operators/icd9.rb +0 -28
- data/lib/conceptql/operators/icd9_procedure.rb +0 -25
- data/lib/conceptql/operators/intersect.rb +0 -34
- data/lib/conceptql/operators/loinc.rb +0 -25
- data/lib/conceptql/operators/medcode.rb +0 -28
- data/lib/conceptql/operators/medcode_procedure.rb +0 -27
- data/lib/conceptql/operators/ndc.rb +0 -29
- data/lib/conceptql/operators/observation_by_enttype.rb +0 -29
- data/lib/conceptql/operators/observation_period.rb +0 -30
- data/lib/conceptql/operators/overlapped_by.rb +0 -23
- data/lib/conceptql/operators/overlaps.rb +0 -19
- data/lib/conceptql/operators/place_of_service_code.rb +0 -24
- data/lib/conceptql/operators/procedure_occurrence.rb +0 -25
- data/lib/conceptql/operators/prodcode.rb +0 -29
- data/lib/conceptql/operators/rxnorm.rb +0 -24
- data/lib/conceptql/operators/snomed.rb +0 -24
- data/lib/conceptql/operators/snomed_condition.rb +0 -26
- data/lib/conceptql/operators/source_vocabulary_operator.rb +0 -58
- data/lib/conceptql/operators/standard_vocabulary_operator.rb +0 -45
- data/lib/conceptql/operators/started_by.rb +0 -22
- data/lib/conceptql/operators/to_seer_visits.rb +0 -24
- data/lib/conceptql/operators/visit.rb +0 -15
- data/lib/conceptql/operators/visit_occurrence.rb +0 -30
- data/lib/conceptql/tree.rb +0 -53
- data/lib/conceptql/utils/temp_table.rb +0 -72
- data/spec/conceptql/behaviors/dottable_spec.rb +0 -99
- data/spec/conceptql/converter_spec.rb +0 -51
- data/spec/conceptql/date_adjuster_spec.rb +0 -68
- data/spec/conceptql/operators/after_spec.rb +0 -16
- data/spec/conceptql/operators/before_spec.rb +0 -16
- data/spec/conceptql/operators/casting_operator_spec.rb +0 -68
- data/spec/conceptql/operators/complement_spec.rb +0 -15
- data/spec/conceptql/operators/concept_spec.rb +0 -40
- data/spec/conceptql/operators/condition_type_spec.rb +0 -128
- data/spec/conceptql/operators/contains_spec.rb +0 -19
- data/spec/conceptql/operators/cpt_spec.rb +0 -29
- data/spec/conceptql/operators/date_range_spec.rb +0 -33
- data/spec/conceptql/operators/death_spec.rb +0 -10
- data/spec/conceptql/operators/during_spec.rb +0 -30
- data/spec/conceptql/operators/except_spec.rb +0 -15
- data/spec/conceptql/operators/first_spec.rb +0 -35
- data/spec/conceptql/operators/from_spec.rb +0 -13
- data/spec/conceptql/operators/gender_spec.rb +0 -27
- data/spec/conceptql/operators/hcpcs_spec.rb +0 -29
- data/spec/conceptql/operators/icd10_spec.rb +0 -34
- data/spec/conceptql/operators/icd9_procedure_spec.rb +0 -29
- data/spec/conceptql/operators/icd9_spec.rb +0 -34
- data/spec/conceptql/operators/intersect_spec.rb +0 -28
- data/spec/conceptql/operators/last_spec.rb +0 -36
- data/spec/conceptql/operators/loinc_spec.rb +0 -29
- data/spec/conceptql/operators/medcode_procedure_spec.rb +0 -34
- data/spec/conceptql/operators/medcode_spec.rb +0 -34
- data/spec/conceptql/operators/observation_period_spec.rb +0 -10
- data/spec/conceptql/operators/occurrence_spec.rb +0 -87
- data/spec/conceptql/operators/overlapped_by_spec.rb +0 -32
- data/spec/conceptql/operators/overlaps_spec.rb +0 -21
- data/spec/conceptql/operators/person_filter_spec.rb +0 -15
- data/spec/conceptql/operators/person_spec.rb +0 -10
- data/spec/conceptql/operators/place_of_service_code_spec.rb +0 -24
- data/spec/conceptql/operators/procedure_occurrence_spec.rb +0 -10
- data/spec/conceptql/operators/prodcode_spec.rb +0 -35
- data/spec/conceptql/operators/query_double.rb +0 -20
- data/spec/conceptql/operators/query_double_spec.rb +0 -7
- data/spec/conceptql/operators/race_spec.rb +0 -21
- data/spec/conceptql/operators/rxnorm_spec.rb +0 -29
- data/spec/conceptql/operators/snomed_spec.rb +0 -29
- data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +0 -35
- data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +0 -35
- data/spec/conceptql/operators/started_by_spec.rb +0 -22
- data/spec/conceptql/operators/temporal_operator_spec.rb +0 -51
- data/spec/conceptql/operators/time_window_spec.rb +0 -77
- data/spec/conceptql/operators/union_spec.rb +0 -21
- data/spec/conceptql/operators/visit_occurrence_spec.rb +0 -10
- data/spec/conceptql/query_spec.rb +0 -22
- data/spec/conceptql/tree_spec.rb +0 -50
- data/spec/doubles/stream_for_casting_double.rb +0 -9
- data/spec/doubles/stream_for_occurrence_double.rb +0 -25
- data/spec/doubles/stream_for_temporal_double.rb +0 -6
- data/spec/spec_helper.rb +0 -102
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require "psych"
|
|
5
|
+
|
|
6
|
+
module ConceptQL
|
|
7
|
+
module DataModel
|
|
8
|
+
class Base
|
|
9
|
+
extend Forwardable
|
|
10
|
+
def_delegators :nodifier, :cdb
|
|
11
|
+
def_delegators :cdb, :lexicon, :source_table_exists?
|
|
12
|
+
def_delegators :lexicon,
|
|
13
|
+
:concept_codes,
|
|
14
|
+
:concept_ids,
|
|
15
|
+
:concept_ids_by_name,
|
|
16
|
+
:concepts,
|
|
17
|
+
:concepts_table,
|
|
18
|
+
:concepts_by_name,
|
|
19
|
+
:concepts_ds,
|
|
20
|
+
:concepts_to_codes,
|
|
21
|
+
:descendants_of,
|
|
22
|
+
:known_codes,
|
|
23
|
+
:related_concept_ids
|
|
24
|
+
|
|
25
|
+
SCHEMAS = ConceptQL.schemas_dir.glob("*.yml").to_h do |schema_file|
|
|
26
|
+
[ schema_file.basename(".*").to_s.to_sym, Psych.load_file(schema_file) ]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attr_reader :operator, :nodifier
|
|
30
|
+
|
|
31
|
+
def initialize(operator, nodifier)
|
|
32
|
+
@operator = operator
|
|
33
|
+
@nodifier = nodifier
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def rdbms
|
|
37
|
+
@rdbms ||= ConceptQL::Rdbms.generate(nodifier.database_type)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The concept table that the display-name joins read. It is the
|
|
41
|
+
# Database's name_concepts_table when it has one, and the full concept
|
|
42
|
+
# table otherwise (bead conceptql-auu, seed conceptql-8u6).
|
|
43
|
+
def name_concepts_table(db)
|
|
44
|
+
table = cdb.opts[:name_concepts_table]
|
|
45
|
+
return concepts_table(db) unless table
|
|
46
|
+
|
|
47
|
+
db[table]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The data columns whose concept ids the display-name joins look up, by
|
|
51
|
+
# table. A data model without those joins has none.
|
|
52
|
+
def name_concept_columns
|
|
53
|
+
{}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def query_modifier_for(column)
|
|
57
|
+
{
|
|
58
|
+
visit_source_concept_id: ConceptQL::QueryModifiers::Omopv4Plus::PoSQueryModifier,
|
|
59
|
+
provider_id: ConceptQL::QueryModifiers::Omopv4Plus::ProviderQueryModifier,
|
|
60
|
+
context_specialty_concept_id: ConceptQL::QueryModifiers::Omopv4Plus::ProviderQueryModifier,
|
|
61
|
+
drug_name: ConceptQL::QueryModifiers::Omopv4Plus::DrugQueryModifier,
|
|
62
|
+
admission_date: ConceptQL::QueryModifiers::Omopv4Plus::AdmissionDateQueryModifier,
|
|
63
|
+
provenance_type: ConceptQL::QueryModifiers::Omopv4Plus::ProvenanceQueryModifier
|
|
64
|
+
}[column]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def criterion_id
|
|
68
|
+
:criterion_id
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def table_id(table = nil)
|
|
72
|
+
return :person_id if table.to_sym == :death
|
|
73
|
+
|
|
74
|
+
:criterion_id if table.nil?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def person_table
|
|
78
|
+
:person
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def make_table_id(table)
|
|
82
|
+
"#{table}_id".to_sym
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def make_fk_id(table)
|
|
86
|
+
make_table_id(table)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def person_id(table)
|
|
90
|
+
case table.to_sym
|
|
91
|
+
when :procedure_cost, :drug_cost
|
|
92
|
+
nil
|
|
93
|
+
else
|
|
94
|
+
:person_id
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def schema
|
|
99
|
+
SCHEMAS[data_model]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def data_model
|
|
103
|
+
:omopv4_plus
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def pk_by_domain(domain)
|
|
107
|
+
case domain.to_sym
|
|
108
|
+
when :death
|
|
109
|
+
:person_id
|
|
110
|
+
when :procedure_cost
|
|
111
|
+
:procedure_occurrence_id
|
|
112
|
+
when :drug_cost
|
|
113
|
+
:drug_exposure_id
|
|
114
|
+
else
|
|
115
|
+
"#{domain}_id".to_sym
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def fk_by_domain(domain)
|
|
120
|
+
"#{domain}_id".to_sym
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def query_columns
|
|
124
|
+
@query_columns ||= Hash[operator.scope.query_columns.zip(operator.scope.query_columns)]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def columns(opts = {})
|
|
128
|
+
table = get_table(opts)
|
|
129
|
+
|
|
130
|
+
cols_hash = if table.nil? && opts[:query_columns].nil?
|
|
131
|
+
query_columns
|
|
132
|
+
else
|
|
133
|
+
columns_in_table(table,
|
|
134
|
+
opts).merge(modifier_columns(table,
|
|
135
|
+
opts)).merge(nullified_columns(table, opts))
|
|
136
|
+
end.dup
|
|
137
|
+
|
|
138
|
+
except_keys = opts[:except] || []
|
|
139
|
+
if cols_hash.key?(:uuid)
|
|
140
|
+
if opts[:uuid]
|
|
141
|
+
except_keys << :uuid
|
|
142
|
+
elsif table
|
|
143
|
+
cols_hash.merge!(uuid: Sequel.cast(nil, String).as(:uuid))
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
col_keys = cols_hash.keys
|
|
147
|
+
col_keys -= except_keys
|
|
148
|
+
col_keys &= opts[:only] if opts[:only]
|
|
149
|
+
|
|
150
|
+
if (qualifier = opts[:qualifier])
|
|
151
|
+
cols_hash = cols_hash.transform_values { |c| Sequel.qualify(qualifier, c) }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
cols_hash.merge!(replace(opts[:replace]))
|
|
155
|
+
cols_hash.values_at(*col_keys)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def modifier_columns(table, opts = {})
|
|
159
|
+
return {} if table.nil? && opts[:query_columns].nil?
|
|
160
|
+
|
|
161
|
+
remainder = query_columns.keys - (opts[:query_columns] ? opts[:query_columns].keys : columns_in_table(table).keys)
|
|
162
|
+
Hash[remainder.zip(remainder)]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def nullified_columns(table, opts = {})
|
|
166
|
+
return {} if table.nil? && opts[:query_columns].nil?
|
|
167
|
+
|
|
168
|
+
remainder = query_columns.keys
|
|
169
|
+
if opts[:query_columns]
|
|
170
|
+
remainder -= opts[:query_columns].keys
|
|
171
|
+
else
|
|
172
|
+
remainder -= table_cols(table)
|
|
173
|
+
remainder -= columns_in_table(table).keys
|
|
174
|
+
remainder -= applicable_query_modifiers(table).flat_map(&:provided_columns)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
Hash[remainder.map { |r| [ r, rdbms.process(r, nil) ] }]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def selectify(query, opts = {})
|
|
181
|
+
ds = modify_query(query, get_table(opts)).select(*columns(opts))
|
|
182
|
+
ds = ds.from_self.select_append(rdbms.uuid.as(:uuid)) if opts[:uuid]
|
|
183
|
+
ds.from_self
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def get_table(opts)
|
|
187
|
+
opts[:table] || table_by_domain(opts[:domain])
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def modify_query(query, table)
|
|
191
|
+
return query if table.nil?
|
|
192
|
+
|
|
193
|
+
applicable_query_modifiers(table).each do |klass|
|
|
194
|
+
query = klass.new(query, operator, table, self).modified_query
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
query
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def applicable_query_modifiers(table)
|
|
201
|
+
query_modifiers.values_at(*query_columns.keys).compact.select do |klass|
|
|
202
|
+
klass.has_required_columns?(table_cols(table))
|
|
203
|
+
end.uniq
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def query_modifiers
|
|
207
|
+
{
|
|
208
|
+
visit_source_concept_id: query_modifier_for(:visit_source_concept_id),
|
|
209
|
+
provider_id: query_modifier_for(:provider_id),
|
|
210
|
+
context_specialty_concept_id: query_modifier_for(:context_specialty_concept_id),
|
|
211
|
+
drug_name: query_modifier_for(:drug_name),
|
|
212
|
+
file_provenance_type: query_modifier_for(:provenance_type),
|
|
213
|
+
admission_date: query_modifier_for(:admission_date),
|
|
214
|
+
value_as_number: query_modifier_for(:value_as_number)
|
|
215
|
+
}
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def columns_in_table(table, opts = {})
|
|
219
|
+
return opts[:query_columns] unless opts[:query_columns].nil?
|
|
220
|
+
|
|
221
|
+
start_date, end_date = *date_columns(nil, table)
|
|
222
|
+
{
|
|
223
|
+
person_id: Sequel.expr(person_id(table)).as(:person_id),
|
|
224
|
+
criterion_id: Sequel.identifier(pk_by_domain(table)).as(:criterion_id),
|
|
225
|
+
criterion_table: Sequel.cast_string(table.to_s).as(:criterion_table),
|
|
226
|
+
criterion_domain: Sequel.cast_string((opts[:criterion_domain] || table_to_domain(table) || table).to_s).as(:criterion_domain),
|
|
227
|
+
start_date: start_date,
|
|
228
|
+
end_date: end_date,
|
|
229
|
+
source_value: Sequel.cast_string(source_value_column(table)).as(:source_value),
|
|
230
|
+
source_vocabulary_id: Sequel.cast_string(source_vocabulary_id(table)).as(:source_vocabulary_id)
|
|
231
|
+
}
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def table_to_domain(table)
|
|
235
|
+
table
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def replace(replace_hash)
|
|
239
|
+
return {} unless replace_hash
|
|
240
|
+
|
|
241
|
+
replace_hash.each_with_object({}) do |(column, value), h|
|
|
242
|
+
h[column] = rdbms.process(column, value)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def place_of_service_concept_id(query, domain)
|
|
247
|
+
place_of_service_concept_id_column(query, domain)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def determine_table(table_method)
|
|
251
|
+
return nil unless operator.respond_to?(table_method)
|
|
252
|
+
|
|
253
|
+
table = table_by_domain(operator.send(table_method))
|
|
254
|
+
table if schema.keys.include?(table)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def assign_column_to_table
|
|
258
|
+
schema.each_with_object({}) do |(table, table_info), cols|
|
|
259
|
+
columns_info = table_info[:columns]
|
|
260
|
+
column = yield table, columns_info.keys.map(&:to_s)
|
|
261
|
+
cols[table] = column ? column.to_sym : nil
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def start_date_columns
|
|
266
|
+
@start_date_columns ||= assign_column_to_table do |_table, columns|
|
|
267
|
+
column = columns.select { |k| k =~ /start_date$/ }.first
|
|
268
|
+
column || columns.select { |k| k =~ /date$/ }.first
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def end_date_columns
|
|
273
|
+
@end_date_columns ||= assign_column_to_table do |_table, columns|
|
|
274
|
+
column = columns.select { |k| k =~ /end_date$/ }.first
|
|
275
|
+
column || columns.select { |k| k =~ /date$/ }.first
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def start_date_column(query, domain)
|
|
280
|
+
start_date_columns.merge(person: person_date_of_birth(query))[domain]
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def end_date_column(query, domain)
|
|
284
|
+
end_date_columns.merge(person: person_date_of_birth(query))[domain]
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def source_value_columns
|
|
288
|
+
@source_value_columns ||= assign_column_to_table do |table, columns|
|
|
289
|
+
reggy = /#{table.to_s.split('_').first}_source_value$/
|
|
290
|
+
column = columns.select { |k| k =~ reggy }.first
|
|
291
|
+
column || columns.select { |k| k =~ /source_value$/ }.first
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def source_vocabulary_ids
|
|
296
|
+
@source_vocabulary_ids = assign_column_to_table do |table, columns|
|
|
297
|
+
next if %w[person death].any? { |tn| table.to_s =~ /#{tn}/ }
|
|
298
|
+
|
|
299
|
+
reggy = /#{table.to_s.split('_').first}_source_vocabulary_id/
|
|
300
|
+
column = columns.select { |k| k =~ reggy }.first
|
|
301
|
+
column || columns.select { |k| k =~ /_source_vocabulary_id/ }.first
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def id_columns
|
|
306
|
+
@id_columns ||= assign_column_to_table do |table, columns|
|
|
307
|
+
reggy = /#{table}_id/
|
|
308
|
+
columns.select { |k| k =~ reggy }.first
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def id_column(table)
|
|
313
|
+
id_columns[table]
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def type_concept_id_columns
|
|
317
|
+
@type_concept_id_columns ||= assign_column_to_table do |_table, columns|
|
|
318
|
+
columns.select { |c| c =~ /_type_concept_id$/ }.first
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def type_concept_id_column(domain)
|
|
323
|
+
type_concept_id_columns[table_by_domain(domain)]
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def table_by_domain(domain)
|
|
327
|
+
domain
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def period_table
|
|
331
|
+
:observation_period
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def source_value_column(table)
|
|
335
|
+
source_value_columns[table]
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def code_provenance_type_column(_query, domain)
|
|
339
|
+
{
|
|
340
|
+
condition_occurrence: :condition_type_concept_id,
|
|
341
|
+
death: :death_type_concept_id,
|
|
342
|
+
drug_exposure: :drug_type_concept_id,
|
|
343
|
+
observation: :observation_type_concept_id,
|
|
344
|
+
procedure_occurrence: :procedure_type_concept_id
|
|
345
|
+
}[domain]
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def file_provenance_type_column(_query, domain)
|
|
349
|
+
{
|
|
350
|
+
condition_occurrence: :condition_type_concept_id,
|
|
351
|
+
death: :death_type_concept_id,
|
|
352
|
+
drug_exposure: :drug_type_concept_id,
|
|
353
|
+
observation: :observation_type_concept_id,
|
|
354
|
+
procedure_occurrence: :procedure_type_concept_id
|
|
355
|
+
}[domain]
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def provider_id_column(_query, domain)
|
|
359
|
+
{
|
|
360
|
+
condition_occurrence: :associated_provider_id,
|
|
361
|
+
death: :death_type_concept_id,
|
|
362
|
+
drug_exposure: :prescribing_provider_id,
|
|
363
|
+
observation: :associated_provider_id,
|
|
364
|
+
person: :provider_id,
|
|
365
|
+
procedure_occurrence: :associated_provider_id,
|
|
366
|
+
provider: :provider_id
|
|
367
|
+
}[domain]
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def place_of_service_concept_id_column(_query, domain)
|
|
371
|
+
return nil if domain.nil?
|
|
372
|
+
return Sequel.cast(:visit_source_concept_id, :Bigint) if table_cols(domain).include?(pos_table_fk)
|
|
373
|
+
|
|
374
|
+
nil
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def pos_table_fk
|
|
378
|
+
:visit_occurrence_id
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def person_date_of_birth(_query)
|
|
382
|
+
rdbms.cast_date(ConceptQL::Utils.assemble_date(:year_of_birth, :month_of_birth, :day_of_birth,
|
|
383
|
+
database_type: nodifier.database_type))
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def date_columns(query, table = nil)
|
|
387
|
+
sd = start_date_column(query, table)
|
|
388
|
+
sd = rdbms.cast_date(Sequel.expr(sd)).as(:start_date) unless sd == :start_date
|
|
389
|
+
ed = end_date_column(query, table)
|
|
390
|
+
unless ed == :end_date
|
|
391
|
+
ed = rdbms.cast_date(Sequel.function(:coalesce, Sequel.expr(ed),
|
|
392
|
+
start_date_column(query, table))).as(:end_date)
|
|
393
|
+
end
|
|
394
|
+
[ sd, ed ]
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def table_to_sym(table)
|
|
398
|
+
case table
|
|
399
|
+
when Symbol
|
|
400
|
+
table = Sequel.split_symbol(table)[1].to_sym if Sequel.split_symbols?
|
|
401
|
+
when Sequel::SQL::AliasedExpression
|
|
402
|
+
table = table.expression
|
|
403
|
+
when Sequel::SQL::QualifiedIdentifier
|
|
404
|
+
table = table.column
|
|
405
|
+
when Sequel::SQL::Identifier
|
|
406
|
+
table = table.value
|
|
407
|
+
end
|
|
408
|
+
table.to_sym
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def table_cols(table)
|
|
412
|
+
table = table_to_sym(table)
|
|
413
|
+
schema.fetch(table)[:columns].keys
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def table_columns(*tables)
|
|
417
|
+
tables.map { |t| table_cols(t) }.flatten.tap do |o|
|
|
418
|
+
p o
|
|
419
|
+
p tables
|
|
420
|
+
end
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def table_source_value(table)
|
|
424
|
+
source_value_columns.fetch(table_to_sym(table))
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def source_vocabulary_id(table)
|
|
428
|
+
source_vocabulary_ids[table_to_sym(table)]
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def table_is_missing?(db)
|
|
432
|
+
!(source_table_exists?(db, :observation_period) && source_table_exists?(db, :condition_occurrence))
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def concept_id(table)
|
|
436
|
+
table_cols(table).find do |col|
|
|
437
|
+
col = col.to_s
|
|
438
|
+
next unless col =~ /concept_id/
|
|
439
|
+
|
|
440
|
+
table_parts = table.to_s.chomp("s").to_s.split("_")
|
|
441
|
+
|
|
442
|
+
possible_names = [ "concept_id" ]
|
|
443
|
+
|
|
444
|
+
until table_parts.empty?
|
|
445
|
+
possible_names.unshift([ table_parts.join("_"), possible_names.last ].join("_"))
|
|
446
|
+
table_parts.pop
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
possible_names.any? do |name|
|
|
450
|
+
col == name
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
def information_period_where_clause(arguments)
|
|
456
|
+
return if arguments.empty?
|
|
457
|
+
|
|
458
|
+
{ plan_source_value: arguments }
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module ConceptQL
|
|
6
|
+
module DataModel
|
|
7
|
+
class Gdm < Base
|
|
8
|
+
def query_modifier_for(column)
|
|
9
|
+
{
|
|
10
|
+
visit_source_concept_id: ConceptQL::QueryModifiers::Gdm::PoSQueryModifier,
|
|
11
|
+
provider_id: ConceptQL::QueryModifiers::Gdm::ProviderQueryModifier,
|
|
12
|
+
context_specialty_concept_id: ConceptQL::QueryModifiers::Gdm::ProviderQueryModifier,
|
|
13
|
+
drug_name: ConceptQL::QueryModifiers::Gdm::DrugQueryModifier,
|
|
14
|
+
admission_date: ConceptQL::QueryModifiers::Gdm::AdmissionDateQueryModifier,
|
|
15
|
+
provenance_type: ConceptQL::QueryModifiers::Gdm::ProvenanceQueryModifier,
|
|
16
|
+
value_as_number: ConceptQL::QueryModifiers::Gdm::LabQueryModifier
|
|
17
|
+
}[column]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def person_id(table = nil)
|
|
21
|
+
return :id if table == :patients
|
|
22
|
+
|
|
23
|
+
:patient_id
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def person_table
|
|
27
|
+
:patients
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def period_table
|
|
31
|
+
:information_periods
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def criterion_id
|
|
35
|
+
Sequel.expr(:id).as(:criterion_id)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def table_id(table = nil)
|
|
39
|
+
return :criterion_id if table.nil?
|
|
40
|
+
|
|
41
|
+
Sequel.expr(make_table_id(table)).as(:criterion_id)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def make_table_id(_table)
|
|
45
|
+
:id
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def fk_by_domain(domain)
|
|
49
|
+
table = table_by_domain(domain)
|
|
50
|
+
"#{table.to_s.gsub(/_id/, '').chomp('s')}_id".to_sym
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def pk_by_domain(_domain)
|
|
54
|
+
:id
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def base
|
|
58
|
+
:gdm
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def name_concept_columns
|
|
62
|
+
{
|
|
63
|
+
clinical_codes: %i[clinical_code_concept_id],
|
|
64
|
+
drug_exposure_details: %i[dose_unit_concept_id],
|
|
65
|
+
measurement_details: %i[unit_concept_id result_as_concept_id],
|
|
66
|
+
admission_details: %i[admit_source_concept_id discharge_location_concept_id]
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def table_by_domain(table)
|
|
71
|
+
return nil unless table
|
|
72
|
+
|
|
73
|
+
case table
|
|
74
|
+
when :person, :patients
|
|
75
|
+
:patients
|
|
76
|
+
when :death, :deaths
|
|
77
|
+
:deaths
|
|
78
|
+
when :observation_period, :information_periods
|
|
79
|
+
:information_periods
|
|
80
|
+
when :provider, :practitioners
|
|
81
|
+
:practitioners
|
|
82
|
+
when :collections
|
|
83
|
+
:collections
|
|
84
|
+
else
|
|
85
|
+
:clinical_codes
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def table_to_domain(table)
|
|
90
|
+
{
|
|
91
|
+
patients: :person,
|
|
92
|
+
deaths: :death,
|
|
93
|
+
information_periods: :observation_period,
|
|
94
|
+
practitioners: :provider
|
|
95
|
+
}[table]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def data_model
|
|
99
|
+
:gdm
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def start_date_column(_query, domain)
|
|
103
|
+
start_date_columns[domain]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def end_date_column(_query, domain)
|
|
107
|
+
end_date_columns[domain]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def id_column(_table)
|
|
111
|
+
:id
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def pos_table_fk
|
|
115
|
+
:context_id
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def source_vocabulary_ids
|
|
119
|
+
@source_vocabulary_ids = assign_column_to_table do |table, columns|
|
|
120
|
+
next if %w[patients death].any? { |tn| table.to_s =~ /#{tn}/ }
|
|
121
|
+
|
|
122
|
+
reggy = /#{table.to_s.split('_').first}_vocabulary_id/
|
|
123
|
+
column = columns.select { |k| k =~ reggy }.first
|
|
124
|
+
column || columns.select { |k| k =~ /_vocabulary_id/ }.first
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def information_period_where_clause(arguments)
|
|
129
|
+
return if arguments.empty?
|
|
130
|
+
|
|
131
|
+
{ information_type_concept_id: arguments.map(&:to_i) }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def code_provenance_type(_query, _domain)
|
|
135
|
+
:provenance_concept_id
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def file_provenance_type(_query, _domain)
|
|
139
|
+
:source_type_concept_id
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def file_provenance_types_vocab
|
|
143
|
+
%w[JIGSAW_FILE_PROVENANCE_TYPE JS_FILE_PROV_TYPE]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def code_provenance_types_vocab
|
|
147
|
+
%w[JIGSAW_CODE_PROVENANCE_TYPE JS_CODE_PROV_TYPE]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def table_is_missing?(db)
|
|
151
|
+
!(source_table_exists?(db, :patients) && source_table_exists?(db, :clinical_codes))
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "gdm"
|
|
4
|
+
|
|
5
|
+
module ConceptQL
|
|
6
|
+
module DataModel
|
|
7
|
+
class GdmWide < Gdm
|
|
8
|
+
def query_modifier_for(column)
|
|
9
|
+
{
|
|
10
|
+
visit_source_concept_id: ConceptQL::QueryModifiers::GdmWide::PoSQueryModifier,
|
|
11
|
+
provider_id: ConceptQL::QueryModifiers::Gdm::ProviderQueryModifier,
|
|
12
|
+
context_specialty_concept_id: ConceptQL::QueryModifiers::Gdm::ProviderQueryModifier,
|
|
13
|
+
drug_name: ConceptQL::QueryModifiers::GdmWide::DrugQueryModifier,
|
|
14
|
+
admission_date: ConceptQL::QueryModifiers::GdmWide::AdmissionDateQueryModifier,
|
|
15
|
+
provenance_type: ConceptQL::QueryModifiers::GdmWide::ProvenanceQueryModifier,
|
|
16
|
+
value_as_number: ConceptQL::QueryModifiers::GdmWide::LabQueryModifier
|
|
17
|
+
}[column]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def table_by_domain(table)
|
|
21
|
+
tab = super(table)
|
|
22
|
+
tab = :observations if %i[clinical_codes collections].include?(tab)
|
|
23
|
+
tab
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def data_model
|
|
27
|
+
:gdm_wide
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def name_concept_columns
|
|
31
|
+
{
|
|
32
|
+
observations: %i[clinical_code_concept_id dose_unit_concept_id unit_concept_id result_as_concept_id
|
|
33
|
+
admit_source_concept_id discharge_location_concept_id]
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def table_is_missing?(db)
|
|
38
|
+
!source_table_exists?(db, :observations)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "data_model/gdm"
|
|
4
|
+
require_relative "data_model/gdm_wide"
|
|
5
|
+
require_relative "data_model/omopv4_plus"
|
|
6
|
+
require_relative "rdbms"
|
|
7
|
+
|
|
8
|
+
module ConceptQL
|
|
9
|
+
module DataModel
|
|
10
|
+
def self.get(data_model, opts = {})
|
|
11
|
+
operator = opts[:operator]
|
|
12
|
+
nodifier = opts[:nodifier]
|
|
13
|
+
|
|
14
|
+
case data_model
|
|
15
|
+
when :gdm
|
|
16
|
+
Gdm.new(operator, nodifier)
|
|
17
|
+
when :gdm_wide
|
|
18
|
+
GdmWide.new(operator, nodifier)
|
|
19
|
+
when :omopv4_plus
|
|
20
|
+
Omopv4Plus.new(operator, nodifier)
|
|
21
|
+
else
|
|
22
|
+
raise "No DataModel defined for #{data_model.inspect}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.for(operator, nodifier)
|
|
27
|
+
get(nodifier.data_model, nodifier: nodifier, operator: operator)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|