conceptql 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,74 +1,68 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'conceptql/
|
2
|
+
require 'conceptql/operators/operator'
|
3
3
|
require 'conceptql/behaviors/dottable'
|
4
4
|
|
5
|
-
class
|
5
|
+
class OperatorDouble < ConceptQL::Operators::Operator
|
6
6
|
include ConceptQL::Behaviors::Dottable
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
@values = values
|
11
|
-
@options = {}
|
8
|
+
def initialize(*args)
|
9
|
+
super
|
12
10
|
@types = []
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
16
14
|
describe ConceptQL::Behaviors::Dottable do
|
17
15
|
before do
|
18
|
-
@obj =
|
19
|
-
@obj.must_behave_like(:node)
|
16
|
+
@obj = OperatorDouble.new
|
20
17
|
end
|
21
18
|
|
22
19
|
describe '#display_name' do
|
23
|
-
it 'should show just the name if no
|
20
|
+
it 'should show just the name if no upstreams or arguments' do
|
24
21
|
@obj.values = []
|
25
|
-
@obj.display_name.
|
22
|
+
expect(@obj.display_name).to match(/Operator Double( \d+)?/)
|
26
23
|
end
|
27
24
|
|
28
25
|
it 'should show name and args' do
|
29
26
|
@obj.values = [5, 10]
|
30
|
-
@obj.display_name.
|
27
|
+
expect(@obj.display_name).to match(/Operator Double( \d+)?: 5, 10/)
|
31
28
|
end
|
32
29
|
|
33
|
-
it 'should not include
|
34
|
-
@obj.values = [::ConceptQL::
|
35
|
-
@obj.display_name.
|
30
|
+
it 'should not include upstreams' do
|
31
|
+
@obj.values = [::ConceptQL::Operators::Operator.new]
|
32
|
+
expect(@obj.display_name).to match(/Operator Double( \d+)?/)
|
36
33
|
end
|
37
34
|
end
|
38
35
|
|
39
|
-
describe '#
|
40
|
-
it 'should show just the name and digit if no
|
41
|
-
@obj.values = [::ConceptQL::
|
42
|
-
@obj.
|
36
|
+
describe '#operator_name' do
|
37
|
+
it 'should show just the name and digit if no upstreams' do
|
38
|
+
@obj.values = [::ConceptQL::Operators::Operator.new]
|
39
|
+
expect(@obj.operator_name).to match(/^operator_double_\d+$/)
|
43
40
|
end
|
44
41
|
|
45
42
|
it 'should not show args' do
|
46
43
|
@obj.values = [5, 10]
|
47
|
-
@obj.
|
44
|
+
expect(@obj.operator_name).to match(/^operator_double_\d+$/)
|
48
45
|
end
|
49
46
|
|
50
|
-
it 'should not include
|
51
|
-
@obj.values = [::ConceptQL::
|
52
|
-
@obj.
|
47
|
+
it 'should not include upstreams' do
|
48
|
+
@obj.values = [::ConceptQL::Operators::Operator.new]
|
49
|
+
expect(@obj.operator_name).to match(/^operator_double_\d+$/)
|
53
50
|
end
|
54
51
|
end
|
55
52
|
|
56
53
|
describe '#graph_it' do
|
57
|
-
it 'should add itself as a
|
54
|
+
it 'should add itself as a operator if no upstreams' do
|
58
55
|
@obj.values = []
|
59
|
-
mock_graph =
|
60
|
-
|
61
|
-
mock_graph.
|
62
|
-
|
63
|
-
|
56
|
+
mock_graph = double("graph")
|
57
|
+
mock_operator = double("operator")
|
58
|
+
expect(mock_graph).to receive(:add_nodes).with(@obj.operator_name).and_return(mock_operator)
|
59
|
+
expect(mock_operator).to receive(:[]=).with(:label, @obj.display_name).and_return(nil)
|
60
|
+
expect(mock_operator).to receive(:[]=).with(:color, 'black').and_return(nil)
|
64
61
|
@obj.graph_it(mock_graph, Sequel.mock)
|
65
|
-
|
66
|
-
mock_node.verify
|
67
|
-
mock_graph.verify
|
68
62
|
end
|
69
63
|
|
70
|
-
it 'should add its
|
71
|
-
class
|
64
|
+
it 'should add its upstreams, then link itself as a operator if upstreams' do
|
65
|
+
class MockUpstream < ConceptQL::Operators::Operator
|
72
66
|
include ConceptQL::Behaviors::Dottable
|
73
67
|
|
74
68
|
attr_accessor :mock
|
@@ -80,32 +74,26 @@ describe ConceptQL::Behaviors::Dottable do
|
|
80
74
|
mock.types
|
81
75
|
end
|
82
76
|
|
83
|
-
def link_to(mock_graph,
|
84
|
-
mock.link_to(mock_graph,
|
77
|
+
def link_to(mock_graph, mock_operator, db)
|
78
|
+
mock.link_to(mock_graph, mock_operator, db)
|
85
79
|
end
|
86
80
|
end
|
87
81
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
mock_graph = Minitest::Mock.new
|
93
|
-
mock_graph.expect :add_nodes, mock_node, [@obj.node_name]
|
82
|
+
mock_operator = double("operator")
|
83
|
+
expect(mock_operator).to receive(:[]=).with(:label, @obj.display_name).and_return(nil)
|
84
|
+
expect(mock_operator).to receive(:[]=).with(:color, 'black').and_return(nil)
|
94
85
|
|
95
|
-
|
96
|
-
|
97
|
-
mock_child.mock.expect :graph_it, :child_node, [mock_graph, :db]
|
98
|
-
mock_child.mock.expect :link_to, nil, [mock_graph, mock_node, :db]
|
86
|
+
mock_graph = double("graph")
|
87
|
+
expect(mock_graph).to receive(:add_nodes).with(@obj.operator_name).and_return(mock_operator)
|
99
88
|
|
100
|
-
|
89
|
+
mock_upstream = MockUpstream.new
|
90
|
+
mock_upstream.mock = double("upstream")
|
91
|
+
expect(mock_upstream.mock).to receive(:graph_it).with(mock_graph, :db).and_return(:upstream_operator)
|
92
|
+
expect(mock_upstream.mock).to receive(:link_to).with(mock_graph, mock_operator, :db).and_return(nil)
|
101
93
|
|
102
|
-
@obj.values =
|
94
|
+
@obj.values = mock_upstream
|
103
95
|
|
104
96
|
@obj.graph_it(mock_graph, :db)
|
105
|
-
|
106
|
-
mock_node.verify
|
107
|
-
mock_graph.verify
|
108
|
-
mock_child.mock.verify
|
109
97
|
end
|
110
98
|
end
|
111
99
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/converter'
|
3
|
+
|
4
|
+
describe ConceptQL::Converter do
|
5
|
+
describe '#convert' do
|
6
|
+
it 'convert {icd9: 412} to [:icd9, "412"]' do
|
7
|
+
statement = { icd9: '412' }
|
8
|
+
expect(ConceptQL::Converter.new.convert(statement)).to eq([:icd9, '412'])
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'convert {icd9: ["412", "200"]} to [:icd9, "412"]' do
|
12
|
+
statement = { icd9: %w(412 200) }
|
13
|
+
expect(ConceptQL::Converter.new.convert(statement)).to eq([:icd9, '412', '200'])
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'convert { first: {icd9: ["412", "200"]}} to [:first, [:icd9, "412"] ]' do
|
17
|
+
statement = {
|
18
|
+
first: {
|
19
|
+
icd9: %w(412 200)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
expect(ConceptQL::Converter.new.convert(statement)).to eq([:first, [:icd9, '412', '200'] ])
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'convert operators in options to list-syntax' do
|
26
|
+
statement = {
|
27
|
+
after: {
|
28
|
+
left: {
|
29
|
+
icd9: '412'
|
30
|
+
},
|
31
|
+
right: {
|
32
|
+
icd9: '200'
|
33
|
+
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
expect(ConceptQL::Converter.new.convert(statement)).to eq([:after, { left: [:icd9, '412'], right: [:icd9, '200'] }])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'converts operators with an array of upstreams' do
|
41
|
+
statement = {
|
42
|
+
intersect: [
|
43
|
+
{ icd9: '412' },
|
44
|
+
{ condition_type: :inpatient_header }
|
45
|
+
]
|
46
|
+
}
|
47
|
+
expect(ConceptQL::Converter.new.convert(statement)).to eq([:intersect, [ :icd9, '412' ], [ :condition_type, :inpatient_header ] ])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -4,63 +4,63 @@ require 'conceptql/date_adjuster'
|
|
4
4
|
describe ConceptQL::DateAdjuster do
|
5
5
|
describe '#adjustments' do
|
6
6
|
it 'returns nothing for input of ""' do
|
7
|
-
ConceptQL::DateAdjuster.new('').adjustments.
|
7
|
+
expect(ConceptQL::DateAdjuster.new('').adjustments).to eq([])
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'returns nothing for input of "0"' do
|
11
|
-
ConceptQL::DateAdjuster.new('').adjustments.
|
11
|
+
expect(ConceptQL::DateAdjuster.new('').adjustments).to eq([])
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'returns nothing for input of nil' do
|
15
|
-
ConceptQL::DateAdjuster.new(nil).adjustments.
|
15
|
+
expect(ConceptQL::DateAdjuster.new(nil).adjustments).to eq([])
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'returns single day for input of "1"' do
|
19
|
-
ConceptQL::DateAdjuster.new('1').adjustments.
|
19
|
+
expect(ConceptQL::DateAdjuster.new('1').adjustments).to eq([[:days, 1]])
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'returns 20 days for input of "20"' do
|
23
|
-
ConceptQL::DateAdjuster.new('20').adjustments.
|
23
|
+
expect(ConceptQL::DateAdjuster.new('20').adjustments).to eq([[:days, 20]])
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'returns single day for input of "d"' do
|
27
|
-
ConceptQL::DateAdjuster.new('d').adjustments.
|
27
|
+
expect(ConceptQL::DateAdjuster.new('d').adjustments).to eq([[:days, 1]])
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'returns single month for input of "m"' do
|
31
|
-
ConceptQL::DateAdjuster.new('m').adjustments.
|
31
|
+
expect(ConceptQL::DateAdjuster.new('m').adjustments).to eq([[:months, 1]])
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'returns single year for input of "y"' do
|
35
|
-
ConceptQL::DateAdjuster.new('y').adjustments.
|
35
|
+
expect(ConceptQL::DateAdjuster.new('y').adjustments).to eq([[:years, 1]])
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'returns 2 days for input of "2d"' do
|
39
|
-
ConceptQL::DateAdjuster.new('2d').adjustments.
|
39
|
+
expect(ConceptQL::DateAdjuster.new('2d').adjustments).to eq([[:days, 2]])
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'returns 2 months for input of "2m"' do
|
43
|
-
ConceptQL::DateAdjuster.new('2m').adjustments.
|
43
|
+
expect(ConceptQL::DateAdjuster.new('2m').adjustments).to eq([[:months, 2]])
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'returns 2 years for input of "2y"' do
|
47
|
-
ConceptQL::DateAdjuster.new('2y').adjustments.
|
47
|
+
expect(ConceptQL::DateAdjuster.new('2y').adjustments).to eq([[:years, 2]])
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'returns negative single day for input of "-d"' do
|
51
|
-
ConceptQL::DateAdjuster.new('-d').adjustments.
|
51
|
+
expect(ConceptQL::DateAdjuster.new('-d').adjustments).to eq([[:days, -1]])
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'returns negative single day, positive single month for "-dm"' do
|
55
|
-
ConceptQL::DateAdjuster.new('-dm').adjustments.
|
55
|
+
expect(ConceptQL::DateAdjuster.new('-dm').adjustments).to eq([[:days, -1], [:months, 1]])
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'returns negative 2 days for "-2d"' do
|
59
|
-
ConceptQL::DateAdjuster.new('-2d').adjustments.
|
59
|
+
expect(ConceptQL::DateAdjuster.new('-2d').adjustments).to eq([[:days, -2]])
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'returns positive 2 days for "2d"' do
|
63
|
-
ConceptQL::DateAdjuster.new('2d').adjustments.
|
63
|
+
expect(ConceptQL::DateAdjuster.new('2d').adjustments).to eq([[:days, 2]])
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/operators/after'
|
3
|
+
require_double('stream_for_temporal')
|
4
|
+
|
5
|
+
describe ConceptQL::Operators::After do
|
6
|
+
it_behaves_like(:temporal_operator)
|
7
|
+
|
8
|
+
subject do
|
9
|
+
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should use proper where clause' do
|
13
|
+
expect(subject.query(Sequel.mock).sql).to match('l.start_date > r.end_date')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/operators/before'
|
3
|
+
require_double('stream_for_temporal')
|
4
|
+
|
5
|
+
describe ConceptQL::Operators::Before do
|
6
|
+
it_behaves_like(:temporal_operator)
|
7
|
+
|
8
|
+
subject do
|
9
|
+
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should use proper where clause' do
|
13
|
+
expect(subject.query(Sequel.mock).sql).to match('l.end_date < r.start_date')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'conceptql/
|
2
|
+
require 'conceptql/operators/casting_operator'
|
3
3
|
require_double('stream_for_casting')
|
4
4
|
|
5
|
-
describe ConceptQL::
|
6
|
-
|
7
|
-
ConceptQL::Nodes::CastingNode.new.must_behave_like(:evaluator)
|
8
|
-
end
|
5
|
+
describe ConceptQL::Operators::CastingOperator do
|
6
|
+
it_behaves_like(:evaluator)
|
9
7
|
|
10
|
-
class CastingDouble < ConceptQL::
|
8
|
+
class CastingDouble < ConceptQL::Operators::CastingOperator
|
11
9
|
def my_type
|
12
10
|
:my_type
|
13
11
|
end
|
@@ -22,9 +20,7 @@ describe ConceptQL::Nodes::CastingNode do
|
|
22
20
|
end
|
23
21
|
|
24
22
|
describe CastingDouble do
|
25
|
-
|
26
|
-
CastingDouble.new.must_behave_like(:casting_node)
|
27
|
-
end
|
23
|
+
it_behaves_like(:casting_operator)
|
28
24
|
end
|
29
25
|
|
30
26
|
describe '#query' do
|
@@ -32,39 +28,39 @@ describe ConceptQL::Nodes::CastingNode do
|
|
32
28
|
stream = StreamForCastingDouble.new
|
33
29
|
stream.types = [:uncastable]
|
34
30
|
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
35
|
-
sql.
|
36
|
-
sql.
|
37
|
-
sql.
|
31
|
+
expect(sql).to match('person_id IN')
|
32
|
+
expect(sql).to match('GROUP BY person_id')
|
33
|
+
expect(sql).to match('FROM table')
|
38
34
|
end
|
39
35
|
|
40
36
|
it 'uses person_ids when an uncastable type is included among castable types' do
|
41
37
|
stream = StreamForCastingDouble.new
|
42
38
|
stream.types = [:i_point1, :uncastable]
|
43
39
|
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
44
|
-
sql.
|
45
|
-
sql.
|
40
|
+
expect(sql).to match('person_id IN')
|
41
|
+
expect(sql).to match('GROUP BY person_id')
|
46
42
|
end
|
47
43
|
|
48
44
|
it 'uses castable types if possible' do
|
49
45
|
stream = StreamForCastingDouble.new
|
50
46
|
stream.types = [:i_point1]
|
51
47
|
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
52
|
-
sql.
|
53
|
-
sql.
|
48
|
+
expect(sql).to match('i_point1_id IN')
|
49
|
+
expect(sql).to match("criterion_type = 'i_point1'")
|
54
50
|
end
|
55
51
|
|
56
52
|
it 'uses and unions multiple castable types if possible' do
|
57
53
|
stream = StreamForCastingDouble.new
|
58
54
|
stream.types = [:i_point1, :at_me2]
|
59
55
|
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
60
|
-
sql.
|
61
|
-
sql.
|
62
|
-
sql.
|
56
|
+
expect(sql).to match('my_type_id IN')
|
57
|
+
expect(sql).to match('i_point1_id IN')
|
58
|
+
expect(sql).to match("criterion_type = 'i_point1'")
|
63
59
|
end
|
64
60
|
|
65
61
|
it 'returns all rows of a table if passed the argument "true"' do
|
66
62
|
sql = CastingDouble.new(true).query(Sequel.mock).sql
|
67
|
-
sql.
|
63
|
+
expect(sql).to match("SELECT * FROM my_type AS tab")
|
68
64
|
end
|
69
65
|
end
|
70
66
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/operators/complement'
|
3
|
+
require_relative 'query_double'
|
4
|
+
|
5
|
+
describe ConceptQL::Operators::Complement do
|
6
|
+
it_behaves_like(:evaluator)
|
7
|
+
|
8
|
+
it 'generates complement for single criteria' do
|
9
|
+
double1 = QueryDouble.new(1)
|
10
|
+
sql = ConceptQL::Operators::Complement.new(double1).query(Sequel.mock).sql
|
11
|
+
expect(sql).to match("criterion_id IS NOT NULL")
|
12
|
+
expect(sql).to match("visit_occurrence_id NOT IN")
|
13
|
+
expect(sql).to match("criterion_type = 'visit_occurrence'")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/operators/concept'
|
3
|
+
|
4
|
+
describe ConceptQL::Operators::Concept do
|
5
|
+
it_behaves_like(:evaluator)
|
6
|
+
|
7
|
+
class ConceptDouble < ConceptQL::Operators::Concept
|
8
|
+
attr_accessor :cql_query
|
9
|
+
|
10
|
+
def arguments
|
11
|
+
[1]
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_statement(value)
|
15
|
+
@statement = { icd9: '412' }
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_cql_query(db)
|
19
|
+
@cql_query ||= nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def cql_query
|
23
|
+
set_cql_query(nil)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#query' do
|
28
|
+
it 'evaluates upstream' do
|
29
|
+
cd = ConceptDouble.new(1)
|
30
|
+
db = Sequel.mock
|
31
|
+
cd.cql_query = double("query")
|
32
|
+
expect(cd.cql_query).to receive(:query).and_return(cd.cql_query)
|
33
|
+
expect(cd.cql_query).to receive(:from_self)
|
34
|
+
cd.query(db)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
@@ -1,110 +1,125 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'conceptql/
|
2
|
+
require 'conceptql/operators/condition_type'
|
3
3
|
|
4
|
-
describe ConceptQL::
|
5
|
-
|
6
|
-
ConceptQL::Nodes::ConditionType.new.must_behave_like(:evaluator)
|
7
|
-
end
|
4
|
+
describe ConceptQL::Operators::ConditionType do
|
5
|
+
it_behaves_like(:evaluator)
|
8
6
|
|
9
7
|
describe '#query' do
|
10
8
|
it 'works for inpatient_detail_primary' do
|
11
9
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000183))"
|
12
|
-
ConceptQL::
|
10
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_detail_primary).query(Sequel.mock).sql).to eq(correct_query)
|
13
11
|
end
|
14
12
|
|
15
13
|
it 'works for inpatient_detail_1' do
|
16
14
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000184))"
|
17
|
-
ConceptQL::
|
15
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_detail_1).query(Sequel.mock).sql).to eq(correct_query)
|
18
16
|
end
|
19
17
|
|
20
18
|
it 'works for inpatient_detail_2' do
|
21
19
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000185))"
|
22
|
-
ConceptQL::
|
20
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_detail_2).query(Sequel.mock).sql).to eq(correct_query)
|
23
21
|
end
|
24
22
|
|
25
23
|
it 'works for inpatient_header_primary' do
|
26
24
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000199))"
|
27
|
-
ConceptQL::
|
25
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_header_primary).query(Sequel.mock).sql).to eq(correct_query)
|
28
26
|
end
|
29
27
|
|
30
28
|
it 'works for inpatient_header_1' do
|
31
29
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000200))"
|
32
|
-
ConceptQL::
|
30
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_header_1).query(Sequel.mock).sql).to eq(correct_query)
|
33
31
|
end
|
34
32
|
|
35
33
|
it 'works for outpatient_detail_1' do
|
36
34
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000215))"
|
37
|
-
ConceptQL::
|
35
|
+
expect(ConceptQL::Operators::ConditionType.new(:outpatient_detail_1).query(Sequel.mock).sql).to eq(correct_query)
|
38
36
|
end
|
39
37
|
|
40
38
|
it 'works for outpatient_header_1' do
|
41
39
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000230))"
|
42
|
-
ConceptQL::
|
40
|
+
expect(ConceptQL::Operators::ConditionType.new(:outpatient_header_1).query(Sequel.mock).sql).to eq(correct_query)
|
43
41
|
end
|
44
42
|
|
45
43
|
it 'works for ehr_problem_list' do
|
46
44
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000245))"
|
47
|
-
ConceptQL::
|
45
|
+
expect(ConceptQL::Operators::ConditionType.new(:ehr_problem_list).query(Sequel.mock).sql).to eq(correct_query)
|
48
46
|
end
|
49
47
|
|
50
48
|
it 'works for condition_era_0_day_window' do
|
51
49
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000246))"
|
52
|
-
ConceptQL::
|
50
|
+
expect(ConceptQL::Operators::ConditionType.new(:condition_era_0_day_window).query(Sequel.mock).sql).to eq(correct_query)
|
53
51
|
end
|
54
52
|
|
55
53
|
it 'works for condition_era_30_day_window' do
|
56
54
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000247))"
|
57
|
-
ConceptQL::
|
55
|
+
expect(ConceptQL::Operators::ConditionType.new(:condition_era_30_day_window).query(Sequel.mock).sql).to eq(correct_query)
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'with primary' do
|
59
|
+
it 'works for just primary' do
|
60
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000183, 38000199, 38000215, 38000230))"
|
61
|
+
expect(ConceptQL::Operators::ConditionType.new(:primary).query(Sequel.mock).sql).to eq(correct_query)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'works for inpatient_primary' do
|
65
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000183, 38000199))"
|
66
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_primary).query(Sequel.mock).sql).to eq(correct_query)
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'works for outpatient_primary' do
|
70
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000215, 38000230))"
|
71
|
+
expect(ConceptQL::Operators::ConditionType.new(:outpatient_primary).query(Sequel.mock).sql).to eq(correct_query)
|
72
|
+
end
|
58
73
|
end
|
59
74
|
|
60
75
|
describe 'with multiple arguments' do
|
61
76
|
it 'works for inpatient_detail_1' do
|
62
77
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000184, 38000185))"
|
63
|
-
ConceptQL::
|
78
|
+
expect(ConceptQL::Operators::ConditionType.new(:inpatient_detail_1, :inpatient_detail_2).query(Sequel.mock).sql).to eq(correct_query)
|
64
79
|
end
|
65
80
|
end
|
66
81
|
|
67
82
|
describe 'with arguments as strings' do
|
68
83
|
it 'works for inpatient_detail_1' do
|
69
84
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000184, 38000185))"
|
70
|
-
ConceptQL::
|
85
|
+
expect(ConceptQL::Operators::ConditionType.new('inpatient_detail_1', 'inpatient_detail_2').query(Sequel.mock).sql).to eq(correct_query)
|
71
86
|
end
|
72
87
|
end
|
73
88
|
|
74
89
|
describe 'as category' do
|
75
90
|
it 'works for inpatient_detail' do
|
76
91
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000183, 38000184, 38000185, 38000186, 38000187, 38000188, 38000189, 38000190, 38000191, 38000192, 38000193, 38000194, 38000195, 38000196, 38000197, 38000198))"
|
77
|
-
ConceptQL::
|
92
|
+
expect(ConceptQL::Operators::ConditionType.new('inpatient_detail').query(Sequel.mock).sql).to eq(correct_query)
|
78
93
|
end
|
79
94
|
|
80
95
|
it 'works for inpatient_header' do
|
81
96
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000199, 38000200, 38000201, 38000202, 38000203, 38000204, 38000205, 38000206, 38000207, 38000208, 38000209, 38000210, 38000211, 38000212, 38000213, 38000214))"
|
82
|
-
ConceptQL::
|
97
|
+
expect(ConceptQL::Operators::ConditionType.new('inpatient_header').query(Sequel.mock).sql).to eq(correct_query)
|
83
98
|
end
|
84
99
|
|
85
100
|
it 'works for inpatient' do
|
86
101
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000183, 38000184, 38000185, 38000186, 38000187, 38000188, 38000189, 38000190, 38000191, 38000192, 38000193, 38000194, 38000195, 38000196, 38000197, 38000198, 38000199, 38000200, 38000201, 38000202, 38000203, 38000204, 38000205, 38000206, 38000207, 38000208, 38000209, 38000210, 38000211, 38000212, 38000213, 38000214))"
|
87
|
-
ConceptQL::
|
102
|
+
expect(ConceptQL::Operators::ConditionType.new('inpatient').query(Sequel.mock).sql).to eq(correct_query)
|
88
103
|
end
|
89
104
|
|
90
105
|
it 'works for outpatient_detail' do
|
91
106
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000215, 38000216, 38000217, 38000218, 38000219, 38000220, 38000221, 38000222, 38000223, 38000224, 38000225, 38000226, 38000227, 38000228, 38000229))"
|
92
|
-
ConceptQL::
|
107
|
+
expect(ConceptQL::Operators::ConditionType.new('outpatient_detail').query(Sequel.mock).sql).to eq(correct_query)
|
93
108
|
end
|
94
109
|
|
95
110
|
it 'works for outpatient_header' do
|
96
111
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000230, 38000231, 38000232, 38000233, 38000234, 38000235, 38000236, 38000237, 38000238, 38000239, 38000240, 38000241, 38000242, 38000243, 38000244))"
|
97
|
-
ConceptQL::
|
112
|
+
expect(ConceptQL::Operators::ConditionType.new('outpatient_header').query(Sequel.mock).sql).to eq(correct_query)
|
98
113
|
end
|
99
114
|
|
100
115
|
it 'works for outpatient' do
|
101
116
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000215, 38000216, 38000217, 38000218, 38000219, 38000220, 38000221, 38000222, 38000223, 38000224, 38000225, 38000226, 38000227, 38000228, 38000229, 38000230, 38000231, 38000232, 38000233, 38000234, 38000235, 38000236, 38000237, 38000238, 38000239, 38000240, 38000241, 38000242, 38000243, 38000244))"
|
102
|
-
ConceptQL::
|
117
|
+
expect(ConceptQL::Operators::ConditionType.new('outpatient').query(Sequel.mock).sql).to eq(correct_query)
|
103
118
|
end
|
104
119
|
|
105
120
|
it 'works for condition_era' do
|
106
121
|
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000246, 38000247))"
|
107
|
-
ConceptQL::
|
122
|
+
expect(ConceptQL::Operators::ConditionType.new('condition_era').query(Sequel.mock).sql).to eq(correct_query)
|
108
123
|
end
|
109
124
|
end
|
110
125
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/operators/contains'
|
3
|
+
require_double('stream_for_temporal')
|
4
|
+
|
5
|
+
describe ConceptQL::Operators::Contains 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.end_date <= l.end_date')
|
15
|
+
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.start_date')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'conceptql/operators/cpt'
|
3
|
+
|
4
|
+
describe ConceptQL::Operators::Cpt 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 4' do
|
25
|
+
expect(subject.vocabulary_id).to eq(4)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|