conceptql 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (196) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +53 -1
  4. data/Guardfile +52 -24
  5. data/conceptql.gemspec +5 -3
  6. data/doc/spec.md +2 -2
  7. data/lib/conceptql/behaviors/debuggable.rb +70 -0
  8. data/lib/conceptql/behaviors/dottable.rb +28 -14
  9. data/lib/conceptql/behaviors/metadatable.rb +97 -0
  10. data/lib/conceptql/behaviors/preppable.rb +20 -0
  11. data/lib/conceptql/cli.rb +31 -5
  12. data/lib/conceptql/converter.rb +65 -0
  13. data/lib/conceptql/debugger.rb +48 -0
  14. data/lib/conceptql/graph.rb +14 -13
  15. data/lib/conceptql/graph_nodifier.rb +49 -17
  16. data/lib/conceptql/nodifier.rb +31 -6
  17. data/lib/conceptql/operators/after.rb +25 -0
  18. data/lib/conceptql/operators/any_overlap.rb +15 -0
  19. data/lib/conceptql/operators/before.rb +21 -0
  20. data/lib/conceptql/{nodes/binary_operator_node.rb → operators/binary_operator_operator.rb} +12 -8
  21. data/lib/conceptql/{nodes/casting_node.rb → operators/casting_operator.rb} +8 -7
  22. data/lib/conceptql/{nodes → operators}/complement.rb +14 -11
  23. data/lib/conceptql/operators/concept.rb +70 -0
  24. data/lib/conceptql/{nodes → operators}/condition_type.rb +13 -5
  25. data/lib/conceptql/operators/contains.rb +17 -0
  26. data/lib/conceptql/operators/count.rb +26 -0
  27. data/lib/conceptql/operators/cpt.rb +25 -0
  28. data/lib/conceptql/{nodes → operators}/date_range.rb +11 -6
  29. data/lib/conceptql/operators/death.rb +23 -0
  30. data/lib/conceptql/operators/drug_type_concept.rb +21 -0
  31. data/lib/conceptql/{nodes → operators}/during.rb +9 -3
  32. data/lib/conceptql/operators/equal.rb +13 -0
  33. data/lib/conceptql/operators/except.rb +28 -0
  34. data/lib/conceptql/operators/filter.rb +21 -0
  35. data/lib/conceptql/{nodes → operators}/first.rb +7 -5
  36. data/lib/conceptql/{nodes → operators}/from.rb +2 -2
  37. data/lib/conceptql/operators/from_seer_visits.rb +23 -0
  38. data/lib/conceptql/{nodes → operators}/gender.rb +6 -6
  39. data/lib/conceptql/operators/hcpcs.rb +25 -0
  40. data/lib/conceptql/operators/icd10.rb +28 -0
  41. data/lib/conceptql/operators/icd9.rb +28 -0
  42. data/lib/conceptql/operators/icd9_procedure.rb +25 -0
  43. data/lib/conceptql/{nodes → operators}/intersect.rb +7 -3
  44. data/lib/conceptql/{nodes → operators}/last.rb +7 -5
  45. data/lib/conceptql/operators/loinc.rb +25 -0
  46. data/lib/conceptql/operators/medcode.rb +28 -0
  47. data/lib/conceptql/operators/medcode_procedure.rb +27 -0
  48. data/lib/conceptql/operators/ndc.rb +29 -0
  49. data/lib/conceptql/operators/numeric.rb +54 -0
  50. data/lib/conceptql/operators/observation_by_enttype.rb +29 -0
  51. data/lib/conceptql/operators/observation_period.rb +30 -0
  52. data/lib/conceptql/operators/occurrence.rb +70 -0
  53. data/lib/conceptql/operators/one_in_two_out.rb +62 -0
  54. data/lib/conceptql/{nodes/node.rb → operators/operator.rb} +84 -52
  55. data/lib/conceptql/operators/overlapped_by.rb +23 -0
  56. data/lib/conceptql/operators/overlaps.rb +19 -0
  57. data/lib/conceptql/operators/pass_thru.rb +11 -0
  58. data/lib/conceptql/{nodes → operators}/person.rb +8 -4
  59. data/lib/conceptql/operators/person_filter.rb +13 -0
  60. data/lib/conceptql/{nodes → operators}/place_of_service_code.rb +7 -7
  61. data/lib/conceptql/operators/procedure_occurrence.rb +25 -0
  62. data/lib/conceptql/operators/prodcode.rb +29 -0
  63. data/lib/conceptql/{nodes → operators}/race.rb +7 -7
  64. data/lib/conceptql/operators/recall.rb +38 -0
  65. data/lib/conceptql/operators/rxnorm.rb +24 -0
  66. data/lib/conceptql/operators/snomed.rb +24 -0
  67. data/lib/conceptql/operators/snomed_condition.rb +26 -0
  68. data/lib/conceptql/{nodes/source_vocabulary_node.rb → operators/source_vocabulary_operator.rb} +7 -4
  69. data/lib/conceptql/{nodes/standard_vocabulary_node.rb → operators/standard_vocabulary_operator.rb} +6 -4
  70. data/lib/conceptql/{nodes → operators}/started_by.rb +9 -3
  71. data/lib/conceptql/{nodes → operators}/sum.rb +9 -4
  72. data/lib/conceptql/{nodes/temporal_node.rb → operators/temporal_operator.rb} +7 -4
  73. data/lib/conceptql/{nodes → operators}/time_window.rb +19 -7
  74. data/lib/conceptql/operators/to_seer_visits.rb +24 -0
  75. data/lib/conceptql/operators/trim_date_end.rb +55 -0
  76. data/lib/conceptql/operators/trim_date_start.rb +56 -0
  77. data/lib/conceptql/{nodes → operators}/union.rb +6 -2
  78. data/lib/conceptql/operators/visit.rb +15 -0
  79. data/lib/conceptql/{nodes → operators}/visit_occurrence.rb +7 -3
  80. data/lib/conceptql/query.rb +19 -17
  81. data/lib/conceptql/scope.rb +69 -0
  82. data/lib/conceptql/tree.rb +33 -18
  83. data/lib/conceptql/utils/temp_table.rb +72 -0
  84. data/lib/conceptql/version.rb +1 -1
  85. data/spec/conceptql/behaviors/dottable_spec.rb +39 -51
  86. data/spec/conceptql/converter_spec.rb +51 -0
  87. data/spec/conceptql/date_adjuster_spec.rb +15 -15
  88. data/spec/conceptql/operators/after_spec.rb +16 -0
  89. data/spec/conceptql/operators/before_spec.rb +16 -0
  90. data/spec/conceptql/{nodes/casting_node_spec.rb → operators/casting_operator_spec.rb} +16 -20
  91. data/spec/conceptql/operators/complement_spec.rb +15 -0
  92. data/spec/conceptql/operators/concept_spec.rb +40 -0
  93. data/spec/conceptql/{nodes → operators}/condition_type_spec.rb +39 -24
  94. data/spec/conceptql/operators/contains_spec.rb +19 -0
  95. data/spec/conceptql/operators/cpt_spec.rb +29 -0
  96. data/spec/conceptql/operators/date_range_spec.rb +33 -0
  97. data/spec/conceptql/operators/death_spec.rb +10 -0
  98. data/spec/conceptql/operators/during_spec.rb +30 -0
  99. data/spec/conceptql/operators/except_spec.rb +15 -0
  100. data/spec/conceptql/operators/first_spec.rb +35 -0
  101. data/spec/conceptql/operators/from_spec.rb +13 -0
  102. data/spec/conceptql/operators/gender_spec.rb +27 -0
  103. data/spec/conceptql/operators/hcpcs_spec.rb +29 -0
  104. data/spec/conceptql/operators/icd10_spec.rb +34 -0
  105. data/spec/conceptql/operators/icd9_procedure_spec.rb +29 -0
  106. data/spec/conceptql/operators/icd9_spec.rb +34 -0
  107. data/spec/conceptql/operators/intersect_spec.rb +28 -0
  108. data/spec/conceptql/operators/last_spec.rb +36 -0
  109. data/spec/conceptql/operators/loinc_spec.rb +29 -0
  110. data/spec/conceptql/operators/medcode_procedure_spec.rb +34 -0
  111. data/spec/conceptql/operators/medcode_spec.rb +34 -0
  112. data/spec/conceptql/operators/observation_period_spec.rb +10 -0
  113. data/spec/conceptql/operators/occurrence_spec.rb +87 -0
  114. data/spec/conceptql/operators/overlapped_by_spec.rb +32 -0
  115. data/spec/conceptql/operators/overlaps_spec.rb +21 -0
  116. data/spec/conceptql/operators/person_filter_spec.rb +15 -0
  117. data/spec/conceptql/operators/person_spec.rb +10 -0
  118. data/spec/conceptql/{nodes → operators}/place_of_service_code_spec.rb +6 -8
  119. data/spec/conceptql/operators/procedure_occurrence_spec.rb +10 -0
  120. data/spec/conceptql/operators/prodcode_spec.rb +35 -0
  121. data/spec/conceptql/operators/query_double.rb +20 -0
  122. data/spec/conceptql/operators/query_double_spec.rb +7 -0
  123. data/spec/conceptql/operators/race_spec.rb +21 -0
  124. data/spec/conceptql/operators/rxnorm_spec.rb +29 -0
  125. data/spec/conceptql/operators/snomed_spec.rb +29 -0
  126. data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +35 -0
  127. data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +35 -0
  128. data/spec/conceptql/operators/started_by_spec.rb +22 -0
  129. data/spec/conceptql/{nodes/temporal_node_spec.rb → operators/temporal_operator_spec.rb} +11 -17
  130. data/spec/conceptql/operators/time_window_spec.rb +77 -0
  131. data/spec/conceptql/operators/union_spec.rb +21 -0
  132. data/spec/conceptql/operators/visit_occurrence_spec.rb +10 -0
  133. data/spec/conceptql/query_spec.rb +10 -9
  134. data/spec/conceptql/tree_spec.rb +24 -28
  135. data/spec/doubles/stream_for_casting_double.rb +1 -1
  136. data/spec/doubles/stream_for_occurrence_double.rb +1 -1
  137. data/spec/doubles/stream_for_temporal_double.rb +1 -1
  138. data/spec/spec_helper.rb +74 -58
  139. metadata +202 -133
  140. data/lib/conceptql/nodes/after.rb +0 -12
  141. data/lib/conceptql/nodes/before.rb +0 -11
  142. data/lib/conceptql/nodes/concept.rb +0 -38
  143. data/lib/conceptql/nodes/count.rb +0 -23
  144. data/lib/conceptql/nodes/cpt.rb +0 -20
  145. data/lib/conceptql/nodes/death.rb +0 -19
  146. data/lib/conceptql/nodes/define.rb +0 -96
  147. data/lib/conceptql/nodes/drug_type_concept.rb +0 -18
  148. data/lib/conceptql/nodes/equal.rb +0 -11
  149. data/lib/conceptql/nodes/except.rb +0 -11
  150. data/lib/conceptql/nodes/hcpcs.rb +0 -20
  151. data/lib/conceptql/nodes/icd10.rb +0 -23
  152. data/lib/conceptql/nodes/icd9.rb +0 -23
  153. data/lib/conceptql/nodes/icd9_procedure.rb +0 -20
  154. data/lib/conceptql/nodes/loinc.rb +0 -20
  155. data/lib/conceptql/nodes/numeric.rb +0 -40
  156. data/lib/conceptql/nodes/occurrence.rb +0 -49
  157. data/lib/conceptql/nodes/pass_thru.rb +0 -11
  158. data/lib/conceptql/nodes/person_filter.rb +0 -12
  159. data/lib/conceptql/nodes/procedure_occurrence.rb +0 -21
  160. data/lib/conceptql/nodes/recall.rb +0 -50
  161. data/lib/conceptql/nodes/rxnorm.rb +0 -20
  162. data/lib/conceptql/nodes/snomed.rb +0 -19
  163. data/lib/conceptql/nodes/visit.rb +0 -11
  164. data/spec/conceptql/nodes/after_spec.rb +0 -18
  165. data/spec/conceptql/nodes/before_spec.rb +0 -18
  166. data/spec/conceptql/nodes/complement_spec.rb +0 -15
  167. data/spec/conceptql/nodes/concept_spec.rb +0 -34
  168. data/spec/conceptql/nodes/cpt_spec.rb +0 -31
  169. data/spec/conceptql/nodes/date_range_spec.rb +0 -35
  170. data/spec/conceptql/nodes/death_spec.rb +0 -12
  171. data/spec/conceptql/nodes/during_spec.rb +0 -32
  172. data/spec/conceptql/nodes/except_spec.rb +0 -18
  173. data/spec/conceptql/nodes/first_spec.rb +0 -37
  174. data/spec/conceptql/nodes/from_spec.rb +0 -15
  175. data/spec/conceptql/nodes/gender_spec.rb +0 -29
  176. data/spec/conceptql/nodes/hcpcs_spec.rb +0 -31
  177. data/spec/conceptql/nodes/icd10_spec.rb +0 -36
  178. data/spec/conceptql/nodes/icd9_procedure_spec.rb +0 -31
  179. data/spec/conceptql/nodes/icd9_spec.rb +0 -36
  180. data/spec/conceptql/nodes/intersect_spec.rb +0 -33
  181. data/spec/conceptql/nodes/last_spec.rb +0 -38
  182. data/spec/conceptql/nodes/loinc_spec.rb +0 -31
  183. data/spec/conceptql/nodes/occurrence_spec.rb +0 -89
  184. data/spec/conceptql/nodes/person_filter_spec.rb +0 -18
  185. data/spec/conceptql/nodes/person_spec.rb +0 -12
  186. data/spec/conceptql/nodes/procedure_occurrence_spec.rb +0 -12
  187. data/spec/conceptql/nodes/query_double.rb +0 -19
  188. data/spec/conceptql/nodes/race_spec.rb +0 -23
  189. data/spec/conceptql/nodes/rxnorm_spec.rb +0 -31
  190. data/spec/conceptql/nodes/snomed_spec.rb +0 -31
  191. data/spec/conceptql/nodes/source_vocabulary_node_spec.rb +0 -37
  192. data/spec/conceptql/nodes/standard_vocabulary_node_spec.rb +0 -40
  193. data/spec/conceptql/nodes/started_by_spec.rb +0 -25
  194. data/spec/conceptql/nodes/time_window_spec.rb +0 -85
  195. data/spec/conceptql/nodes/union_spec.rb +0 -25
  196. data/spec/conceptql/nodes/visit_occurrence_spec.rb +0 -12
@@ -1,74 +1,68 @@
1
1
  require 'spec_helper'
2
- require 'conceptql/nodes/node'
2
+ require 'conceptql/operators/operator'
3
3
  require 'conceptql/behaviors/dottable'
4
4
 
5
- class NodeDouble < ConceptQL::Nodes::Node
5
+ class OperatorDouble < ConceptQL::Operators::Operator
6
6
  include ConceptQL::Behaviors::Dottable
7
7
 
8
- attr_accessor :values, :options
9
- def initialize(*values)
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 = NodeDouble.new
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 children or arguments' do
20
+ it 'should show just the name if no upstreams or arguments' do
24
21
  @obj.values = []
25
- @obj.display_name.must_equal 'Node Double'
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.must_equal 'Node Double: 5, 10'
27
+ expect(@obj.display_name).to match(/Operator Double( \d+)?: 5, 10/)
31
28
  end
32
29
 
33
- it 'should not include children' do
34
- @obj.values = [::ConceptQL::Nodes::Node.new]
35
- @obj.display_name.must_equal 'Node Double'
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 '#node_name' do
40
- it 'should show just the name and digit if no children' do
41
- @obj.values = [::ConceptQL::Nodes::Node.new]
42
- @obj.node_name.must_match(/^node_double_\d+$/)
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.node_name.must_match(/^node_double_\d+$/)
44
+ expect(@obj.operator_name).to match(/^operator_double_\d+$/)
48
45
  end
49
46
 
50
- it 'should not include children' do
51
- @obj.values = [::ConceptQL::Nodes::Node.new]
52
- @obj.node_name.must_match(/^node_double_\d+$/)
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 node if no children' do
54
+ it 'should add itself as a operator if no upstreams' do
58
55
  @obj.values = []
59
- mock_graph = Minitest::Mock.new
60
- mock_node = Minitest::Mock.new
61
- mock_graph.expect :add_nodes, mock_node, [@obj.node_name]
62
- mock_node.expect :[]=, nil, [:label, @obj.display_name]
63
- mock_node.expect :[]=, nil, [:color, 'black']
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 children, then link itself as a node if children' do
71
- class MockChild < ConceptQL::Nodes::Node
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, mock_node, db)
84
- mock.link_to(mock_graph, mock_node, db)
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
- mock_node = Minitest::Mock.new
89
- mock_node.expect :[]=, nil, [:label, @obj.display_name]
90
- mock_node.expect :[]=, nil, [:color, 'black']
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
- mock_child = MockChild.new
96
- mock_child.mock = Minitest::Mock.new
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
- mock_child.must_behave_like(:node)
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 = [mock_child]
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.must_equal []
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.must_equal []
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.must_equal []
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.must_equal [[:days, 1]]
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.must_equal [[:days, 20]]
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.must_equal [[:days, 1]]
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.must_equal [[:months, 1]]
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.must_equal [[:years, 1]]
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.must_equal [[:days, 2]]
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.must_equal [[:months, 2]]
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.must_equal [[:years, 2]]
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.must_equal [[:days, -1]]
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.must_equal [[:days, -1], [:months, 1]]
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.must_equal [[:days, -2]]
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.must_equal [[:days, 2]]
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/nodes/casting_node'
2
+ require 'conceptql/operators/casting_operator'
3
3
  require_double('stream_for_casting')
4
4
 
5
- describe ConceptQL::Nodes::CastingNode do
6
- it 'behaves itself' do
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::Nodes::CastingNode
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
- it 'must behave' do
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.must_match 'person_id IN'
36
- sql.must_match 'GROUP BY person_id'
37
- sql.must_match 'FROM table'
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.must_match 'person_id IN'
45
- sql.must_match 'GROUP BY person_id'
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.must_match 'i_point1_id IN'
53
- sql.must_match "criterion_type = 'i_point1'"
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.must_match 'my_type_id IN'
61
- sql.must_match 'i_point1_id IN'
62
- sql.must_match "criterion_type = 'i_point1'"
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.must_match "SELECT * FROM my_type AS tab"
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/nodes/condition_type'
2
+ require 'conceptql/operators/condition_type'
3
3
 
4
- describe ConceptQL::Nodes::ConditionType do
5
- it 'behaves itself' do
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::Nodes::ConditionType.new(:inpatient_detail_primary).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:inpatient_detail_1).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:inpatient_detail_2).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:inpatient_header_primary).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:inpatient_header_1).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:outpatient_detail_1).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:outpatient_header_1).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:ehr_problem_list).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:condition_era_0_day_window).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:condition_era_30_day_window).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new(:inpatient_detail_1, :inpatient_detail_2).query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('inpatient_detail_1', 'inpatient_detail_2').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('inpatient_detail').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('inpatient_header').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('inpatient').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('outpatient_detail').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('outpatient_header').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('outpatient').query(Sequel.mock).sql.must_equal correct_query
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::Nodes::ConditionType.new('condition_era').query(Sequel.mock).sql.must_equal correct_query
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
+