conceptql 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/lib/conceptql/date_adjuster.rb +6 -7
- data/lib/conceptql/graph_nodifier.rb +2 -20
- data/lib/conceptql/nodes/date_range.rb +4 -4
- data/lib/conceptql/nodes/define.rb +5 -1
- data/lib/conceptql/nodes/intersect.rb +1 -1
- data/lib/conceptql/nodes/node.rb +23 -18
- data/lib/conceptql/nodes/occurrence.rb +4 -2
- data/lib/conceptql/nodes/temporal_node.rb +1 -1
- data/lib/conceptql/nodes/time_window.rb +8 -3
- data/lib/conceptql/nodifier.rb +3 -1
- data/lib/conceptql/version.rb +1 -1
- data/spec/conceptql/behaviors/dottable_spec.rb +3 -3
- data/spec/conceptql/date_adjuster_spec.rb +12 -12
- data/spec/conceptql/nodes/casting_node_spec.rb +5 -6
- data/spec/conceptql/nodes/complement_spec.rb +1 -1
- data/spec/conceptql/nodes/condition_type_spec.rb +19 -19
- data/spec/conceptql/nodes/date_range_spec.rb +4 -4
- data/spec/conceptql/nodes/gender_spec.rb +2 -2
- data/spec/conceptql/nodes/intersect_spec.rb +2 -2
- data/spec/conceptql/nodes/occurrence_spec.rb +1 -1
- data/spec/conceptql/nodes/place_of_service_code_spec.rb +3 -3
- data/spec/conceptql/nodes/race_spec.rb +2 -2
- data/spec/conceptql/nodes/source_vocabulary_node_spec.rb +2 -2
- data/spec/conceptql/nodes/standard_vocabulary_node_spec.rb +2 -2
- data/spec/conceptql/nodes/time_window_spec.rb +42 -23
- data/spec/conceptql/query_spec.rb +2 -1
- data/spec/conceptql/tree_spec.rb +10 -10
- data/spec/doubles/stream_for_occurrence_double.rb +4 -0
- data/spec/spec_helper.rb +12 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd428ab59c2a551527b6a2d3382679559aeb1bdb
|
4
|
+
data.tar.gz: 9250fb01a96c2b4f735bac39a12e9d37e0ffa534
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf43748c517516ed53ecedeef4a6e93d72576f0cc458460a67352fa8eb19c6e6cae3c22adde516be357b997d44751bee281e3538f86449acd25708fb0b3fac7d
|
7
|
+
data.tar.gz: 56cbc0f0697a0c3d98ed541cf286c36114a6dfa07c09c5fe13c2fc8bce3b55d645a5dc2aaebdc6d88dba3df5d24db33b0453b5709e920a9ee64141b33b616252
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,27 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## 0.0.7 - 2014-08-28
|
5
|
+
|
6
|
+
### Added
|
7
|
+
- Support for Oracle.
|
8
|
+
|
9
|
+
### Deprecated
|
10
|
+
- Nothing.
|
11
|
+
|
12
|
+
### Removed
|
13
|
+
- Nothing.
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
- DateAdjuster/TimeWindow use Sequel's date_arithmetic extension to produce database agnostic date manipulation.
|
17
|
+
- Breakage from Node#tree in GraphNodifier.
|
18
|
+
- All tests are back to passing.
|
19
|
+
|
20
|
+
|
4
21
|
## 0.0.6 - 2014-08-23
|
5
22
|
|
6
23
|
### Added
|
24
|
+
- Support for Oracle
|
7
25
|
- Tree#defined to pass type information between Define and Recall.
|
8
26
|
- Node#sql to produce SQL for each node.
|
9
27
|
- Graph includes row count on each edge in the diagram.
|
@@ -18,6 +36,8 @@ All notable changes to this project will be documented in this file.
|
|
18
36
|
- Bug in CastingNode that generate SQL returning multiple columns in a subquery.
|
19
37
|
- Made ruby-graphviz a dependency so calling programs don't bomb out.
|
20
38
|
- Define now passes rows on through like any other node!
|
39
|
+
- DateAdjuster/TimeWindow use Sequel's date_arithmetic extension to produce database agnostic date manipulation.
|
40
|
+
- All tests are back to passing.
|
21
41
|
|
22
42
|
|
23
43
|
## 0.0.5 - 2014-08-19
|
@@ -16,16 +16,16 @@ module ConceptQL
|
|
16
16
|
private
|
17
17
|
def lookup
|
18
18
|
{
|
19
|
-
'y' =>
|
20
|
-
'm' =>
|
21
|
-
'd' =>
|
19
|
+
'y' => :years,
|
20
|
+
'm' => :months,
|
21
|
+
'd' => :days
|
22
22
|
}
|
23
23
|
end
|
24
24
|
|
25
25
|
def parse(str)
|
26
26
|
ConceptQL.logger.debug(str)
|
27
|
-
return [] if str.nil?
|
28
|
-
return [
|
27
|
+
return [] if str.nil? || str.empty?
|
28
|
+
return [[lookup['d'], str.to_i]] if str.match(/^[-+]?\d+$/)
|
29
29
|
str.downcase.scan(/([-+]?\d*[dmy])/).map do |adjustment|
|
30
30
|
adjustment = adjustment.first
|
31
31
|
quantity = 1
|
@@ -37,8 +37,7 @@ module ConceptQL
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
unit = lookup[adjustment.chars.last]
|
40
|
-
unit
|
41
|
-
[quantity, unit].join(' ')
|
40
|
+
[unit, quantity]
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
@@ -126,30 +126,12 @@ module ConceptQL
|
|
126
126
|
end
|
127
127
|
|
128
128
|
class DefineNode < DotNode
|
129
|
-
def initialize(*args)
|
130
|
-
@gn = args.pop
|
131
|
-
super(*args)
|
132
|
-
end
|
133
|
-
|
134
|
-
def types
|
135
|
-
@gn.types[namify(arguments.first)] = super
|
136
|
-
end
|
137
|
-
|
138
129
|
def shape
|
139
130
|
:cds
|
140
131
|
end
|
141
132
|
end
|
142
133
|
|
143
134
|
class RecallNode < DotNode
|
144
|
-
def initialize(*args)
|
145
|
-
@gn = args.pop
|
146
|
-
super(*args)
|
147
|
-
end
|
148
|
-
|
149
|
-
def types
|
150
|
-
@gn.types[namify(arguments.first)]
|
151
|
-
end
|
152
|
-
|
153
135
|
def shape
|
154
136
|
:cds
|
155
137
|
end
|
@@ -176,9 +158,9 @@ module ConceptQL
|
|
176
158
|
if BINARY_OPERATOR_TYPES.include?(type)
|
177
159
|
return BinaryOperatorNode.new(type, values)
|
178
160
|
elsif type == :define
|
179
|
-
return DefineNode.new(type, values
|
161
|
+
return DefineNode.new(type, values).tap { |n| n.tree = self }
|
180
162
|
elsif type == :recall
|
181
|
-
return RecallNode.new(type, values
|
163
|
+
return RecallNode.new(type, values).tap { |n| n.tree = self }
|
182
164
|
elsif type == :vsac
|
183
165
|
types = values.pop
|
184
166
|
return VsacNode.new(type, values, types)
|
@@ -10,9 +10,9 @@ module ConceptQL
|
|
10
10
|
class DateRange < Node
|
11
11
|
def query(db)
|
12
12
|
db.from(:person)
|
13
|
-
.select_append(Sequel.
|
13
|
+
.select_append(Sequel.cast_string('person').as(:criterion_type))
|
14
14
|
.select_append(Sequel.expr(:person_id).as(:criterion_id))
|
15
|
-
.select_append(Sequel.
|
15
|
+
.select_append(Sequel.lit('date ?', start_date(db)).as(:start_date), Sequel.lit('date ?', end_date(db)).as(:end_date)).from_self
|
16
16
|
end
|
17
17
|
|
18
18
|
def types
|
@@ -31,8 +31,8 @@ module ConceptQL
|
|
31
31
|
# TODO: Select the earliest and latest dates of observation from
|
32
32
|
# the proper CDM table to represent the start and end of data
|
33
33
|
def date_from(db, str)
|
34
|
-
return db.from(:
|
35
|
-
return db.from(:
|
34
|
+
return db.from(:visit_occurrence).select { min(:start_date) } if str.upcase == 'START'
|
35
|
+
return db.from(:visit_occurrence).select { max(:end_date) } if str.upcase == 'END'
|
36
36
|
return str
|
37
37
|
end
|
38
38
|
end
|
@@ -15,7 +15,6 @@ module ConceptQL
|
|
15
15
|
class Define < Node
|
16
16
|
def initialize(*args)
|
17
17
|
super
|
18
|
-
tree.defined[table_name] = self
|
19
18
|
end
|
20
19
|
# Create a temporary table and store the stream of results in that table.
|
21
20
|
# This "caches" the results so we only have to execute stream's query
|
@@ -55,6 +54,11 @@ module ConceptQL
|
|
55
54
|
db[db.send(:create_table_as_sql, table_name, stream.evaluate(db).sql, temp: true)].sql
|
56
55
|
end
|
57
56
|
|
57
|
+
def tree=(tree)
|
58
|
+
super
|
59
|
+
tree.defined[table_name] = self
|
60
|
+
end
|
61
|
+
|
58
62
|
private
|
59
63
|
|
60
64
|
def table_name
|
data/lib/conceptql/nodes/node.rb
CHANGED
@@ -3,8 +3,8 @@ module ConceptQL
|
|
3
3
|
module Nodes
|
4
4
|
class Node
|
5
5
|
attr :values, :options
|
6
|
-
|
7
|
-
|
6
|
+
attr_accessor :tree
|
7
|
+
def initialize(*args)
|
8
8
|
args.flatten!
|
9
9
|
if args.last.is_a?(Hash)
|
10
10
|
@options = args.pop.symbolize_keys
|
@@ -23,7 +23,7 @@ module ConceptQL
|
|
23
23
|
|
24
24
|
def select_it(query, specific_type = nil)
|
25
25
|
specific_type = type if specific_type.nil? && respond_to?(:type)
|
26
|
-
query.select(*columns(specific_type))
|
26
|
+
query.select(*columns(query, specific_type))
|
27
27
|
end
|
28
28
|
|
29
29
|
def types
|
@@ -42,14 +42,14 @@ module ConceptQL
|
|
42
42
|
@arguments ||= values.reject { |v| v.is_a?(Node) }
|
43
43
|
end
|
44
44
|
|
45
|
-
def columns(local_type = nil)
|
45
|
+
def columns(query, local_type = nil)
|
46
46
|
criterion_type = Sequel.expr(:criterion_type)
|
47
47
|
if local_type
|
48
|
-
criterion_type = Sequel.
|
48
|
+
criterion_type = Sequel.cast_string(local_type.to_s)
|
49
49
|
end
|
50
50
|
[:person_id___person_id,
|
51
51
|
Sequel.expr(type_id(local_type)).as(:criterion_id),
|
52
|
-
criterion_type.as(:criterion_type)] + date_columns(local_type)
|
52
|
+
criterion_type.as(:criterion_type)] + date_columns(query, local_type)
|
53
53
|
end
|
54
54
|
|
55
55
|
private
|
@@ -83,23 +83,23 @@ module ConceptQL
|
|
83
83
|
"#{table}___tab".to_sym
|
84
84
|
end
|
85
85
|
|
86
|
-
def date_columns(type = nil)
|
86
|
+
def date_columns(query, type = nil)
|
87
87
|
return [:start_date, :end_date] unless type
|
88
|
-
sd = start_date_column(type)
|
88
|
+
sd = start_date_column(query, type)
|
89
89
|
sd = Sequel.expr(sd).cast(:date).as(:start_date) unless sd == :start_date
|
90
|
-
ed = end_date_column(type)
|
90
|
+
ed = end_date_column(query, type)
|
91
91
|
ed = Sequel.expr(ed).cast(:date).as(:end_date) unless ed == :end_date
|
92
92
|
[sd, ed]
|
93
93
|
end
|
94
94
|
|
95
|
-
def start_date_column(type)
|
95
|
+
def start_date_column(query, type)
|
96
96
|
{
|
97
97
|
condition_occurrence: :condition_start_date,
|
98
98
|
death: :death_date,
|
99
99
|
drug_exposure: :drug_exposure_start_date,
|
100
100
|
drug_cost: nil,
|
101
101
|
payer_plan_period: :payer_plan_period_start_date,
|
102
|
-
person: person_date_of_birth,
|
102
|
+
person: person_date_of_birth(query),
|
103
103
|
procedure_occurrence: :procedure_date,
|
104
104
|
procedure_cost: nil,
|
105
105
|
observation: :observation_date,
|
@@ -107,14 +107,14 @@ module ConceptQL
|
|
107
107
|
}[type]
|
108
108
|
end
|
109
109
|
|
110
|
-
def end_date_column(type)
|
110
|
+
def end_date_column(query, type)
|
111
111
|
{
|
112
112
|
condition_occurrence: :condition_end_date,
|
113
113
|
death: :death_date,
|
114
114
|
drug_exposure: :drug_exposure_end_date,
|
115
115
|
drug_cost: nil,
|
116
116
|
payer_plan_period: :payer_plan_period_end_date,
|
117
|
-
person: person_date_of_birth,
|
117
|
+
person: person_date_of_birth(query),
|
118
118
|
procedure_occurrence: :procedure_date,
|
119
119
|
procedure_cost: nil,
|
120
120
|
observation: :observation_date,
|
@@ -122,16 +122,21 @@ module ConceptQL
|
|
122
122
|
}[type]
|
123
123
|
end
|
124
124
|
|
125
|
-
def person_date_of_birth
|
126
|
-
assemble_date(:year_of_birth, :month_of_birth, :day_of_birth)
|
125
|
+
def person_date_of_birth(query)
|
126
|
+
assemble_date(query, :year_of_birth, :month_of_birth, :day_of_birth)
|
127
127
|
end
|
128
128
|
|
129
|
-
def assemble_date(*symbols)
|
129
|
+
def assemble_date(query, *symbols)
|
130
130
|
strings = symbols.map do |symbol|
|
131
|
-
Sequel.function(:coalesce, Sequel.
|
131
|
+
Sequel.cast_string(Sequel.function(:coalesce, Sequel.cast_string(symbol), Sequel.cast_string('01')))
|
132
132
|
end
|
133
133
|
strings = strings.zip(['-'] * (symbols.length - 1)).flatten.compact
|
134
|
-
|
134
|
+
concatted_strings = Sequel.join(strings)
|
135
|
+
unless query.db.database_type == :oracle
|
136
|
+
Sequel.cast(concatted_strings, Date)
|
137
|
+
else
|
138
|
+
Sequel.function(:to_date, concatted_strings, 'YYYY-MM-DD')
|
139
|
+
end
|
135
140
|
end
|
136
141
|
|
137
142
|
def determine_types
|
@@ -23,8 +23,10 @@ module ConceptQL
|
|
23
23
|
# occurrence, this node returns nothing for that person
|
24
24
|
class Occurrence < Node
|
25
25
|
def query(db)
|
26
|
-
|
27
|
-
.
|
26
|
+
stream.evaluate(db)
|
27
|
+
.from_self
|
28
|
+
.select_append { |o| o.row_number(:over, partition: :person_id, order: ordered_columns){}.as(:rn) }
|
29
|
+
.from_self
|
28
30
|
.where(rn: occurrence.abs)
|
29
31
|
end
|
30
32
|
|
@@ -10,7 +10,7 @@ module ConceptQL
|
|
10
10
|
class TemporalNode < BinaryOperatorNode
|
11
11
|
def query(db)
|
12
12
|
db.from(db.from(left_stream(db))
|
13
|
-
.join(right_stream(db),
|
13
|
+
.join(right_stream(db), l__person_id: :r__person_id)
|
14
14
|
.where(where_clause)
|
15
15
|
.select_all(:l))
|
16
16
|
end
|
@@ -21,11 +21,12 @@ module ConceptQL
|
|
21
21
|
# start: 'd', end: '' # Only adjust start_date by positive 1 day and leave end_date uneffected
|
22
22
|
class TimeWindow < Node
|
23
23
|
def query(db)
|
24
|
+
db.extension :date_arithmetic
|
24
25
|
db.from(stream.evaluate(db))
|
25
26
|
end
|
26
27
|
|
27
28
|
private
|
28
|
-
def date_columns(type = nil)
|
29
|
+
def date_columns(query, type = nil)
|
29
30
|
[adjusted_start_date, adjusted_end_date]
|
30
31
|
end
|
31
32
|
|
@@ -44,8 +45,12 @@ module ConceptQL
|
|
44
45
|
arg ||= ''
|
45
46
|
return ['end_date', column].join('___').to_sym if arg.downcase == 'end'
|
46
47
|
return ['start_date', column].join('___').to_sym if arg.downcase == 'start'
|
47
|
-
DateAdjuster.new(arg).adjustments.inject(Sequel.
|
48
|
-
|
48
|
+
DateAdjuster.new(arg).adjustments.inject(Sequel.expr(column)) do |sql, (units, quantity)|
|
49
|
+
if quantity > 0
|
50
|
+
Sequel.date_add(sql, units => quantity)
|
51
|
+
else
|
52
|
+
Sequel.date_sub(sql, units => quantity.abs)
|
53
|
+
end
|
49
54
|
end.as(column)
|
50
55
|
end
|
51
56
|
end
|
data/lib/conceptql/nodifier.rb
CHANGED
@@ -3,7 +3,9 @@ module ConceptQL
|
|
3
3
|
class Nodifier
|
4
4
|
def create(type, values, tree)
|
5
5
|
require_relative "nodes/#{type}"
|
6
|
-
"conceptQL/nodes/#{type}".camelize.constantize.new(
|
6
|
+
node = "conceptQL/nodes/#{type}".camelize.constantize.new(values)
|
7
|
+
node.tree = tree
|
8
|
+
node
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
data/lib/conceptql/version.rb
CHANGED
@@ -80,8 +80,8 @@ describe ConceptQL::Behaviors::Dottable do
|
|
80
80
|
mock.types
|
81
81
|
end
|
82
82
|
|
83
|
-
def link_to(mock_graph, mock_node)
|
84
|
-
mock.link_to(mock_graph, mock_node)
|
83
|
+
def link_to(mock_graph, mock_node, db)
|
84
|
+
mock.link_to(mock_graph, mock_node, db)
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
@@ -95,7 +95,7 @@ describe ConceptQL::Behaviors::Dottable do
|
|
95
95
|
mock_child = MockChild.new
|
96
96
|
mock_child.mock = Minitest::Mock.new
|
97
97
|
mock_child.mock.expect :graph_it, :child_node, [mock_graph, :db]
|
98
|
-
mock_child.mock.expect :link_to, nil, [mock_graph, mock_node]
|
98
|
+
mock_child.mock.expect :link_to, nil, [mock_graph, mock_node, :db]
|
99
99
|
|
100
100
|
mock_child.must_behave_like(:node)
|
101
101
|
|
@@ -16,51 +16,51 @@ describe ConceptQL::DateAdjuster do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'returns single day for input of "1"' do
|
19
|
-
ConceptQL::DateAdjuster.new('1').adjustments.must_equal [
|
19
|
+
ConceptQL::DateAdjuster.new('1').adjustments.must_equal [[: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 [
|
23
|
+
ConceptQL::DateAdjuster.new('20').adjustments.must_equal [[: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 [
|
27
|
+
ConceptQL::DateAdjuster.new('d').adjustments.must_equal [[: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 [
|
31
|
+
ConceptQL::DateAdjuster.new('m').adjustments.must_equal [[: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 [
|
35
|
+
ConceptQL::DateAdjuster.new('y').adjustments.must_equal [[: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 [
|
39
|
+
ConceptQL::DateAdjuster.new('2d').adjustments.must_equal [[: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 [
|
43
|
+
ConceptQL::DateAdjuster.new('2m').adjustments.must_equal [[: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 [
|
47
|
+
ConceptQL::DateAdjuster.new('2y').adjustments.must_equal [[: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 [
|
51
|
+
ConceptQL::DateAdjuster.new('-d').adjustments.must_equal [[: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 [
|
55
|
+
ConceptQL::DateAdjuster.new('-dm').adjustments.must_equal [[: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 [
|
59
|
+
ConceptQL::DateAdjuster.new('-2d').adjustments.must_equal [[: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 [
|
63
|
+
ConceptQL::DateAdjuster.new('2d').adjustments.must_equal [[:days, 2]]
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -49,8 +49,8 @@ describe ConceptQL::Nodes::CastingNode do
|
|
49
49
|
stream = StreamForCastingDouble.new
|
50
50
|
stream.types = [:i_point1]
|
51
51
|
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
52
|
-
sql.must_match '
|
53
|
-
sql.must_match
|
52
|
+
sql.must_match 'i_point1_id IN'
|
53
|
+
sql.must_match "criterion_type = 'i_point1'"
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'uses and unions multiple castable types if possible' do
|
@@ -58,14 +58,13 @@ describe ConceptQL::Nodes::CastingNode do
|
|
58
58
|
stream.types = [:i_point1, :at_me2]
|
59
59
|
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
60
60
|
sql.must_match 'my_type_id IN'
|
61
|
-
sql.must_match '
|
62
|
-
sql.must_match
|
63
|
-
sql.must_match 'UNION'
|
61
|
+
sql.must_match 'i_point1_id IN'
|
62
|
+
sql.must_match "criterion_type = 'i_point1'"
|
64
63
|
end
|
65
64
|
|
66
65
|
it 'returns all rows of a table if passed the argument "true"' do
|
67
66
|
sql = CastingDouble.new(true).query(Sequel.mock).sql
|
68
|
-
sql.must_match "SELECT * FROM
|
67
|
+
sql.must_match "SELECT * FROM my_type AS tab"
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
@@ -10,6 +10,6 @@ describe ConceptQL::Nodes::Complement do
|
|
10
10
|
it 'generates complement for single criteria' do
|
11
11
|
double1 = QueryDouble.new(1)
|
12
12
|
double1.must_behave_like(:evaluator)
|
13
|
-
ConceptQL::Nodes::Complement.new(double1).query(Sequel.mock).sql.must_equal "SELECT
|
13
|
+
ConceptQL::Nodes::Complement.new(double1).query(Sequel.mock).sql.must_equal "SELECT * FROM (SELECT person_id AS person_id, visit_occurrence_id AS criterion_id, CAST('visit_occurrence' AS varchar(255)) AS criterion_type, CAST(visit_start_date AS date) AS start_date, CAST(visit_end_date AS date) AS end_date FROM visit_occurrence AS tab WHERE (visit_occurrence_id NOT IN (SELECT criterion_id FROM (SELECT * FROM table1) AS t1 WHERE ((criterion_id IS NOT NULL) AND (criterion_type = 'visit_occurrence'))))) AS t1"
|
14
14
|
end
|
15
15
|
end
|
@@ -8,102 +8,102 @@ describe ConceptQL::Nodes::ConditionType do
|
|
8
8
|
|
9
9
|
describe '#query' do
|
10
10
|
it 'works for inpatient_detail_primary' do
|
11
|
-
correct_query = "SELECT * FROM
|
11
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000183))"
|
12
12
|
ConceptQL::Nodes::ConditionType.new(:inpatient_detail_primary).query(Sequel.mock).sql.must_equal correct_query
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'works for inpatient_detail_1' do
|
16
|
-
correct_query = "SELECT * FROM
|
16
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000184))"
|
17
17
|
ConceptQL::Nodes::ConditionType.new(:inpatient_detail_1).query(Sequel.mock).sql.must_equal correct_query
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'works for inpatient_detail_2' do
|
21
|
-
correct_query = "SELECT * FROM
|
21
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000185))"
|
22
22
|
ConceptQL::Nodes::ConditionType.new(:inpatient_detail_2).query(Sequel.mock).sql.must_equal correct_query
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'works for inpatient_header_primary' do
|
26
|
-
correct_query = "SELECT * FROM
|
26
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000199))"
|
27
27
|
ConceptQL::Nodes::ConditionType.new(:inpatient_header_primary).query(Sequel.mock).sql.must_equal correct_query
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'works for inpatient_header_1' do
|
31
|
-
correct_query = "SELECT * FROM
|
31
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000200))"
|
32
32
|
ConceptQL::Nodes::ConditionType.new(:inpatient_header_1).query(Sequel.mock).sql.must_equal correct_query
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'works for outpatient_detail_1' do
|
36
|
-
correct_query = "SELECT * FROM
|
36
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000215))"
|
37
37
|
ConceptQL::Nodes::ConditionType.new(:outpatient_detail_1).query(Sequel.mock).sql.must_equal correct_query
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'works for outpatient_header_1' do
|
41
|
-
correct_query = "SELECT * FROM
|
41
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000230))"
|
42
42
|
ConceptQL::Nodes::ConditionType.new(:outpatient_header_1).query(Sequel.mock).sql.must_equal correct_query
|
43
43
|
end
|
44
44
|
|
45
45
|
it 'works for ehr_problem_list' do
|
46
|
-
correct_query = "SELECT * FROM
|
46
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000245))"
|
47
47
|
ConceptQL::Nodes::ConditionType.new(:ehr_problem_list).query(Sequel.mock).sql.must_equal correct_query
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'works for condition_era_0_day_window' do
|
51
|
-
correct_query = "SELECT * FROM
|
51
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000246))"
|
52
52
|
ConceptQL::Nodes::ConditionType.new(:condition_era_0_day_window).query(Sequel.mock).sql.must_equal correct_query
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'works for condition_era_30_day_window' do
|
56
|
-
correct_query = "SELECT * FROM
|
56
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000247))"
|
57
57
|
ConceptQL::Nodes::ConditionType.new(:condition_era_30_day_window).query(Sequel.mock).sql.must_equal correct_query
|
58
58
|
end
|
59
59
|
|
60
60
|
describe 'with multiple arguments' do
|
61
61
|
it 'works for inpatient_detail_1' do
|
62
|
-
correct_query = "SELECT * FROM
|
62
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000184, 38000185))"
|
63
63
|
ConceptQL::Nodes::ConditionType.new(:inpatient_detail_1, :inpatient_detail_2).query(Sequel.mock).sql.must_equal correct_query
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
describe 'with arguments as strings' do
|
68
68
|
it 'works for inpatient_detail_1' do
|
69
|
-
correct_query = "SELECT * FROM
|
69
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000184, 38000185))"
|
70
70
|
ConceptQL::Nodes::ConditionType.new('inpatient_detail_1', 'inpatient_detail_2').query(Sequel.mock).sql.must_equal correct_query
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
describe 'as category' do
|
75
75
|
it 'works for inpatient_detail' do
|
76
|
-
correct_query = "SELECT * FROM
|
76
|
+
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
77
|
ConceptQL::Nodes::ConditionType.new('inpatient_detail').query(Sequel.mock).sql.must_equal correct_query
|
78
78
|
end
|
79
79
|
|
80
80
|
it 'works for inpatient_header' do
|
81
|
-
correct_query = "SELECT * FROM
|
81
|
+
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
82
|
ConceptQL::Nodes::ConditionType.new('inpatient_header').query(Sequel.mock).sql.must_equal correct_query
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'works for inpatient' do
|
86
|
-
correct_query = "SELECT * FROM
|
86
|
+
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
87
|
ConceptQL::Nodes::ConditionType.new('inpatient').query(Sequel.mock).sql.must_equal correct_query
|
88
88
|
end
|
89
89
|
|
90
90
|
it 'works for outpatient_detail' do
|
91
|
-
correct_query = "SELECT * FROM
|
91
|
+
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
92
|
ConceptQL::Nodes::ConditionType.new('outpatient_detail').query(Sequel.mock).sql.must_equal correct_query
|
93
93
|
end
|
94
94
|
|
95
95
|
it 'works for outpatient_header' do
|
96
|
-
correct_query = "SELECT * FROM
|
96
|
+
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
97
|
ConceptQL::Nodes::ConditionType.new('outpatient_header').query(Sequel.mock).sql.must_equal correct_query
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'works for outpatient' do
|
101
|
-
correct_query = "SELECT * FROM
|
101
|
+
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
102
|
ConceptQL::Nodes::ConditionType.new('outpatient').query(Sequel.mock).sql.must_equal correct_query
|
103
103
|
end
|
104
104
|
|
105
105
|
it 'works for condition_era' do
|
106
|
-
correct_query = "SELECT * FROM
|
106
|
+
correct_query = "SELECT * FROM condition_occurrence WHERE (condition_type_concept_id IN (38000246, 38000247))"
|
107
107
|
ConceptQL::Nodes::ConditionType.new('condition_era').query(Sequel.mock).sql.must_equal correct_query
|
108
108
|
end
|
109
109
|
end
|
@@ -14,19 +14,19 @@ describe ConceptQL::Nodes::DateRange do
|
|
14
14
|
|
15
15
|
describe '#query' do
|
16
16
|
it 'should be dates specified assigned to all persons' do
|
17
|
-
ConceptQL::Nodes::DateRange.new(start: '2004-12-13', end: '2010-03-20').query(Sequel.mock).sql.must_equal("SELECT * FROM (SELECT *, CAST('2004-12-13' AS
|
17
|
+
ConceptQL::Nodes::DateRange.new(start: '2004-12-13', end: '2010-03-20').query(Sequel.mock).sql.must_equal("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")
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'should handle strings for option keys' do
|
21
|
-
ConceptQL::Nodes::DateRange.new('start' => '2004-12-13', 'end' => '2010-03-20').query(Sequel.mock).sql.must_equal("SELECT * FROM (SELECT *, CAST('2004-12-13' AS
|
21
|
+
ConceptQL::Nodes::DateRange.new('start' => '2004-12-13', 'end' => '2010-03-20').query(Sequel.mock).sql.must_equal("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")
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'handles START as day before first recorded visit_occurrence' do
|
25
|
-
ConceptQL::Nodes::DateRange.new(start: 'START', end: '2010-03-20').query(Sequel.mock).sql.must_equal("SELECT * FROM (SELECT *, CAST((SELECT min(start_date) FROM
|
25
|
+
ConceptQL::Nodes::DateRange.new(start: 'START', end: '2010-03-20').query(Sequel.mock).sql.must_equal("SELECT * FROM (SELECT *, CAST('person' AS varchar(255)) AS criterion_type, person_id AS criterion_id, date (SELECT min(start_date) FROM visit_occurrence) AS start_date, date '2010-03-20' AS end_date FROM person) AS t1")
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'handles END as 2010-12-31' do
|
29
|
-
ConceptQL::Nodes::DateRange.new(start: '2004-12-13', end: 'END').query(Sequel.mock).sql.must_equal("SELECT * FROM (SELECT *, CAST('2004-12-13' AS
|
29
|
+
ConceptQL::Nodes::DateRange.new(start: '2004-12-13', end: 'END').query(Sequel.mock).sql.must_equal("SELECT * FROM (SELECT *, CAST('person' AS varchar(255)) AS criterion_type, person_id AS criterion_id, date '2004-12-13' AS start_date, date (SELECT max(end_date) FROM visit_occurrence) AS end_date FROM person) AS t1")
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -8,7 +8,7 @@ describe ConceptQL::Nodes::Gender do
|
|
8
8
|
|
9
9
|
describe '#query' do
|
10
10
|
it 'works for male/MALE/Male/M/m' do
|
11
|
-
correct_query = "SELECT * FROM
|
11
|
+
correct_query = "SELECT * FROM person WHERE (gender_concept_id IN (8507))"
|
12
12
|
ConceptQL::Nodes::Gender.new('male').query(Sequel.mock).sql.must_equal correct_query
|
13
13
|
ConceptQL::Nodes::Gender.new('Male').query(Sequel.mock).sql.must_equal correct_query
|
14
14
|
ConceptQL::Nodes::Gender.new('MALE').query(Sequel.mock).sql.must_equal correct_query
|
@@ -17,7 +17,7 @@ describe ConceptQL::Nodes::Gender do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'works for Female/FEMALE/female/F/f' do
|
20
|
-
correct_query = "SELECT * FROM
|
20
|
+
correct_query = "SELECT * FROM person WHERE (gender_concept_id IN (8532))"
|
21
21
|
ConceptQL::Nodes::Gender.new('female').query(Sequel.mock).sql.must_equal correct_query
|
22
22
|
ConceptQL::Nodes::Gender.new('Female').query(Sequel.mock).sql.must_equal correct_query
|
23
23
|
ConceptQL::Nodes::Gender.new('FEMALE').query(Sequel.mock).sql.must_equal correct_query
|
@@ -13,7 +13,7 @@ describe ConceptQL::Nodes::Intersect do
|
|
13
13
|
double2 = QueryDouble.new(2)
|
14
14
|
double3 = QueryDouble.new(3)
|
15
15
|
double1.must_behave_like(:evaluator)
|
16
|
-
ConceptQL::Nodes::Intersect.new(double1, double2, double3).query(Sequel.mock).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table1 INTERSECT
|
16
|
+
ConceptQL::Nodes::Intersect.new(double1, double2, double3).query(Sequel.mock).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table1 INTERSECT SELECT * FROM table2) AS t1 INTERSECT SELECT * FROM table3) AS t1"
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'works for multiple criteria of different type' do
|
@@ -21,7 +21,7 @@ describe ConceptQL::Nodes::Intersect do
|
|
21
21
|
double2 = QueryDouble.new(2, :person)
|
22
22
|
double3 = QueryDouble.new(3)
|
23
23
|
double1.must_behave_like(:evaluator)
|
24
|
-
ConceptQL::Nodes::Intersect.new(double1, double2, double3).query(Sequel.mock).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table1 INTERSECT
|
24
|
+
ConceptQL::Nodes::Intersect.new(double1, double2, double3).query(Sequel.mock).sql.must_equal "SELECT * FROM (SELECT * FROM (SELECT * FROM table1 INTERSECT SELECT * FROM table3) AS t1 UNION ALL SELECT * FROM table2) AS t1"
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'works for single criteria' do
|
@@ -8,17 +8,17 @@ describe ConceptQL::Nodes::PlaceOfServiceCode do
|
|
8
8
|
|
9
9
|
describe '#query' do
|
10
10
|
it 'works for 23' do
|
11
|
-
correct_query = "SELECT * FROM
|
11
|
+
correct_query = "SELECT * FROM visit_occurrence AS v INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = v.place_of_service_concept_id) WHERE ((vc.concept_code IN ('23')) AND (vc.vocabulary_id = 14))"
|
12
12
|
ConceptQL::Nodes::PlaceOfServiceCode.new('23').query(Sequel.mock).sql.must_equal correct_query
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'works for 23 as number' do
|
16
|
-
correct_query = "SELECT * FROM
|
16
|
+
correct_query = "SELECT * FROM visit_occurrence AS v INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = v.place_of_service_concept_id) WHERE ((vc.concept_code IN ('23')) AND (vc.vocabulary_id = 14))"
|
17
17
|
ConceptQL::Nodes::PlaceOfServiceCode.new(23).query(Sequel.mock).sql.must_equal correct_query
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'works for multiple values' do
|
21
|
-
correct_query = "SELECT * FROM
|
21
|
+
correct_query = "SELECT * FROM visit_occurrence AS v INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = v.place_of_service_concept_id) WHERE ((vc.concept_code IN ('23', '22')) AND (vc.vocabulary_id = 14))"
|
22
22
|
ConceptQL::Nodes::PlaceOfServiceCode.new('23', '22').query(Sequel.mock).sql.must_equal correct_query
|
23
23
|
end
|
24
24
|
end
|
@@ -8,13 +8,13 @@ describe ConceptQL::Nodes::Race do
|
|
8
8
|
|
9
9
|
describe '#query' do
|
10
10
|
it 'works for white' do
|
11
|
-
correct_query = "SELECT * FROM
|
11
|
+
correct_query = "SELECT * FROM person AS p INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = p.race_concept_id) WHERE (lower(vc.concept_name) IN ('white'))"
|
12
12
|
ConceptQL::Nodes::Race.new('White').query(Sequel.mock).sql.must_equal correct_query
|
13
13
|
ConceptQL::Nodes::Race.new('white').query(Sequel.mock).sql.must_equal correct_query
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'works for multiple values' do
|
17
|
-
correct_query = "SELECT * FROM
|
17
|
+
correct_query = "SELECT * FROM person AS p INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = p.race_concept_id) WHERE (lower(vc.concept_name) IN ('white', 'other'))"
|
18
18
|
ConceptQL::Nodes::Race.new('White', 'Other').query(Sequel.mock).sql.must_equal correct_query
|
19
19
|
ConceptQL::Nodes::Race.new('white', 'other').query(Sequel.mock).sql.must_equal correct_query
|
20
20
|
end
|
@@ -26,11 +26,11 @@ describe ConceptQL::Nodes::SourceVocabularyNode do
|
|
26
26
|
|
27
27
|
describe '#query' do
|
28
28
|
it 'works for single values' do
|
29
|
-
SourceVocabularyDouble.new('value').query(Sequel.mock).sql.must_equal "SELECT * FROM
|
29
|
+
SourceVocabularyDouble.new('value').query(Sequel.mock).sql.must_equal "SELECT * FROM table AS tab INNER JOIN vocabulary.source_to_concept_map AS scm ON (scm.target_concept_id = tab.concept_column) WHERE ((scm.source_code IN ('value')) AND (scm.source_vocabulary_id = 1) AND (scm.source_code = tab.source_column))"
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'works for multiple values' do
|
33
|
-
SourceVocabularyDouble.new('value1', 'value2').query(Sequel.mock).sql.must_equal "SELECT * FROM
|
33
|
+
SourceVocabularyDouble.new('value1', 'value2').query(Sequel.mock).sql.must_equal "SELECT * FROM table AS tab INNER JOIN vocabulary.source_to_concept_map AS scm ON (scm.target_concept_id = tab.concept_column) WHERE ((scm.source_code IN ('value1', 'value2')) AND (scm.source_vocabulary_id = 1) AND (scm.source_code = tab.source_column))"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -28,11 +28,11 @@ describe ConceptQL::Nodes::StandardVocabularyNode do
|
|
28
28
|
|
29
29
|
describe '#query' do
|
30
30
|
it 'works for single values' do
|
31
|
-
StandardVocabularyDouble.new('value').query(Sequel.mock).sql.must_equal "SELECT * FROM
|
31
|
+
StandardVocabularyDouble.new('value').query(Sequel.mock).sql.must_equal "SELECT * FROM table AS tab INNER JOIN vocabulary.concept AS c ON (c.concept_id = tab.concept_column) WHERE ((c.concept_code IN ('value')) AND (c.vocabulary_id = 1))"
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'works for multiple diagnoses' do
|
35
|
-
StandardVocabularyDouble.new('value1', 'value2').query(Sequel.mock).sql.must_equal "SELECT * FROM
|
35
|
+
StandardVocabularyDouble.new('value1', 'value2').query(Sequel.mock).sql.must_equal "SELECT * FROM table AS tab INNER JOIN vocabulary.concept AS c ON (c.concept_id = tab.concept_column) WHERE ((c.concept_code IN ('value1', 'value2')) AND (c.vocabulary_id = 1))"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -13,52 +13,71 @@ describe ConceptQL::Nodes::TimeWindow do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
before do
|
17
|
+
@db_mock = Sequel.mock
|
18
|
+
@sequel_mock = Minitest::Mock.new
|
19
|
+
@sequel_mock.expect :expr, @sequel_mock, [:start_date]
|
20
|
+
@sequel_mock.expect :expr, @sequel_mock, [:end_date]
|
21
|
+
@sequel_mock.expect :as, @sequel_mock, [:start_date]
|
22
|
+
@sequel_mock.expect :as, @sequel_mock, [:end_date]
|
23
|
+
end
|
24
|
+
|
16
25
|
describe '#evaluate' do
|
17
26
|
it 'adjusts start by 1 day' do
|
18
|
-
|
19
|
-
|
20
|
-
|
27
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, days: 1]
|
28
|
+
|
29
|
+
stub_const(ConceptQL::Nodes::TimeWindow, :Sequel, @sequel_mock) do
|
30
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'd', end: '' }).evaluate(@db_mock)
|
31
|
+
end
|
32
|
+
@sequel_mock.verify
|
21
33
|
end
|
22
34
|
|
23
35
|
it 'adjusts start by 1 day' do
|
24
|
-
|
25
|
-
|
26
|
-
|
36
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, days: 1]
|
37
|
+
stub_const(ConceptQL::Nodes::TimeWindow, :Sequel, @sequel_mock) do
|
38
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: '', end: 'd' }).evaluate(@db_mock)
|
39
|
+
end
|
40
|
+
@sequel_mock.verify
|
27
41
|
end
|
28
42
|
|
29
43
|
it 'adjusts both values by 1 day' do
|
30
|
-
|
31
|
-
|
44
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, days: 1]
|
45
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, days: 1]
|
46
|
+
stub_const(ConceptQL::Nodes::TimeWindow, :Sequel, @sequel_mock) do
|
47
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'd', end: 'd' }).evaluate(@db_mock)
|
48
|
+
end
|
49
|
+
@sequel_mock.verify
|
32
50
|
end
|
33
51
|
|
34
52
|
it 'makes multiple adjustments to both values' do
|
35
|
-
|
36
|
-
|
37
|
-
|
53
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, days: 1]
|
54
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, months: 1]
|
55
|
+
@sequel_mock.expect :date_add, @sequel_mock, [@sequel_mock, years: 1]
|
56
|
+
|
57
|
+
@sequel_mock.expect :date_sub, @sequel_mock, [@sequel_mock, days: 1]
|
58
|
+
@sequel_mock.expect :date_sub, @sequel_mock, [@sequel_mock, months: 1]
|
59
|
+
@sequel_mock.expect :date_sub, @sequel_mock, [@sequel_mock, years: 1]
|
60
|
+
|
61
|
+
stub_const(ConceptQL::Nodes::TimeWindow, :Sequel, @sequel_mock) do
|
62
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'dmy', end: '-d-m-y' }).evaluate(@db_mock)
|
63
|
+
end
|
64
|
+
@sequel_mock.verify
|
38
65
|
end
|
39
66
|
|
40
67
|
it 'can set start_date to be end_date' do
|
41
|
-
|
42
|
-
sql.must_match(%q{end_date AS start_date})
|
43
|
-
sql.must_match(%q{date(end_date) AS end_date})
|
68
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'end', end: '' }).evaluate(@db_mock)
|
44
69
|
end
|
45
70
|
|
46
71
|
it 'can set end_date to be start_date' do
|
47
|
-
|
48
|
-
sql.must_match(%q{start_date AS end_date})
|
49
|
-
sql.must_match(%q{date(start_date) AS start_date})
|
72
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: '', end: 'start' }).evaluate(@db_mock)
|
50
73
|
end
|
51
74
|
|
52
75
|
it 'will swap start and end dates, though this is a bad idea but you should probably know about this' do
|
53
|
-
|
54
|
-
sql.must_match(%q{start_date AS end_date})
|
55
|
-
sql.must_match(%q{end_date AS start_date})
|
76
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'end', end: 'start' }).evaluate(@db_mock)
|
56
77
|
end
|
57
78
|
|
58
79
|
it 'handles nil arguments to both start and end' do
|
59
|
-
|
60
|
-
sql.must_match(%q{date(start_date) AS start_date})
|
61
|
-
sql.must_match(%q{date(end_date) AS end_date})
|
80
|
+
ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: nil, end: nil }).evaluate(@db_mock)
|
62
81
|
end
|
63
82
|
end
|
64
83
|
end
|
@@ -7,10 +7,11 @@ describe ConceptQL::Query do
|
|
7
7
|
yaml = Psych.dump({ icd9: '799.22' })
|
8
8
|
mock_tree = Minitest::Mock.new
|
9
9
|
mock_node = Minitest::Mock.new
|
10
|
+
mock_query = Minitest::Mock.new
|
10
11
|
|
11
12
|
query = ConceptQL::Query.new(:mock_db, yaml, mock_tree)
|
12
13
|
mock_tree.expect :root, mock_node, [query]
|
13
|
-
mock_node.expect :
|
14
|
+
mock_node.expect :map, [mock_query]
|
14
15
|
query.query
|
15
16
|
|
16
17
|
mock_node.verify
|
data/spec/conceptql/tree_spec.rb
CHANGED
@@ -15,39 +15,39 @@ describe ConceptQL::Tree do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should walk single node criteria tree and convert to node' do
|
18
|
-
@mock_nodifier.expect :create, :success_indicator, [:icd9, '799.22']
|
18
|
+
@mock_nodifier.expect :create, :success_indicator, [:icd9, '799.22', @tree]
|
19
19
|
@mock_query_obj.expect :statement, { icd9: '799.22' }
|
20
20
|
|
21
|
-
@tree.root(@mock_query_obj).must_equal :success_indicator
|
21
|
+
@tree.root(@mock_query_obj).must_equal [:success_indicator]
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'should extend all nodes created with behavior passed in' do
|
25
25
|
mock_icd9_obj = Minitest::Mock.new
|
26
26
|
mock_icd9_obj.expect :extend, nil, [:mock_behavior]
|
27
27
|
|
28
|
-
|
28
|
+
tree = ConceptQL::Tree.new(nodifier: @mock_nodifier, behavior: :mock_behavior)
|
29
|
+
@mock_nodifier.expect :create, mock_icd9_obj, [:icd9, '799.22', tree]
|
29
30
|
@mock_query_obj.expect :statement, { icd9: '799.22' }
|
30
31
|
|
31
|
-
tree = ConceptQL::Tree.new(nodifier: @mock_nodifier, behavior: :mock_behavior)
|
32
32
|
tree.root(@mock_query_obj)
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'should walk multi-criteria node' do
|
36
|
-
@mock_nodifier.expect :create, :mock_icd9, [:icd9, '799.22']
|
37
|
-
@mock_nodifier.expect :create, :success_indicator, [:nth, { occurrence: 1, expression: :mock_icd9 }]
|
36
|
+
@mock_nodifier.expect :create, :mock_icd9, [:icd9, '799.22', @tree]
|
37
|
+
@mock_nodifier.expect :create, :success_indicator, [:nth, { occurrence: 1, expression: :mock_icd9 }, @tree]
|
38
38
|
|
39
39
|
@mock_query_obj.expect :statement, { nth: { occurrence: 1, expression: { icd9: '799.22' } } }
|
40
40
|
|
41
|
-
@tree.root(@mock_query_obj).must_equal :success_indicator
|
41
|
+
@tree.root(@mock_query_obj).must_equal [:success_indicator]
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'should walk multi-node criteria tree and convert to nodes' do
|
45
|
-
@mock_nodifier.expect :create, :mock_icd9, [:icd9, '799.22']
|
46
|
-
@mock_nodifier.expect :create, :success_indicator, [:any, [:mock_icd9]]
|
45
|
+
@mock_nodifier.expect :create, :mock_icd9, [:icd9, '799.22', @tree]
|
46
|
+
@mock_nodifier.expect :create, :success_indicator, [:any, [:mock_icd9], @tree]
|
47
47
|
|
48
48
|
@mock_query_obj.expect :statement, { any: [{ icd9: '799.22' }] }
|
49
49
|
|
50
|
-
@tree.root(@mock_query_obj).must_equal :success_indicator
|
50
|
+
@tree.root(@mock_query_obj).must_equal [:success_indicator]
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -6,6 +6,10 @@ class StreamForOccurrenceDouble < ConceptQL::Nodes::Node
|
|
6
6
|
ds
|
7
7
|
end
|
8
8
|
|
9
|
+
def evaluate(db)
|
10
|
+
query(db)
|
11
|
+
end
|
12
|
+
|
9
13
|
# Stole this from:
|
10
14
|
# https://github.com/jeremyevans/sequel/blob/63397b787335d06de97dc89ddf49b7a3a93ffdc9/spec/core/expression_filters_spec.rb#L400
|
11
15
|
#
|
data/spec/spec_helper.rb
CHANGED
@@ -72,3 +72,15 @@ def require_double(double_name)
|
|
72
72
|
p = p + 'spec' + 'doubles' + (double_name + '_double')
|
73
73
|
require(p.expand_path)
|
74
74
|
end
|
75
|
+
|
76
|
+
def stub_const(klass, const, replace, &block)
|
77
|
+
klass.send(:const_set, const, replace)
|
78
|
+
if block_given?
|
79
|
+
yield
|
80
|
+
remove_stubbed_const(klass, const)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def remove_stubbed_const(klass, const)
|
85
|
+
klass.send(:remove_const, const)
|
86
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conceptql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Duryea
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|