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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d18bbb657fb80b014eb554e98b1329f98ecb64f
4
- data.tar.gz: 80564c67d29d44af5c91cae68a0096eac546116b
3
+ metadata.gz: cd428ab59c2a551527b6a2d3382679559aeb1bdb
4
+ data.tar.gz: 9250fb01a96c2b4f735bac39a12e9d37e0ffa534
5
5
  SHA512:
6
- metadata.gz: 2bfa1b9efeae75d2d96c3565cc9ffe38398667e5d15afbf8c9c4d5d835c48da685eb74561262db103f86d8f880e4957ac3bd53ffc26816c5ceec73b065a09457
7
- data.tar.gz: 11a3813fdd1450c70b4f6aa866dffba16f2e22376ec6a625a77ef6840aeb777dbc8099ab3f40b78feae2080706ebdf40b0609d2cea017f89af5e67faee1823e0
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' => 'year',
20
- 'm' => 'month',
21
- 'd' => 'day'
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 ["#{str} days"] if str.match(/^[-+]?\d+$/)
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 += 's' if quantity.abs > 1
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, self)
161
+ return DefineNode.new(type, values).tap { |n| n.tree = self }
180
162
  elsif type == :recall
181
- return RecallNode.new(type, values, self)
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.cast('person', :text).as(:criterion_type))
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.expr(start_date(db)).cast(:date).as(:start_date),Sequel.expr(end_date(db)).cast(:date).as(:end_date)).from_self
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(:visit_occurrence_with_dates).select { min(:start_date) } if str.upcase == 'START'
35
- return db.from(:visit_occurrence_with_dates).select { max(:end_date) } if str.upcase == 'END'
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
@@ -17,7 +17,7 @@ module ConceptQL
17
17
  end
18
18
  typed_queries = exprs.map do |type, queries|
19
19
  queries.inject do |q, query|
20
- q.intersect(query, all: true)
20
+ q.intersect(query)
21
21
  end
22
22
  end
23
23
 
@@ -3,8 +3,8 @@ module ConceptQL
3
3
  module Nodes
4
4
  class Node
5
5
  attr :values, :options
6
- def initialize(tree, *args)
7
- @tree = tree
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.expr(local_type.to_s).cast(:text)
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.expr(symbol).cast(:text), Sequel.expr('01').cast(:text)).cast(:text)
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
- Sequel.function(:date, Sequel.join(strings))
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
- db.from(db.from(stream.evaluate(db))
27
- .select_append { |o| o.row_number(:over, partition: :person_id, order: ordered_columns){}.as(:rn) })
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), [:person_id])
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.function(:date, column)) do |sql, adjustment|
48
- Sequel.function(:date, sql + Sequel.lit("interval '#{adjustment}'"))
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
@@ -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(tree, values)
6
+ node = "conceptQL/nodes/#{type}".camelize.constantize.new(values)
7
+ node.tree = tree
8
+ node
7
9
  end
8
10
  end
9
11
  end
@@ -1,3 +1,3 @@
1
1
  module ConceptQL
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
@@ -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 ['1 days']
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 ['20 days']
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 ['1 day']
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 ['1 month']
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 ['1 year']
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 ['2 days']
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 ['2 months']
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 ['2 years']
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 ['-1 day']
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 ['-1 day', '1 month']
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 ['-2 days']
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 ['2 days']
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 'my_type_id IN'
53
- sql.must_match 'GROUP BY i_point1_id'
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 'GROUP BY i_point1_id'
62
- sql.must_match 'GROUP BY at_me2_id'
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 my_type_with_dates AS tab"
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 person_id AS person_id, CAST(NULL AS bigint) AS condition_occurrence_id, CAST(NULL AS bigint) AS death_id, CAST(NULL AS bigint) AS drug_cost_id, CAST(NULL AS bigint) AS drug_exposure_id, CAST(NULL AS bigint) AS observation_id, CAST(NULL AS bigint) AS payer_plan_period_id, CAST(NULL AS bigint) AS procedure_cost_id, CAST(NULL AS bigint) AS procedure_occurrence_id, visit_occurrence_id AS visit_occurrence_id, start_date, end_date FROM visit_occurrence_with_dates AS tab WHERE (visit_occurrence_id NOT IN (SELECT * FROM (SELECT visit_occurrence_id FROM table1) AS t1 WHERE (visit_occurrence_id IS NOT NULL)))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000183))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000184))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000185))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000199))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000200))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000215))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000230))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000245))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000246))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000247))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000184, 38000185))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000184, 38000185))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000183, 38000184, 38000185, 38000186, 38000187, 38000188, 38000189, 38000190, 38000191, 38000192, 38000193, 38000194, 38000195, 38000196, 38000197, 38000198))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000199, 38000200, 38000201, 38000202, 38000203, 38000204, 38000205, 38000206, 38000207, 38000208, 38000209, 38000210, 38000211, 38000212, 38000213, 38000214))"
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 condition_occurrence_with_dates 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))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000215, 38000216, 38000217, 38000218, 38000219, 38000220, 38000221, 38000222, 38000223, 38000224, 38000225, 38000226, 38000227, 38000228, 38000229))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000230, 38000231, 38000232, 38000233, 38000234, 38000235, 38000236, 38000237, 38000238, 38000239, 38000240, 38000241, 38000242, 38000243, 38000244))"
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 condition_occurrence_with_dates 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))"
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 condition_occurrence_with_dates WHERE (condition_type_concept_id IN (38000246, 38000247))"
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 date) AS start_date, CAST('2010-03-20' AS date) AS end_date FROM person) AS t1")
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 date) AS start_date, CAST('2010-03-20' AS date) AS end_date FROM person) AS t1")
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 visit_occurrence_with_dates) AS date) AS start_date, CAST('2010-03-20' AS date) AS end_date FROM person) AS t1")
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 date) AS start_date, CAST((SELECT max(end_date) FROM visit_occurrence_with_dates) AS date) AS end_date FROM person) AS t1")
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 person_with_dates WHERE (gender_concept_id IN (8507))"
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 person_with_dates WHERE (gender_concept_id IN (8532))"
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 ALL SELECT * FROM table2) AS t1 INTERSECT ALL SELECT * FROM table3) AS t1"
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 ALL SELECT * FROM table3) AS t1 UNION ALL SELECT * FROM table2) AS t1"
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
@@ -81,7 +81,7 @@ describe ConceptQL::Nodes::Occurrence do
81
81
  end
82
82
 
83
83
  it 'should order by ascending start_date' do
84
- subject.must_match ', condition_occurrence_id ASC'
84
+ subject.must_match ', criterion_type, criterion_id'
85
85
  end
86
86
  end
87
87
  end
@@ -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 visit_occurrence_with_dates AS v INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = v.place_of_service_concept_id) WHERE (vc.concept_code IN ('23'))"
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 visit_occurrence_with_dates AS v INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = v.place_of_service_concept_id) WHERE (vc.concept_code IN ('23'))"
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 visit_occurrence_with_dates 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'))"
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 person_with_dates AS p INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = p.race_concept_id) WHERE (lower(vc.concept_name) IN ('white'))"
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 person_with_dates AS p INNER JOIN vocabulary.concept AS vc ON (vc.concept_id = p.race_concept_id) WHERE (lower(vc.concept_name) IN ('white', 'other'))"
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 table_with_dates 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))"
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 table_with_dates 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))"
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 table_with_dates 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))"
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 table_with_dates 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))"
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'd', end: '' }).evaluate(Sequel.mock).sql
19
- sql.must_match(%q{date((date(start_date) + interval '1 day')) AS start_date})
20
- sql.must_match(%q{date(end_date) AS end_date})
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: '', end: 'd' }).evaluate(Sequel.mock).sql
25
- sql.must_match(%q{date(start_date) AS start_date})
26
- sql.must_match(%q{date((date(end_date) + interval '1 day')) AS end_date})
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'd', end: 'd' }).evaluate(Sequel.mock).sql
31
- sql.must_match(%q{date((date(start_date) + interval '1 day')) AS start_date, date((date(end_date) + interval '1 day')) AS end_date})
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'dmy', end: '-d-m-y' }).evaluate(Sequel.mock).sql
36
- sql.must_match(%q{date((date((date((date(start_date) + interval '1 day')) + interval '1 month')) + interval '1 year'))})
37
- sql.must_match(%q{date((date((date((date(end_date) + interval '-1 day')) + interval '-1 month')) + interval '-1 year'))})
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'end', end: '' }).evaluate(Sequel.mock).sql
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: '', end: 'start' }).evaluate(Sequel.mock).sql
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: 'end', end: 'start' }).evaluate(Sequel.mock).sql
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
- sql = ConceptQL::Nodes::TimeWindow.new(Stream4TimeWindowDouble.new, { start: nil, end: nil }).evaluate(Sequel.mock).sql
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 :evaluate, nil, [:mock_db]
14
+ mock_node.expect :map, [mock_query]
14
15
  query.query
15
16
 
16
17
  mock_node.verify
@@ -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
- @mock_nodifier.expect :create, mock_icd9_obj, [:icd9, '799.22']
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.6
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-23 00:00:00.000000000 Z
11
+ date: 2014-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport