conceptql 0.1.1 → 0.2.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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +53 -1
- data/Guardfile +52 -24
- data/conceptql.gemspec +5 -3
- data/doc/spec.md +2 -2
- data/lib/conceptql/behaviors/debuggable.rb +70 -0
- data/lib/conceptql/behaviors/dottable.rb +28 -14
- data/lib/conceptql/behaviors/metadatable.rb +97 -0
- data/lib/conceptql/behaviors/preppable.rb +20 -0
- data/lib/conceptql/cli.rb +31 -5
- data/lib/conceptql/converter.rb +65 -0
- data/lib/conceptql/debugger.rb +48 -0
- data/lib/conceptql/graph.rb +14 -13
- data/lib/conceptql/graph_nodifier.rb +49 -17
- data/lib/conceptql/nodifier.rb +31 -6
- data/lib/conceptql/operators/after.rb +25 -0
- data/lib/conceptql/operators/any_overlap.rb +15 -0
- data/lib/conceptql/operators/before.rb +21 -0
- data/lib/conceptql/{nodes/binary_operator_node.rb → operators/binary_operator_operator.rb} +12 -8
- data/lib/conceptql/{nodes/casting_node.rb → operators/casting_operator.rb} +8 -7
- data/lib/conceptql/{nodes → operators}/complement.rb +14 -11
- data/lib/conceptql/operators/concept.rb +70 -0
- data/lib/conceptql/{nodes → operators}/condition_type.rb +13 -5
- data/lib/conceptql/operators/contains.rb +17 -0
- data/lib/conceptql/operators/count.rb +26 -0
- data/lib/conceptql/operators/cpt.rb +25 -0
- data/lib/conceptql/{nodes → operators}/date_range.rb +11 -6
- data/lib/conceptql/operators/death.rb +23 -0
- data/lib/conceptql/operators/drug_type_concept.rb +21 -0
- data/lib/conceptql/{nodes → operators}/during.rb +9 -3
- data/lib/conceptql/operators/equal.rb +13 -0
- data/lib/conceptql/operators/except.rb +28 -0
- data/lib/conceptql/operators/filter.rb +21 -0
- data/lib/conceptql/{nodes → operators}/first.rb +7 -5
- data/lib/conceptql/{nodes → operators}/from.rb +2 -2
- data/lib/conceptql/operators/from_seer_visits.rb +23 -0
- data/lib/conceptql/{nodes → operators}/gender.rb +6 -6
- data/lib/conceptql/operators/hcpcs.rb +25 -0
- data/lib/conceptql/operators/icd10.rb +28 -0
- data/lib/conceptql/operators/icd9.rb +28 -0
- data/lib/conceptql/operators/icd9_procedure.rb +25 -0
- data/lib/conceptql/{nodes → operators}/intersect.rb +7 -3
- data/lib/conceptql/{nodes → operators}/last.rb +7 -5
- data/lib/conceptql/operators/loinc.rb +25 -0
- data/lib/conceptql/operators/medcode.rb +28 -0
- data/lib/conceptql/operators/medcode_procedure.rb +27 -0
- data/lib/conceptql/operators/ndc.rb +29 -0
- data/lib/conceptql/operators/numeric.rb +54 -0
- data/lib/conceptql/operators/observation_by_enttype.rb +29 -0
- data/lib/conceptql/operators/observation_period.rb +30 -0
- data/lib/conceptql/operators/occurrence.rb +70 -0
- data/lib/conceptql/operators/one_in_two_out.rb +62 -0
- data/lib/conceptql/{nodes/node.rb → operators/operator.rb} +84 -52
- data/lib/conceptql/operators/overlapped_by.rb +23 -0
- data/lib/conceptql/operators/overlaps.rb +19 -0
- data/lib/conceptql/operators/pass_thru.rb +11 -0
- data/lib/conceptql/{nodes → operators}/person.rb +8 -4
- data/lib/conceptql/operators/person_filter.rb +13 -0
- data/lib/conceptql/{nodes → operators}/place_of_service_code.rb +7 -7
- data/lib/conceptql/operators/procedure_occurrence.rb +25 -0
- data/lib/conceptql/operators/prodcode.rb +29 -0
- data/lib/conceptql/{nodes → operators}/race.rb +7 -7
- data/lib/conceptql/operators/recall.rb +38 -0
- data/lib/conceptql/operators/rxnorm.rb +24 -0
- data/lib/conceptql/operators/snomed.rb +24 -0
- data/lib/conceptql/operators/snomed_condition.rb +26 -0
- data/lib/conceptql/{nodes/source_vocabulary_node.rb → operators/source_vocabulary_operator.rb} +7 -4
- data/lib/conceptql/{nodes/standard_vocabulary_node.rb → operators/standard_vocabulary_operator.rb} +6 -4
- data/lib/conceptql/{nodes → operators}/started_by.rb +9 -3
- data/lib/conceptql/{nodes → operators}/sum.rb +9 -4
- data/lib/conceptql/{nodes/temporal_node.rb → operators/temporal_operator.rb} +7 -4
- data/lib/conceptql/{nodes → operators}/time_window.rb +19 -7
- data/lib/conceptql/operators/to_seer_visits.rb +24 -0
- data/lib/conceptql/operators/trim_date_end.rb +55 -0
- data/lib/conceptql/operators/trim_date_start.rb +56 -0
- data/lib/conceptql/{nodes → operators}/union.rb +6 -2
- data/lib/conceptql/operators/visit.rb +15 -0
- data/lib/conceptql/{nodes → operators}/visit_occurrence.rb +7 -3
- data/lib/conceptql/query.rb +19 -17
- data/lib/conceptql/scope.rb +69 -0
- data/lib/conceptql/tree.rb +33 -18
- data/lib/conceptql/utils/temp_table.rb +72 -0
- data/lib/conceptql/version.rb +1 -1
- data/spec/conceptql/behaviors/dottable_spec.rb +39 -51
- data/spec/conceptql/converter_spec.rb +51 -0
- data/spec/conceptql/date_adjuster_spec.rb +15 -15
- data/spec/conceptql/operators/after_spec.rb +16 -0
- data/spec/conceptql/operators/before_spec.rb +16 -0
- data/spec/conceptql/{nodes/casting_node_spec.rb → operators/casting_operator_spec.rb} +16 -20
- data/spec/conceptql/operators/complement_spec.rb +15 -0
- data/spec/conceptql/operators/concept_spec.rb +40 -0
- data/spec/conceptql/{nodes → operators}/condition_type_spec.rb +39 -24
- data/spec/conceptql/operators/contains_spec.rb +19 -0
- data/spec/conceptql/operators/cpt_spec.rb +29 -0
- data/spec/conceptql/operators/date_range_spec.rb +33 -0
- data/spec/conceptql/operators/death_spec.rb +10 -0
- data/spec/conceptql/operators/during_spec.rb +30 -0
- data/spec/conceptql/operators/except_spec.rb +15 -0
- data/spec/conceptql/operators/first_spec.rb +35 -0
- data/spec/conceptql/operators/from_spec.rb +13 -0
- data/spec/conceptql/operators/gender_spec.rb +27 -0
- data/spec/conceptql/operators/hcpcs_spec.rb +29 -0
- data/spec/conceptql/operators/icd10_spec.rb +34 -0
- data/spec/conceptql/operators/icd9_procedure_spec.rb +29 -0
- data/spec/conceptql/operators/icd9_spec.rb +34 -0
- data/spec/conceptql/operators/intersect_spec.rb +28 -0
- data/spec/conceptql/operators/last_spec.rb +36 -0
- data/spec/conceptql/operators/loinc_spec.rb +29 -0
- data/spec/conceptql/operators/medcode_procedure_spec.rb +34 -0
- data/spec/conceptql/operators/medcode_spec.rb +34 -0
- data/spec/conceptql/operators/observation_period_spec.rb +10 -0
- data/spec/conceptql/operators/occurrence_spec.rb +87 -0
- data/spec/conceptql/operators/overlapped_by_spec.rb +32 -0
- data/spec/conceptql/operators/overlaps_spec.rb +21 -0
- data/spec/conceptql/operators/person_filter_spec.rb +15 -0
- data/spec/conceptql/operators/person_spec.rb +10 -0
- data/spec/conceptql/{nodes → operators}/place_of_service_code_spec.rb +6 -8
- data/spec/conceptql/operators/procedure_occurrence_spec.rb +10 -0
- data/spec/conceptql/operators/prodcode_spec.rb +35 -0
- data/spec/conceptql/operators/query_double.rb +20 -0
- data/spec/conceptql/operators/query_double_spec.rb +7 -0
- data/spec/conceptql/operators/race_spec.rb +21 -0
- data/spec/conceptql/operators/rxnorm_spec.rb +29 -0
- data/spec/conceptql/operators/snomed_spec.rb +29 -0
- data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +35 -0
- data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +35 -0
- data/spec/conceptql/operators/started_by_spec.rb +22 -0
- data/spec/conceptql/{nodes/temporal_node_spec.rb → operators/temporal_operator_spec.rb} +11 -17
- data/spec/conceptql/operators/time_window_spec.rb +77 -0
- data/spec/conceptql/operators/union_spec.rb +21 -0
- data/spec/conceptql/operators/visit_occurrence_spec.rb +10 -0
- data/spec/conceptql/query_spec.rb +10 -9
- data/spec/conceptql/tree_spec.rb +24 -28
- data/spec/doubles/stream_for_casting_double.rb +1 -1
- data/spec/doubles/stream_for_occurrence_double.rb +1 -1
- data/spec/doubles/stream_for_temporal_double.rb +1 -1
- data/spec/spec_helper.rb +74 -58
- metadata +202 -133
- data/lib/conceptql/nodes/after.rb +0 -12
- data/lib/conceptql/nodes/before.rb +0 -11
- data/lib/conceptql/nodes/concept.rb +0 -38
- data/lib/conceptql/nodes/count.rb +0 -23
- data/lib/conceptql/nodes/cpt.rb +0 -20
- data/lib/conceptql/nodes/death.rb +0 -19
- data/lib/conceptql/nodes/define.rb +0 -96
- data/lib/conceptql/nodes/drug_type_concept.rb +0 -18
- data/lib/conceptql/nodes/equal.rb +0 -11
- data/lib/conceptql/nodes/except.rb +0 -11
- data/lib/conceptql/nodes/hcpcs.rb +0 -20
- data/lib/conceptql/nodes/icd10.rb +0 -23
- data/lib/conceptql/nodes/icd9.rb +0 -23
- data/lib/conceptql/nodes/icd9_procedure.rb +0 -20
- data/lib/conceptql/nodes/loinc.rb +0 -20
- data/lib/conceptql/nodes/numeric.rb +0 -40
- data/lib/conceptql/nodes/occurrence.rb +0 -49
- data/lib/conceptql/nodes/pass_thru.rb +0 -11
- data/lib/conceptql/nodes/person_filter.rb +0 -12
- data/lib/conceptql/nodes/procedure_occurrence.rb +0 -21
- data/lib/conceptql/nodes/recall.rb +0 -50
- data/lib/conceptql/nodes/rxnorm.rb +0 -20
- data/lib/conceptql/nodes/snomed.rb +0 -19
- data/lib/conceptql/nodes/visit.rb +0 -11
- data/spec/conceptql/nodes/after_spec.rb +0 -18
- data/spec/conceptql/nodes/before_spec.rb +0 -18
- data/spec/conceptql/nodes/complement_spec.rb +0 -15
- data/spec/conceptql/nodes/concept_spec.rb +0 -34
- data/spec/conceptql/nodes/cpt_spec.rb +0 -31
- data/spec/conceptql/nodes/date_range_spec.rb +0 -35
- data/spec/conceptql/nodes/death_spec.rb +0 -12
- data/spec/conceptql/nodes/during_spec.rb +0 -32
- data/spec/conceptql/nodes/except_spec.rb +0 -18
- data/spec/conceptql/nodes/first_spec.rb +0 -37
- data/spec/conceptql/nodes/from_spec.rb +0 -15
- data/spec/conceptql/nodes/gender_spec.rb +0 -29
- data/spec/conceptql/nodes/hcpcs_spec.rb +0 -31
- data/spec/conceptql/nodes/icd10_spec.rb +0 -36
- data/spec/conceptql/nodes/icd9_procedure_spec.rb +0 -31
- data/spec/conceptql/nodes/icd9_spec.rb +0 -36
- data/spec/conceptql/nodes/intersect_spec.rb +0 -33
- data/spec/conceptql/nodes/last_spec.rb +0 -38
- data/spec/conceptql/nodes/loinc_spec.rb +0 -31
- data/spec/conceptql/nodes/occurrence_spec.rb +0 -89
- data/spec/conceptql/nodes/person_filter_spec.rb +0 -18
- data/spec/conceptql/nodes/person_spec.rb +0 -12
- data/spec/conceptql/nodes/procedure_occurrence_spec.rb +0 -12
- data/spec/conceptql/nodes/query_double.rb +0 -19
- data/spec/conceptql/nodes/race_spec.rb +0 -23
- data/spec/conceptql/nodes/rxnorm_spec.rb +0 -31
- data/spec/conceptql/nodes/snomed_spec.rb +0 -31
- data/spec/conceptql/nodes/source_vocabulary_node_spec.rb +0 -37
- data/spec/conceptql/nodes/standard_vocabulary_node_spec.rb +0 -40
- data/spec/conceptql/nodes/started_by_spec.rb +0 -25
- data/spec/conceptql/nodes/time_window_spec.rb +0 -85
- data/spec/conceptql/nodes/union_spec.rb +0 -25
- data/spec/conceptql/nodes/visit_occurrence_spec.rb +0 -12
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/date_range'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::DateRange do
|
|
5
|
+
it_behaves_like(:evaluator)
|
|
6
|
+
|
|
7
|
+
describe '#types' do
|
|
8
|
+
it 'should be [:date]' do
|
|
9
|
+
expect(ConceptQL::Operators::DateRange.new(start: '2004-12-13', end: '2010-03-20').types).to eq([:person])
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '#query' do
|
|
14
|
+
it 'should be dates specified assigned to all persons' do
|
|
15
|
+
expect(ConceptQL::Operators::DateRange.new(start: '2004-12-13', end: '2010-03-20').query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT *, CAST('person' AS varchar(255)) AS criterion_type, person_id AS criterion_id, date '2004-12-13' AS start_date, date '2010-03-20' AS end_date FROM person) AS t1")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'should handle strings for option keys' do
|
|
19
|
+
expect(ConceptQL::Operators::DateRange.new('start' => '2004-12-13', 'end' => '2010-03-20').query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT *, CAST('person' AS varchar(255)) AS criterion_type, person_id AS criterion_id, date '2004-12-13' AS start_date, date '2010-03-20' AS end_date FROM person) AS t1")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'handles START as day before first recorded observation_period' do
|
|
23
|
+
expect(ConceptQL::Operators::DateRange.new(start: 'START', end: '2010-03-20').query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT *, CAST('person' AS varchar(255)) AS criterion_type, person_id AS criterion_id, (SELECT min(observation_period_start_date) FROM observation_period) AS start_date, date '2010-03-20' AS end_date FROM person) AS t1")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'handles END as last date of recorded observation_period' do
|
|
27
|
+
expect(ConceptQL::Operators::DateRange.new(start: '2004-12-13', end: 'END').query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT *, CAST('person' AS varchar(255)) AS criterion_type, person_id AS criterion_id, date '2004-12-13' AS start_date, (SELECT max(observation_period_end_date) FROM observation_period) AS end_date FROM person) AS t1")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/during'
|
|
3
|
+
require_double('stream_for_temporal')
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::During do
|
|
6
|
+
it_behaves_like(:temporal_operator)
|
|
7
|
+
|
|
8
|
+
describe 'when not inclusive' do
|
|
9
|
+
subject do
|
|
10
|
+
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should use proper where clause' do
|
|
14
|
+
expect(subject.query(Sequel.mock).sql).to match('l.end_date <= r.end_date')
|
|
15
|
+
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.start_date')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe 'when inclusive' do
|
|
20
|
+
subject do
|
|
21
|
+
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new, inclusive: true)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should use proper where clause' do
|
|
25
|
+
expect(subject.query(Sequel.mock).sql).to match(/\(r.start_date <= l.end_date\) AND \(l.end_date <= r.end_date\)/)
|
|
26
|
+
expect(subject.query(Sequel.mock).sql).to match(/\(r.start_date <= l.start_date\) AND \(l.start_date <= r.end_date\)/)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/except'
|
|
3
|
+
require_relative 'query_double'
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::Except do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
describe '#query' do
|
|
9
|
+
it 'uses right stream as argument to EXCEPT against left stream' do
|
|
10
|
+
double1 = QueryDouble.new(1)
|
|
11
|
+
double2 = QueryDouble.new(2)
|
|
12
|
+
expect(ConceptQL::Operators::Except.new(left: double1, right: double2).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM table1 EXCEPT SELECT * FROM table2) AS t1")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/first'
|
|
3
|
+
require_double('stream_for_occurrence')
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::First do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
it 'should have occurrence pegged at 1' do
|
|
9
|
+
expect(described_class.new.occurrence).to eq(1)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe 'occurrence set to 1' do
|
|
13
|
+
subject do
|
|
14
|
+
described_class.new(StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should order by ascending start_date' do
|
|
18
|
+
expect(subject).to match('ORDER BY "start_date" ASC')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should partition by person_id' do
|
|
22
|
+
expect(subject).to match('PARTITION BY "person_id"')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should assign a row number' do
|
|
26
|
+
expect(subject).to match('row_number()')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'should find the all rows with rn = 1' do
|
|
30
|
+
expect(subject).to match('"rn" = 1')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/from'
|
|
3
|
+
require_relative 'query_double'
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::From do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
describe '#query' do
|
|
9
|
+
it 'works for single criteria' do
|
|
10
|
+
expect(ConceptQL::Operators::From.new(:table1).query(Sequel.mock).sql).to eq("SELECT * FROM table1")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/gender'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Gender do
|
|
5
|
+
it_behaves_like(:evaluator)
|
|
6
|
+
|
|
7
|
+
describe '#query' do
|
|
8
|
+
it 'works for male/MALE/Male/M/m' do
|
|
9
|
+
correct_query = "SELECT * FROM person WHERE (gender_concept_id IN (8507))"
|
|
10
|
+
expect(ConceptQL::Operators::Gender.new('male').query(Sequel.mock).sql).to eq(correct_query)
|
|
11
|
+
expect(ConceptQL::Operators::Gender.new('Male').query(Sequel.mock).sql).to eq(correct_query)
|
|
12
|
+
expect(ConceptQL::Operators::Gender.new('MALE').query(Sequel.mock).sql).to eq(correct_query)
|
|
13
|
+
expect(ConceptQL::Operators::Gender.new('M').query(Sequel.mock).sql).to eq(correct_query)
|
|
14
|
+
expect(ConceptQL::Operators::Gender.new('m').query(Sequel.mock).sql).to eq(correct_query)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'works for Female/FEMALE/female/F/f' do
|
|
18
|
+
correct_query = "SELECT * FROM person WHERE (gender_concept_id IN (8532))"
|
|
19
|
+
expect(ConceptQL::Operators::Gender.new('female').query(Sequel.mock).sql).to eq(correct_query)
|
|
20
|
+
expect(ConceptQL::Operators::Gender.new('Female').query(Sequel.mock).sql).to eq(correct_query)
|
|
21
|
+
expect(ConceptQL::Operators::Gender.new('FEMALE').query(Sequel.mock).sql).to eq(correct_query)
|
|
22
|
+
expect(ConceptQL::Operators::Gender.new('F').query(Sequel.mock).sql).to eq(correct_query)
|
|
23
|
+
expect(ConceptQL::Operators::Gender.new('f').query(Sequel.mock).sql).to eq(correct_query)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/hcpcs'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Hcpcs do
|
|
5
|
+
it_behaves_like(:standard_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
described_class.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be procedure_occurrence' do
|
|
13
|
+
expect(subject.table).to eq(:procedure_occurrence)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be procedure_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:procedure_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#vocabulary_id' do
|
|
24
|
+
it 'should be 5' do
|
|
25
|
+
expect(subject.vocabulary_id).to eq(5)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/icd10'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Icd10 do
|
|
5
|
+
it_behaves_like(:source_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
described_class.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be condition_occurrence' do
|
|
13
|
+
expect(subject.table).to eq(:condition_occurrence)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be condition_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:condition_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#source_column' do
|
|
24
|
+
it 'should be condition_source_valuej' do
|
|
25
|
+
expect(subject.source_column).to eq(:condition_source_value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#vocabulary_id' do
|
|
30
|
+
it 'should be 34' do
|
|
31
|
+
expect(subject.vocabulary_id).to eq(34)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/icd9_procedure'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Icd9Procedure do
|
|
5
|
+
it_behaves_like(:standard_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
described_class.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be procedure_occurrence' do
|
|
13
|
+
expect(subject.table).to eq(:procedure_occurrence)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be procedure_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:procedure_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#vocabulary_id' do
|
|
24
|
+
it 'should be 3' do
|
|
25
|
+
expect(subject.vocabulary_id).to eq(3)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/icd9'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Icd9 do
|
|
5
|
+
it_behaves_like(:source_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
ConceptQL::Operators::Icd9.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be condition_occurrence' do
|
|
13
|
+
expect(subject.table).to eq(:condition_occurrence)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be condition_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:condition_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#source_column' do
|
|
24
|
+
it 'should be condition_source_valuej' do
|
|
25
|
+
expect(subject.source_column).to eq(:condition_source_value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#vocabulary_id' do
|
|
30
|
+
it 'should be 2' do
|
|
31
|
+
expect(subject.vocabulary_id).to eq(2)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/intersect'
|
|
3
|
+
require_relative 'query_double'
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::Intersect do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
describe '#query' do
|
|
9
|
+
it 'works for multiple criteria of same type' do
|
|
10
|
+
double1 = QueryDouble.new(1)
|
|
11
|
+
double2 = QueryDouble.new(2)
|
|
12
|
+
double3 = QueryDouble.new(3)
|
|
13
|
+
expect(ConceptQL::Operators::Intersect.new(double1, double2, double3).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM (SELECT * FROM table1 INTERSECT SELECT * FROM table2) AS t1 INTERSECT SELECT * FROM table3) AS t1")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'works for multiple criteria of different type' do
|
|
17
|
+
double1 = QueryDouble.new(1)
|
|
18
|
+
double2 = QueryDouble.new(2, :person)
|
|
19
|
+
double3 = QueryDouble.new(3)
|
|
20
|
+
expect(ConceptQL::Operators::Intersect.new(double1, double2, double3).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM (SELECT * FROM table1 INTERSECT SELECT * FROM table3) AS t1 UNION ALL SELECT * FROM table2) AS t1")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'works for single criteria' do
|
|
24
|
+
double1 = QueryDouble.new(1)
|
|
25
|
+
expect(ConceptQL::Operators::Intersect.new(double1).query(Sequel.mock).sql).to eq("SELECT * FROM table1")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/last'
|
|
3
|
+
require_double('stream_for_occurrence')
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::Last do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
it 'should have occurrence pegged at -1' do
|
|
9
|
+
expect(described_class.new.occurrence).to eq(-1)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe 'occurrence set to -1' do
|
|
13
|
+
subject do
|
|
14
|
+
described_class.new(StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
it 'should order by descending start_date' do
|
|
19
|
+
expect(subject).to match('ORDER BY "start_date" DESC')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'should partition by person_id' do
|
|
23
|
+
expect(subject).to match('PARTITION BY "person_id"')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'should assign a row number' do
|
|
27
|
+
expect(subject).to match('row_number()')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'should find the all rows with rn = 1' do
|
|
31
|
+
expect(subject).to match('"rn" = 1')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/loinc'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Loinc do
|
|
5
|
+
it_behaves_like(:standard_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
described_class.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be observation' do
|
|
13
|
+
expect(subject.table).to eq(:observation)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be procedure_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:observation_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#vocabulary_id' do
|
|
24
|
+
it 'should be 6' do
|
|
25
|
+
expect(subject.vocabulary_id).to eq(6)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/medcode_procedure'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::MedcodeProcedure do
|
|
5
|
+
it_behaves_like(:source_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
described_class.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be procedure_occurrence' do
|
|
13
|
+
expect(subject.table).to eq(:procedure_occurrence)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be procedure_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:procedure_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#source_column' do
|
|
24
|
+
it 'should be procedure_source_valuej' do
|
|
25
|
+
expect(subject.source_column).to eq(:procedure_source_value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#vocabulary_id' do
|
|
30
|
+
it 'should be 204 (a J&J provided mapping as part of CPRD)' do
|
|
31
|
+
expect(subject.vocabulary_id).to eq(204)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/medcode'
|
|
3
|
+
|
|
4
|
+
describe ConceptQL::Operators::Medcode do
|
|
5
|
+
it_behaves_like(:source_vocabulary_operator)
|
|
6
|
+
|
|
7
|
+
subject do
|
|
8
|
+
described_class.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#table' do
|
|
12
|
+
it 'should be condition_occurrence' do
|
|
13
|
+
expect(subject.table).to eq(:condition_occurrence)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '#concept_column' do
|
|
18
|
+
it 'should be condition_concept_id' do
|
|
19
|
+
expect(subject.concept_column).to eq(:condition_concept_id)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#source_column' do
|
|
24
|
+
it 'should be condition_source_valuej' do
|
|
25
|
+
expect(subject.source_column).to eq(:condition_source_value)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#vocabulary_id' do
|
|
30
|
+
it 'should be 203 (a J&J provided mapping as part of CPRD)' do
|
|
31
|
+
expect(subject.vocabulary_id).to eq(203)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/occurrence'
|
|
3
|
+
require_double('stream_for_occurrence')
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::Occurrence do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
describe 'occurrence set to 1' do
|
|
9
|
+
subject do
|
|
10
|
+
described_class.new(1, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should order by ascending start_date' do
|
|
14
|
+
expect(subject).to match('ORDER BY "start_date" ASC')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should partition by person_id' do
|
|
18
|
+
expect(subject).to match('PARTITION BY "person_id"')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'should assign a row number' do
|
|
22
|
+
expect(subject).to match('row_number()')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should find the all rows with "rn" = 1' do
|
|
26
|
+
expect(subject).to match('"rn" = 1')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe 'occurrence set to 2' do
|
|
31
|
+
subject do
|
|
32
|
+
described_class.new(2, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'should order by ascending start_date' do
|
|
36
|
+
expect(subject).to match('ORDER BY "start_date" ASC')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'should find the all rows with "rn" = 2' do
|
|
40
|
+
expect(subject).to match('"rn" = 2')
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe 'occurrence set to -1' do
|
|
45
|
+
subject do
|
|
46
|
+
described_class.new(-1, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'should order by ascending start_date' do
|
|
50
|
+
expect(subject).to match('ORDER BY "start_date" DESC')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'should find the all rows with "rn" = 1' do
|
|
54
|
+
expect(subject).to match('"rn" = 1')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe 'occurrence set to -2' do
|
|
59
|
+
subject do
|
|
60
|
+
described_class.new(-2, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'should order by ascending start_date' do
|
|
64
|
+
expect(subject).to match('ORDER BY "start_date" DESC')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'should find the all rows with "rn" = 2' do
|
|
68
|
+
expect(subject).to match('"rn" = 2')
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe 'occurrence respects types' do
|
|
73
|
+
subject do
|
|
74
|
+
dub = StreamForOccurrenceDouble.new
|
|
75
|
+
def dub.types
|
|
76
|
+
[:condition_occurrence]
|
|
77
|
+
end
|
|
78
|
+
described_class.new(-2, dub).query(Sequel.mock(host: 'postgres')).sql
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'should order by ascending start_date' do
|
|
82
|
+
expect(subject).to match(', "criterion_type", "criterion_id"')
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/overlapped_by'
|
|
3
|
+
require_double('stream_for_temporal')
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::OverlappedBy do
|
|
6
|
+
it_behaves_like(:temporal_operator)
|
|
7
|
+
|
|
8
|
+
describe 'when not inclusive' do
|
|
9
|
+
subject do
|
|
10
|
+
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should use proper where clause' do
|
|
14
|
+
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.end_date')
|
|
15
|
+
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.start_date')
|
|
16
|
+
expect(subject.query(Sequel.mock).sql).to match('r.end_date <= l.end_date')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe 'when inclusive' do
|
|
21
|
+
subject do
|
|
22
|
+
described_class.new(inclusive: true, left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'should use proper where clause' do
|
|
26
|
+
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.end_date')
|
|
27
|
+
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.start_date')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/overlaps'
|
|
3
|
+
require_double('stream_for_temporal')
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::Overlaps do
|
|
6
|
+
it_behaves_like(:temporal_operator)
|
|
7
|
+
|
|
8
|
+
describe 'when not inclusive' do
|
|
9
|
+
subject do
|
|
10
|
+
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'should use proper where clause' do
|
|
14
|
+
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.end_date')
|
|
15
|
+
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.start_date')
|
|
16
|
+
expect(subject.query(Sequel.mock).sql).to match('l.end_date <= r.end_date')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'conceptql/operators/person_filter'
|
|
3
|
+
require_relative 'query_double'
|
|
4
|
+
|
|
5
|
+
describe ConceptQL::Operators::PersonFilter do
|
|
6
|
+
it_behaves_like(:evaluator)
|
|
7
|
+
|
|
8
|
+
describe '#query' do
|
|
9
|
+
it 'uses right stream as argument to PERSON_FILTER against left stream' do
|
|
10
|
+
double1 = QueryDouble.new(1)
|
|
11
|
+
double2 = QueryDouble.new(2)
|
|
12
|
+
expect(ConceptQL::Operators::PersonFilter.new(left: double1, right: double2).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM table1) AS t1 WHERE (person_id IN (SELECT person_id FROM table2 GROUP BY person_id))")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|