conceptql 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +226 -117
- data/LICENSE +21 -0
- data/README.md +35 -83
- data/bin/conceptql +2 -1
- data/bin/conceptql_utils +6 -0
- data/config/multiple_vocabularies.csv +4 -0
- data/config/provenance.yml +489 -0
- data/config/race.yml +50 -0
- data/config/vocabularies.csv +87 -0
- data/lib/conceptql/behaviors/code_lister.rb +23 -0
- data/lib/conceptql/behaviors/drugish.rb +17 -0
- data/lib/conceptql/behaviors/labish.rb +19 -0
- data/lib/conceptql/behaviors/metadatable.rb +226 -73
- data/lib/conceptql/behaviors/provenanceable.rb +26 -0
- data/lib/conceptql/behaviors/single_event.rb +11 -0
- data/lib/conceptql/behaviors/timeless.rb +11 -0
- data/lib/conceptql/behaviors/utilizable.rb +206 -0
- data/lib/conceptql/behaviors/windowable.rb +27 -0
- data/lib/conceptql/cli.rb +117 -108
- data/lib/conceptql/columnizer.rb +75 -0
- data/lib/conceptql/data_model/base.rb +462 -0
- data/lib/conceptql/data_model/gdm.rb +155 -0
- data/lib/conceptql/data_model/gdm_wide.rb +42 -0
- data/lib/conceptql/data_model/omopv4_plus.rb +12 -0
- data/lib/conceptql/data_model.rb +30 -0
- data/lib/conceptql/database.rb +214 -0
- data/lib/conceptql/date_adjuster.rb +66 -18
- data/lib/conceptql/diagram.rb +243 -0
- data/lib/conceptql/lexicon/lexicon_gdm.rb +47 -0
- data/lib/conceptql/lexicon/lexicon_no_db.rb +49 -0
- data/lib/conceptql/lexicon/lexicon_ohdsi.rb +63 -0
- data/lib/conceptql/lexicon/lexicon_strategy.rb +116 -0
- data/lib/conceptql/lexicon.rb +111 -0
- data/lib/conceptql/nodifier.rb +65 -24
- data/lib/conceptql/operators/after.rb +34 -14
- data/lib/conceptql/operators/any_overlap.rb +8 -6
- data/lib/conceptql/operators/before.rb +34 -10
- data/lib/conceptql/operators/binary_operator_operator.rb +66 -23
- data/lib/conceptql/operators/casting_operator.rb +51 -36
- data/lib/conceptql/operators/co_reported.rb +111 -0
- data/lib/conceptql/operators/concurrent_within.rb +69 -0
- data/lib/conceptql/operators/contains.rb +12 -8
- data/lib/conceptql/operators/count.rb +17 -9
- data/lib/conceptql/operators/date_range.rb +48 -14
- data/lib/conceptql/operators/death.rb +14 -4
- data/lib/conceptql/operators/dedup.rb +31 -0
- data/lib/conceptql/operators/during.rb +7 -12
- data/lib/conceptql/operators/episode.rb +146 -0
- data/lib/conceptql/operators/equal.rb +9 -3
- data/lib/conceptql/operators/ethnicity.rb +49 -0
- data/lib/conceptql/operators/except.rb +19 -12
- data/lib/conceptql/operators/filter.rb +23 -8
- data/lib/conceptql/operators/first.rb +16 -3
- data/lib/conceptql/operators/from.rb +52 -4
- data/lib/conceptql/operators/gender.rb +34 -11
- data/lib/conceptql/operators/hospice.rb +19 -0
- data/lib/conceptql/operators/hospitalization.rb +19 -0
- data/lib/conceptql/operators/information_periods.rb +36 -0
- data/lib/conceptql/operators/invalid.rb +35 -0
- data/lib/conceptql/operators/last.rb +16 -3
- data/lib/conceptql/operators/match.rb +91 -0
- data/lib/conceptql/operators/multiple_vocabularies.rb +172 -0
- data/lib/conceptql/operators/numeric.rb +65 -23
- data/lib/conceptql/operators/numeric_filter.rb +68 -0
- data/lib/conceptql/operators/occurrence.rb +153 -32
- data/lib/conceptql/operators/one_in_two_out.rb +237 -38
- data/lib/conceptql/operators/operator.rb +624 -178
- data/lib/conceptql/operators/pass_thru.rb +17 -3
- data/lib/conceptql/operators/person.rb +18 -6
- data/lib/conceptql/operators/person_filter.rb +9 -3
- data/lib/conceptql/operators/place_of_service_filter.rb +43 -0
- data/lib/conceptql/operators/provenance.rb +55 -0
- data/lib/conceptql/operators/provider_filter.rb +62 -0
- data/lib/conceptql/operators/race.rb +55 -7
- data/lib/conceptql/operators/read.rb +168 -0
- data/lib/conceptql/operators/recall.rb +49 -14
- data/lib/conceptql/operators/snf.rb +19 -0
- data/lib/conceptql/operators/sum.rb +29 -12
- data/lib/conceptql/operators/temporal_operator.rb +108 -16
- data/lib/conceptql/operators/time_window.rb +20 -32
- data/lib/conceptql/operators/trim_date.rb +71 -0
- data/lib/conceptql/operators/trim_date_end.rb +28 -40
- data/lib/conceptql/operators/trim_date_start.rb +28 -41
- data/lib/conceptql/operators/union.rb +67 -6
- data/lib/conceptql/operators/vocabulary.rb +151 -0
- data/lib/conceptql/paths.rb +41 -0
- data/lib/conceptql/query.rb +191 -26
- data/lib/conceptql/query_modifiers/gdm/admission_date_query_modifier.rb +46 -0
- data/lib/conceptql/query_modifiers/gdm/drug_query_modifier.rb +54 -0
- data/lib/conceptql/query_modifiers/gdm/lab_query_modifier.rb +57 -0
- data/lib/conceptql/query_modifiers/gdm/pos_query_modifier.rb +46 -0
- data/lib/conceptql/query_modifiers/gdm/provenance_query_modifier.rb +45 -0
- data/lib/conceptql/query_modifiers/gdm/provider_query_modifier.rb +53 -0
- data/lib/conceptql/query_modifiers/gdm_wide/admission_date_query_modifier.rb +42 -0
- data/lib/conceptql/query_modifiers/gdm_wide/drug_query_modifier.rb +52 -0
- data/lib/conceptql/query_modifiers/gdm_wide/lab_query_modifier.rb +55 -0
- data/lib/conceptql/query_modifiers/gdm_wide/pos_query_modifier.rb +37 -0
- data/lib/conceptql/query_modifiers/gdm_wide/provenance_query_modifier.rb +38 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/admission_date_query_modifier.rb +45 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/drug_query_modifier.rb +80 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/pos_query_modifier.rb +47 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/provenance_query_modifier.rb +45 -0
- data/lib/conceptql/query_modifiers/omopv4_plus/provider_query_modifier.rb +26 -0
- data/lib/conceptql/query_modifiers/query_modifier.rb +20 -0
- data/lib/conceptql/rdbms/duckdb.rb +25 -0
- data/lib/conceptql/rdbms/generic.rb +120 -0
- data/lib/conceptql/rdbms/postgres.rb +51 -0
- data/lib/conceptql/rdbms/spark.rb +22 -0
- data/lib/conceptql/rdbms.rb +22 -0
- data/lib/conceptql/scope.rb +481 -31
- data/lib/conceptql/sql_formatters/formatter.rb +25 -0
- data/lib/conceptql/sql_formatters.rb +22 -0
- data/lib/conceptql/utils.rb +113 -0
- data/lib/conceptql/utils_cli.rb +17 -0
- data/lib/conceptql/version.rb +3 -1
- data/lib/conceptql/visitors/metadata_extractor.rb +54 -0
- data/lib/conceptql/vocabularies/behaviors/costish.rb +24 -0
- data/lib/conceptql/vocabularies/behaviors/gdmish.rb +19 -0
- data/lib/conceptql/vocabularies/behaviors/omopish.rb +32 -0
- data/lib/conceptql/vocabularies/dynamic_vocabularies.rb +63 -0
- data/lib/conceptql/vocabularies/entry.rb +138 -0
- data/lib/conceptql/vocabularies/vocabulary_class_factory.rb +85 -0
- data/lib/conceptql/window/base.rb +26 -0
- data/lib/conceptql/window/date_range.rb +25 -0
- data/lib/conceptql/window/table.rb +116 -0
- data/lib/conceptql/window.rb +72 -0
- data/lib/conceptql.rb +65 -2
- data/lib/sequel/extensions/pg_ctas_explain.rb +22 -0
- data/lib/sequel/extensions/pg_vacuum_table.rb +23 -0
- data/schemas/gdm.yml +882 -0
- data/schemas/gdm_wide.yml +757 -0
- data/schemas/ohdsi_vocabs.yml +143 -0
- data/schemas/omopv4_plus.yml +729 -0
- data/schemas/omopv4_plus_more_ignorables.tsv +13 -0
- metadata +267 -207
- data/.gitignore +0 -23
- data/Gemfile +0 -4
- data/Guardfile +0 -56
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -1
- data/conceptql.gemspec +0 -32
- data/doc/ConceptQL Specification (alpha).pdf +0 -0
- data/doc/diagram_0.png +0 -0
- data/doc/implementation_notes.md +0 -39
- data/doc/spec.md +0 -1344
- data/lib/conceptql/behaviors/debuggable.rb +0 -70
- data/lib/conceptql/behaviors/dottable.rb +0 -103
- data/lib/conceptql/behaviors/preppable.rb +0 -20
- data/lib/conceptql/converter.rb +0 -65
- data/lib/conceptql/debugger.rb +0 -48
- data/lib/conceptql/fake_grapher.rb +0 -20
- data/lib/conceptql/graph.rb +0 -52
- data/lib/conceptql/graph_nodifier.rb +0 -203
- data/lib/conceptql/logger.rb +0 -10
- data/lib/conceptql/operators/complement.rb +0 -38
- data/lib/conceptql/operators/concept.rb +0 -70
- data/lib/conceptql/operators/condition_type.rb +0 -71
- data/lib/conceptql/operators/cpt.rb +0 -25
- data/lib/conceptql/operators/drug_type_concept.rb +0 -21
- data/lib/conceptql/operators/from_seer_visits.rb +0 -23
- data/lib/conceptql/operators/hcpcs.rb +0 -25
- data/lib/conceptql/operators/icd10.rb +0 -28
- data/lib/conceptql/operators/icd9.rb +0 -28
- data/lib/conceptql/operators/icd9_procedure.rb +0 -25
- data/lib/conceptql/operators/intersect.rb +0 -34
- data/lib/conceptql/operators/loinc.rb +0 -25
- data/lib/conceptql/operators/medcode.rb +0 -28
- data/lib/conceptql/operators/medcode_procedure.rb +0 -27
- data/lib/conceptql/operators/ndc.rb +0 -29
- data/lib/conceptql/operators/observation_by_enttype.rb +0 -29
- data/lib/conceptql/operators/observation_period.rb +0 -30
- data/lib/conceptql/operators/overlapped_by.rb +0 -23
- data/lib/conceptql/operators/overlaps.rb +0 -19
- data/lib/conceptql/operators/place_of_service_code.rb +0 -24
- data/lib/conceptql/operators/procedure_occurrence.rb +0 -25
- data/lib/conceptql/operators/prodcode.rb +0 -29
- data/lib/conceptql/operators/rxnorm.rb +0 -24
- data/lib/conceptql/operators/snomed.rb +0 -24
- data/lib/conceptql/operators/snomed_condition.rb +0 -26
- data/lib/conceptql/operators/source_vocabulary_operator.rb +0 -58
- data/lib/conceptql/operators/standard_vocabulary_operator.rb +0 -45
- data/lib/conceptql/operators/started_by.rb +0 -22
- data/lib/conceptql/operators/to_seer_visits.rb +0 -24
- data/lib/conceptql/operators/visit.rb +0 -15
- data/lib/conceptql/operators/visit_occurrence.rb +0 -30
- data/lib/conceptql/tree.rb +0 -53
- data/lib/conceptql/utils/temp_table.rb +0 -72
- data/spec/conceptql/behaviors/dottable_spec.rb +0 -99
- data/spec/conceptql/converter_spec.rb +0 -51
- data/spec/conceptql/date_adjuster_spec.rb +0 -68
- data/spec/conceptql/operators/after_spec.rb +0 -16
- data/spec/conceptql/operators/before_spec.rb +0 -16
- data/spec/conceptql/operators/casting_operator_spec.rb +0 -68
- data/spec/conceptql/operators/complement_spec.rb +0 -15
- data/spec/conceptql/operators/concept_spec.rb +0 -40
- data/spec/conceptql/operators/condition_type_spec.rb +0 -128
- data/spec/conceptql/operators/contains_spec.rb +0 -19
- data/spec/conceptql/operators/cpt_spec.rb +0 -29
- data/spec/conceptql/operators/date_range_spec.rb +0 -33
- data/spec/conceptql/operators/death_spec.rb +0 -10
- data/spec/conceptql/operators/during_spec.rb +0 -30
- data/spec/conceptql/operators/except_spec.rb +0 -15
- data/spec/conceptql/operators/first_spec.rb +0 -35
- data/spec/conceptql/operators/from_spec.rb +0 -13
- data/spec/conceptql/operators/gender_spec.rb +0 -27
- data/spec/conceptql/operators/hcpcs_spec.rb +0 -29
- data/spec/conceptql/operators/icd10_spec.rb +0 -34
- data/spec/conceptql/operators/icd9_procedure_spec.rb +0 -29
- data/spec/conceptql/operators/icd9_spec.rb +0 -34
- data/spec/conceptql/operators/intersect_spec.rb +0 -28
- data/spec/conceptql/operators/last_spec.rb +0 -36
- data/spec/conceptql/operators/loinc_spec.rb +0 -29
- data/spec/conceptql/operators/medcode_procedure_spec.rb +0 -34
- data/spec/conceptql/operators/medcode_spec.rb +0 -34
- data/spec/conceptql/operators/observation_period_spec.rb +0 -10
- data/spec/conceptql/operators/occurrence_spec.rb +0 -87
- data/spec/conceptql/operators/overlapped_by_spec.rb +0 -32
- data/spec/conceptql/operators/overlaps_spec.rb +0 -21
- data/spec/conceptql/operators/person_filter_spec.rb +0 -15
- data/spec/conceptql/operators/person_spec.rb +0 -10
- data/spec/conceptql/operators/place_of_service_code_spec.rb +0 -24
- data/spec/conceptql/operators/procedure_occurrence_spec.rb +0 -10
- data/spec/conceptql/operators/prodcode_spec.rb +0 -35
- data/spec/conceptql/operators/query_double.rb +0 -20
- data/spec/conceptql/operators/query_double_spec.rb +0 -7
- data/spec/conceptql/operators/race_spec.rb +0 -21
- data/spec/conceptql/operators/rxnorm_spec.rb +0 -29
- data/spec/conceptql/operators/snomed_spec.rb +0 -29
- data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +0 -35
- data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +0 -35
- data/spec/conceptql/operators/started_by_spec.rb +0 -22
- data/spec/conceptql/operators/temporal_operator_spec.rb +0 -51
- data/spec/conceptql/operators/time_window_spec.rb +0 -77
- data/spec/conceptql/operators/union_spec.rb +0 -21
- data/spec/conceptql/operators/visit_occurrence_spec.rb +0 -10
- data/spec/conceptql/query_spec.rb +0 -22
- data/spec/conceptql/tree_spec.rb +0 -50
- data/spec/doubles/stream_for_casting_double.rb +0 -9
- data/spec/doubles/stream_for_occurrence_double.rb +0 -25
- data/spec/doubles/stream_for_temporal_double.rb +0 -6
- data/spec/spec_helper.rb +0 -102
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/medcode'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::Medcode do
|
|
5
|
-
it_behaves_like(:source_vocabulary_operator)
|
|
6
|
-
|
|
7
|
-
subject do
|
|
8
|
-
described_class.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe '#table' do
|
|
12
|
-
it 'should be condition_occurrence' do
|
|
13
|
-
expect(subject.table).to eq(:condition_occurrence)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe '#concept_column' do
|
|
18
|
-
it 'should be condition_concept_id' do
|
|
19
|
-
expect(subject.concept_column).to eq(:condition_concept_id)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe '#source_column' do
|
|
24
|
-
it 'should be condition_source_valuej' do
|
|
25
|
-
expect(subject.source_column).to eq(:condition_source_value)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe '#vocabulary_id' do
|
|
30
|
-
it 'should be 203 (a J&J provided mapping as part of CPRD)' do
|
|
31
|
-
expect(subject.vocabulary_id).to eq(203)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/occurrence'
|
|
3
|
-
require_double('stream_for_occurrence')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::Occurrence do
|
|
6
|
-
it_behaves_like(:evaluator)
|
|
7
|
-
|
|
8
|
-
describe 'occurrence set to 1' do
|
|
9
|
-
subject do
|
|
10
|
-
described_class.new(1, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it 'should order by ascending start_date' do
|
|
14
|
-
expect(subject).to match('ORDER BY "start_date" ASC')
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it 'should partition by person_id' do
|
|
18
|
-
expect(subject).to match('PARTITION BY "person_id"')
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
it 'should assign a row number' do
|
|
22
|
-
expect(subject).to match('row_number()')
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'should find the all rows with "rn" = 1' do
|
|
26
|
-
expect(subject).to match('"rn" = 1')
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
describe 'occurrence set to 2' do
|
|
31
|
-
subject do
|
|
32
|
-
described_class.new(2, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it 'should order by ascending start_date' do
|
|
36
|
-
expect(subject).to match('ORDER BY "start_date" ASC')
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'should find the all rows with "rn" = 2' do
|
|
40
|
-
expect(subject).to match('"rn" = 2')
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
describe 'occurrence set to -1' do
|
|
45
|
-
subject do
|
|
46
|
-
described_class.new(-1, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
it 'should order by ascending start_date' do
|
|
50
|
-
expect(subject).to match('ORDER BY "start_date" DESC')
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it 'should find the all rows with "rn" = 1' do
|
|
54
|
-
expect(subject).to match('"rn" = 1')
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
describe 'occurrence set to -2' do
|
|
59
|
-
subject do
|
|
60
|
-
described_class.new(-2, StreamForOccurrenceDouble.new).query(Sequel.mock(host: 'postgres')).sql
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it 'should order by ascending start_date' do
|
|
64
|
-
expect(subject).to match('ORDER BY "start_date" DESC')
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'should find the all rows with "rn" = 2' do
|
|
68
|
-
expect(subject).to match('"rn" = 2')
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
describe 'occurrence respects types' do
|
|
73
|
-
subject do
|
|
74
|
-
dub = StreamForOccurrenceDouble.new
|
|
75
|
-
def dub.types
|
|
76
|
-
[:condition_occurrence]
|
|
77
|
-
end
|
|
78
|
-
described_class.new(-2, dub).query(Sequel.mock(host: 'postgres')).sql
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it 'should order by ascending start_date' do
|
|
82
|
-
expect(subject).to match(', "criterion_type", "criterion_id"')
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/overlapped_by'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::OverlappedBy do
|
|
6
|
-
it_behaves_like(:temporal_operator)
|
|
7
|
-
|
|
8
|
-
describe 'when not inclusive' do
|
|
9
|
-
subject do
|
|
10
|
-
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it 'should use proper where clause' do
|
|
14
|
-
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.end_date')
|
|
15
|
-
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.start_date')
|
|
16
|
-
expect(subject.query(Sequel.mock).sql).to match('r.end_date <= l.end_date')
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe 'when inclusive' do
|
|
21
|
-
subject do
|
|
22
|
-
described_class.new(inclusive: true, left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'should use proper where clause' do
|
|
26
|
-
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.end_date')
|
|
27
|
-
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.start_date')
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/overlaps'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::Overlaps do
|
|
6
|
-
it_behaves_like(:temporal_operator)
|
|
7
|
-
|
|
8
|
-
describe 'when not inclusive' do
|
|
9
|
-
subject do
|
|
10
|
-
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it 'should use proper where clause' do
|
|
14
|
-
expect(subject.query(Sequel.mock).sql).to match('r.start_date <= l.end_date')
|
|
15
|
-
expect(subject.query(Sequel.mock).sql).to match('l.start_date <= r.start_date')
|
|
16
|
-
expect(subject.query(Sequel.mock).sql).to match('l.end_date <= r.end_date')
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/person_filter'
|
|
3
|
-
require_relative 'query_double'
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::PersonFilter do
|
|
6
|
-
it_behaves_like(:evaluator)
|
|
7
|
-
|
|
8
|
-
describe '#query' do
|
|
9
|
-
it 'uses right stream as argument to PERSON_FILTER against left stream' do
|
|
10
|
-
double1 = QueryDouble.new(1)
|
|
11
|
-
double2 = QueryDouble.new(2)
|
|
12
|
-
expect(ConceptQL::Operators::PersonFilter.new(left: double1, right: double2).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM table1) AS t1 WHERE (person_id IN (SELECT person_id FROM table2 GROUP BY person_id))")
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/place_of_service_code'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::PlaceOfServiceCode do
|
|
5
|
-
it_behaves_like(:evaluator)
|
|
6
|
-
|
|
7
|
-
describe '#query' do
|
|
8
|
-
it 'works for 23' do
|
|
9
|
-
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))"
|
|
10
|
-
expect(ConceptQL::Operators::PlaceOfServiceCode.new('23').query(Sequel.mock).sql).to eq(correct_query)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it 'works for 23 as number' do
|
|
14
|
-
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))"
|
|
15
|
-
expect(ConceptQL::Operators::PlaceOfServiceCode.new(23).query(Sequel.mock).sql).to eq(correct_query)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it 'works for multiple values' do
|
|
19
|
-
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))"
|
|
20
|
-
expect(ConceptQL::Operators::PlaceOfServiceCode.new('23', '22').query(Sequel.mock).sql).to eq(correct_query)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/prodcode'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::Prodcode do
|
|
5
|
-
it_behaves_like(:source_vocabulary_operator)
|
|
6
|
-
|
|
7
|
-
subject do
|
|
8
|
-
described_class.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe '#table' do
|
|
12
|
-
it 'should be drug_exposure' do
|
|
13
|
-
expect(subject.table).to eq(:drug_exposure)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe '#concept_column' do
|
|
18
|
-
it 'should be drug_concept_id' do
|
|
19
|
-
expect(subject.concept_column).to eq(:drug_concept_id)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe '#source_column' do
|
|
24
|
-
it 'should be drug_source_valuej' do
|
|
25
|
-
expect(subject.source_column).to eq(:drug_source_value)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe '#vocabulary_id' do
|
|
30
|
-
it 'should be 200 (a J&J provided mapping as part of CPRD)' do
|
|
31
|
-
expect(subject.vocabulary_id).to eq(200)
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require 'conceptql/operators/operator'
|
|
2
|
-
class QueryDouble < ConceptQL::Operators::Operator
|
|
3
|
-
def initialize(*args)
|
|
4
|
-
super
|
|
5
|
-
@num = arguments.first
|
|
6
|
-
@type = arguments[1] || :visit_occurrence
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def types
|
|
10
|
-
[@type]
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def evaluate(db)
|
|
14
|
-
query(db)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def query(db)
|
|
18
|
-
db["table#{@num}".to_sym]
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/race'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::Race do
|
|
5
|
-
it_behaves_like(:evaluator)
|
|
6
|
-
|
|
7
|
-
describe '#query' do
|
|
8
|
-
it 'works for white' do
|
|
9
|
-
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'))"
|
|
10
|
-
expect(ConceptQL::Operators::Race.new('White').query(Sequel.mock).sql).to eq(correct_query)
|
|
11
|
-
expect(ConceptQL::Operators::Race.new('white').query(Sequel.mock).sql).to eq(correct_query)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it 'works for multiple values' do
|
|
15
|
-
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'))"
|
|
16
|
-
expect(ConceptQL::Operators::Race.new('White', 'Other').query(Sequel.mock).sql).to eq(correct_query)
|
|
17
|
-
expect(ConceptQL::Operators::Race.new('white', 'other').query(Sequel.mock).sql).to eq(correct_query)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/rxnorm'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::Rxnorm do
|
|
5
|
-
it_behaves_like(:standard_vocabulary_operator)
|
|
6
|
-
|
|
7
|
-
subject do
|
|
8
|
-
described_class.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe '#table' do
|
|
12
|
-
it 'should be drug_exposure' do
|
|
13
|
-
expect(subject.table).to eq(:drug_exposure)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe '#concept_column' do
|
|
18
|
-
it 'should be drug_concept_id' do
|
|
19
|
-
expect(subject.concept_column).to eq(:drug_concept_id)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe '#vocabulary_id' do
|
|
24
|
-
it 'should be 8' do
|
|
25
|
-
expect(subject.vocabulary_id).to eq(8)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/snomed'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::Snomed do
|
|
5
|
-
it_behaves_like(:standard_vocabulary_operator)
|
|
6
|
-
|
|
7
|
-
subject do
|
|
8
|
-
described_class.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe '#table' do
|
|
12
|
-
it 'should be condition_occurrence' do
|
|
13
|
-
expect(subject.table).to eq(:condition_occurrence)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe '#concept_column' do
|
|
18
|
-
it 'should be condition_concept_id' do
|
|
19
|
-
expect(subject.concept_column).to eq(:condition_concept_id)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe '#vocabulary_id' do
|
|
24
|
-
it 'should be 1' do
|
|
25
|
-
expect(subject.vocabulary_id).to eq(1)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/source_vocabulary_operator'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::SourceVocabularyOperator do
|
|
5
|
-
it_behaves_like(:evaluator)
|
|
6
|
-
|
|
7
|
-
class SourceVocabularyDouble < ConceptQL::Operators::SourceVocabularyOperator
|
|
8
|
-
def table
|
|
9
|
-
:table
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def source_column
|
|
13
|
-
:source_column
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def concept_column
|
|
17
|
-
:concept_column
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def vocabulary_id
|
|
21
|
-
1
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe '#query' do
|
|
26
|
-
it 'works for single values' do
|
|
27
|
-
expect(SourceVocabularyDouble.new('value').query(Sequel.mock).sql).to eq("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))")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'works for multiple values' do
|
|
31
|
-
expect(SourceVocabularyDouble.new('value1', 'value2').query(Sequel.mock).sql).to eq("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))")
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/standard_vocabulary_operator'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Operators::StandardVocabularyOperator do
|
|
5
|
-
it_behaves_like(:evaluator)
|
|
6
|
-
|
|
7
|
-
class StandardVocabularyDouble < ConceptQL::Operators::StandardVocabularyOperator
|
|
8
|
-
def table
|
|
9
|
-
:table
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def concept_column
|
|
13
|
-
:concept_column
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def vocabulary_id
|
|
17
|
-
1
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
describe StandardVocabularyDouble do
|
|
22
|
-
it_behaves_like(:standard_vocabulary_operator)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe '#query' do
|
|
26
|
-
it 'works for single values' do
|
|
27
|
-
expect(StandardVocabularyDouble.new('value').query(Sequel.mock).sql).to eq("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))")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'works for multiple diagnoses' do
|
|
31
|
-
expect(StandardVocabularyDouble.new('value1', 'value2').query(Sequel.mock).sql).to eq("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))")
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/started_by'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::StartedBy do
|
|
6
|
-
it_behaves_like(:temporal_operator)
|
|
7
|
-
subject do
|
|
8
|
-
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it 'should use proper where clause' do
|
|
12
|
-
expect(subject.query(Sequel.mock).sql).to match('l.start_date = r.start_date')
|
|
13
|
-
expect(subject.query(Sequel.mock).sql).to match('l.end_date > r.end_date')
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'should use proper where clause when inclusive' do
|
|
17
|
-
sub = ConceptQL::Operators::StartedBy.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new, inclusive: true)
|
|
18
|
-
expect(sub.query(Sequel.mock).sql).to match('l.start_date = r.start_date')
|
|
19
|
-
expect(sub.query(Sequel.mock).sql).to match('l.end_date >= r.end_date')
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/temporal_operator'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::TemporalOperator do
|
|
6
|
-
it_behaves_like(:evaluator)
|
|
7
|
-
|
|
8
|
-
class TemporalDouble < ConceptQL::Operators::TemporalOperator
|
|
9
|
-
def where_clause
|
|
10
|
-
Proc.new do
|
|
11
|
-
l__end_date < r__start_date
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
describe TemporalDouble do
|
|
17
|
-
it_behaves_like(:temporal_operator)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe StreamForTemporalDouble do
|
|
21
|
-
it_behaves_like(:evaluator)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe '#inclusive?' do
|
|
25
|
-
it 'defaults to false' do
|
|
26
|
-
expect(TemporalDouble.new.inclusive?).to be_falsy
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it 'can be set to true' do
|
|
30
|
-
expect(TemporalDouble.new(inclusive: true).inclusive?).to be_truthy
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
describe '#query' do
|
|
35
|
-
it 'uses logic from where_clause' do
|
|
36
|
-
sql = TemporalDouble.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new).query(Sequel.mock).sql
|
|
37
|
-
expect(sql).to match('l.end_date < r.start_date')
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'pulls from the right tables' do
|
|
41
|
-
sql = TemporalDouble.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new).query(Sequel.mock).sql
|
|
42
|
-
expect(sql).to match('FROM table')
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it 'is ok with symbols' do
|
|
46
|
-
sql = TemporalDouble.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new).query(Sequel.mock).sql
|
|
47
|
-
expect(sql).to match('FROM table')
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/time_window'
|
|
3
|
-
require 'conceptql/operators/operator'
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::TimeWindow do
|
|
6
|
-
class Stream4TimeWindowDouble < ConceptQL::Operators::Operator
|
|
7
|
-
def types
|
|
8
|
-
[:visit_occurrence]
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def query(db)
|
|
12
|
-
db.from(:table)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
let (:sequel_mock) do
|
|
17
|
-
sequel_mock = double("sequel")
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
before do
|
|
21
|
-
@db_mock = Sequel.mock
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe '#evaluate' do
|
|
25
|
-
it 'adjusts start by 1 day' do
|
|
26
|
-
expect(sequel_mock).to receive(:date_add).with(Sequel.identifier("start_date"), days: 1).and_return(sequel_mock)
|
|
27
|
-
expect(@db_mock).to receive(:extension).with(:date_arithmetic)
|
|
28
|
-
|
|
29
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: 'd', end: '', date_manipulator: sequel_mock }).evaluate(@db_mock)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'adjusts end by 1 day' do
|
|
33
|
-
expect(sequel_mock).to receive(:date_add).with(Sequel.identifier("end_date"), days: 1).and_return(sequel_mock)
|
|
34
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: '', end: 'd', date_manipulator: sequel_mock }).evaluate(@db_mock)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it 'adjusts both values by 1 day' do
|
|
38
|
-
expect(sequel_mock).to receive(:date_add).with(Sequel.identifier("start_date"), days: 1).and_return(sequel_mock)
|
|
39
|
-
expect(sequel_mock).to receive(:date_add).with(Sequel.identifier("end_date"), days: 1).and_return(sequel_mock)
|
|
40
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: 'd', end: 'd', date_manipulator: sequel_mock }).evaluate(@db_mock)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it 'makes multiple adjustments to both values' do
|
|
44
|
-
expect(sequel_mock).to receive(:date_add).with(Sequel.identifier("start_date"), days: 1).and_return(sequel_mock)
|
|
45
|
-
expect(sequel_mock).to receive(:date_add).with(sequel_mock, months: 1).and_return(sequel_mock)
|
|
46
|
-
expect(sequel_mock).to receive(:date_add).with(sequel_mock, years: 1).and_return(sequel_mock)
|
|
47
|
-
|
|
48
|
-
expect(sequel_mock).to receive(:date_sub).with(Sequel.identifier("end_date"), days: 1).and_return(sequel_mock)
|
|
49
|
-
expect(sequel_mock).to receive(:date_sub).with(sequel_mock, months: 1).and_return(sequel_mock)
|
|
50
|
-
expect(sequel_mock).to receive(:date_sub).with(sequel_mock, years: 1).and_return(sequel_mock)
|
|
51
|
-
|
|
52
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: 'dmy', end: '-d-m-y', date_manipulator: sequel_mock }).evaluate(@db_mock)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it 'can set start_date and end_date to specific dates' do
|
|
56
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: '2000-01-01', end: '2000-02-02' }).evaluate(@db_mock)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it 'can set start_date to be end_date' do
|
|
60
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: 'end', end: '' }).evaluate(@db_mock)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
it 'can set end_date to be start_date' do
|
|
64
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: '', end: 'start' }).evaluate(@db_mock)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it 'will swap start and end dates, though this is a bad idea but you should probably know about this' do
|
|
68
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: 'end', end: 'start' }).evaluate(@db_mock)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it 'handles nil arguments to both start and end' do
|
|
72
|
-
described_class.new(Stream4TimeWindowDouble.new, { start: nil, end: nil }).evaluate(@db_mock)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/union'
|
|
3
|
-
require_relative 'query_double'
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::Union do
|
|
6
|
-
it_behaves_like(:evaluator)
|
|
7
|
-
|
|
8
|
-
describe '#query' do
|
|
9
|
-
it 'works for multiple criteria' do
|
|
10
|
-
double1 = QueryDouble.new(1)
|
|
11
|
-
double2 = QueryDouble.new(2)
|
|
12
|
-
double3 = QueryDouble.new(3)
|
|
13
|
-
expect(described_class.new(double1, double2, double3).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM table1) AS t1 UNION ALL SELECT * FROM (SELECT * FROM table2) AS t1) AS t1 UNION ALL SELECT * FROM (SELECT * FROM table3) AS t1) AS t1")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'works for single criteria' do
|
|
17
|
-
double1 = QueryDouble.new(1)
|
|
18
|
-
expect(described_class.new(double1).query(Sequel.mock).sql).to eq("SELECT * FROM (SELECT * FROM table1) AS t1")
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|