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,58 +0,0 @@
|
|
|
1
|
-
require_relative 'operator'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
# A SourceVocabularyOperator is a superclass for a operator that represents a criterion whose column stores information associated with a source vocabulary.
|
|
6
|
-
#
|
|
7
|
-
# If that seems confusing, then think of ICD-9 or NDC criteria. That type of criterion takes a set of values that are mapped via the source_to_concept_map table into a standard vocabulary.
|
|
8
|
-
#
|
|
9
|
-
# This kind of criterion can have some interesting issues when we are searching for rows that match. Let's take ICD-9 286.53 for example. That code maps to concept_id 0, so if we try to pull all conditions that match just the concept_id of 0 we'll pull all condtions that have no match in the SNOMED standard vocabulary. That's not what we want! So we need to search the condition_source_value field for matches on this code instead.
|
|
10
|
-
#
|
|
11
|
-
# But there's another, more complicated problem. Say we're looking for ICD-9 289.81. OMOP maps this to concept_id 432585. OMOP also maps 20 other conditions, 6 of which are other ICD-9 codes, to this same concept_id. So if we look for ICD-9s that have a non-zero condition_condept_id, we might pull up conditions that match on concept_id, but aren't the same exact code as the one we're looking for.
|
|
12
|
-
#
|
|
13
|
-
# My coworker came up with a nice, gneralized query that checks for matching concept_ids and matching source_code values. This class encapsulates that query.
|
|
14
|
-
#
|
|
15
|
-
# Subclasses must provide the following methods:
|
|
16
|
-
# * table
|
|
17
|
-
# * The CDM table name where the criterion will fetch its rows
|
|
18
|
-
# * e.g. for ICD-9, this would be condition_occurrence
|
|
19
|
-
# * concept_column
|
|
20
|
-
# * Name of the column in the table that stores a concept_id related to the criterion
|
|
21
|
-
# * e.g. for ICD-9, this would be condition_concept_id
|
|
22
|
-
# * source_column
|
|
23
|
-
# * Name of the column in the table that stores the "raw" value related to the criterion
|
|
24
|
-
# * e.g. for ICD-9, this would be condition_source_value
|
|
25
|
-
# * vocabulary_id
|
|
26
|
-
# * The vocabulary ID of the source vocabulary for the criterion
|
|
27
|
-
# * e.g. for ICD-9, a value of 2 (for ICD-9-CM)
|
|
28
|
-
class SourceVocabularyOperator < Operator
|
|
29
|
-
category 'Source Vocabulary'
|
|
30
|
-
category 'Code Lists'
|
|
31
|
-
|
|
32
|
-
def query(db)
|
|
33
|
-
db.from(table_name)
|
|
34
|
-
.join(:vocabulary__source_to_concept_map___scm, scm__target_concept_id: table_concept_column)
|
|
35
|
-
.where(Sequel.expr(scm__source_code: values, scm__source_vocabulary_id: vocabulary_id).&(Sequel.expr(scm__source_code: table_source_column)))
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def type
|
|
39
|
-
table
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
private
|
|
43
|
-
|
|
44
|
-
def table_name
|
|
45
|
-
@table_name ||= make_table_name(table)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def table_concept_column
|
|
49
|
-
"tab__#{concept_column}".to_sym
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def table_source_column
|
|
53
|
-
"tab__#{source_column}".to_sym
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require_relative 'operator'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
# A StandardVocabularyOperator is a superclass for a operator that represents a criterion whose column stores information associated with a standard vocabulary.
|
|
6
|
-
#
|
|
7
|
-
# If that seems confusing, then think of CPT or SNOMED criteria. That type of criterion takes a set of values that live in the OMOP concept table.
|
|
8
|
-
#
|
|
9
|
-
# My coworker came up with a nice, gneralized query that checks for matching concept_ids and matching source_code values. This class encapsulates that query.
|
|
10
|
-
#
|
|
11
|
-
# Subclasses must provide the following methods:
|
|
12
|
-
# * table
|
|
13
|
-
# * The CDM table name where the criterion will fetch its rows
|
|
14
|
-
# * e.g. for CPT, this would be procedure_occurrence
|
|
15
|
-
# * concept_column
|
|
16
|
-
# * Name of the column in the table that stores a concept_id related to the criterion
|
|
17
|
-
# * e.g. for CPT, this would be procedure_concept_id
|
|
18
|
-
# * vocabulary_id
|
|
19
|
-
# * The vocabulary ID of the source vocabulary for the criterion
|
|
20
|
-
# * e.g. for CPT, a value of 4 (for CPT-4)
|
|
21
|
-
class StandardVocabularyOperator < Operator
|
|
22
|
-
category 'Standard Vocabulary'
|
|
23
|
-
category 'Code Lists'
|
|
24
|
-
def query(db)
|
|
25
|
-
db.from(table_name)
|
|
26
|
-
.join(:vocabulary__concept___c, c__concept_id: table_concept_column)
|
|
27
|
-
.where(c__concept_code: values, c__vocabulary_id: vocabulary_id)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def type
|
|
31
|
-
table
|
|
32
|
-
end
|
|
33
|
-
private
|
|
34
|
-
|
|
35
|
-
def table_name
|
|
36
|
-
@table_name ||= make_table_name(table)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def table_concept_column
|
|
40
|
-
"tab__#{concept_column}".to_sym
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
require_relative 'temporal_operator'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
class StartedBy < TemporalOperator
|
|
6
|
-
desc <<-EOF
|
|
7
|
-
If LHR has the same start date as RHR, but LHR's end_date falls on or after end_date of RHR, LHR is passed through.
|
|
8
|
-
L----Y----L
|
|
9
|
-
R-------R
|
|
10
|
-
L--N--L
|
|
11
|
-
EOF
|
|
12
|
-
def where_clause
|
|
13
|
-
[ { l__start_date: :r__start_date } ] + \
|
|
14
|
-
if inclusive?
|
|
15
|
-
[ Proc.new { l__end_date >= r__end_date } ]
|
|
16
|
-
else
|
|
17
|
-
[ Proc.new { l__end_date > r__end_date } ]
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
require_relative 'operator'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
class ToSeerVisits < Operator
|
|
6
|
-
def type
|
|
7
|
-
:visit_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def query(db)
|
|
11
|
-
query = options.map do |k, v|
|
|
12
|
-
next if v.nil?
|
|
13
|
-
db[:observation]
|
|
14
|
-
.where(observation_source_value: k.to_s.upcase, value_as_string: v)
|
|
15
|
-
.select(:visit_occurrence_id)
|
|
16
|
-
.from_self
|
|
17
|
-
end.compact.inject { |q, i| i.intersect(q) }
|
|
18
|
-
db[:visit_occurrence].where(visit_occurrence_id: query)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require_relative 'operator'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
class Visit < Operator
|
|
6
|
-
desc 'Generates all visit_occurrence records, or, if fed a stream, fetches all visit_occurrence records for the people represented in the incoming result set.'
|
|
7
|
-
types :visit_occurrence
|
|
8
|
-
allows_one_upstream
|
|
9
|
-
|
|
10
|
-
def types
|
|
11
|
-
[:visit_occurrence]
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
require_relative 'casting_operator'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
class VisitOccurrence < CastingOperator
|
|
6
|
-
desc 'Returns all visits in the database, or if given a upstream, converts all results to the set of visit_occurrences related to those results.'
|
|
7
|
-
allows_one_upstream
|
|
8
|
-
types :visit_occurrence
|
|
9
|
-
|
|
10
|
-
def my_type
|
|
11
|
-
:visit_occurrence
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def i_point_at
|
|
15
|
-
[ :person ]
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def these_point_at_me
|
|
19
|
-
%i[
|
|
20
|
-
condition_occurrence
|
|
21
|
-
drug_cost
|
|
22
|
-
drug_exposure
|
|
23
|
-
observation
|
|
24
|
-
procedure_cost
|
|
25
|
-
procedure_occurrence
|
|
26
|
-
]
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
data/lib/conceptql/tree.rb
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
require_relative 'nodifier'
|
|
2
|
-
require_relative 'converter'
|
|
3
|
-
require_relative 'scope'
|
|
4
|
-
require 'facets/hash/deep_rekey'
|
|
5
|
-
require 'facets/array/recurse'
|
|
6
|
-
|
|
7
|
-
module ConceptQL
|
|
8
|
-
# Tree is used to walk through a ConceptQL statement, instantiate
|
|
9
|
-
# all operators, and then provide access to the root operator
|
|
10
|
-
class Tree
|
|
11
|
-
attr :nodifier, :behavior, :defined, :opts, :temp_tables, :scope
|
|
12
|
-
def initialize(opts = {})
|
|
13
|
-
@nodifier = opts.fetch(:nodifier, Nodifier.new)
|
|
14
|
-
@behavior = opts.fetch(:behavior, nil)
|
|
15
|
-
@defined = {}
|
|
16
|
-
@temp_tables = {}
|
|
17
|
-
@opts = {}
|
|
18
|
-
@scope = opts.fetch(:scope, Scope.new)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def root(query)
|
|
22
|
-
@root ||= start_traverse(query.statement)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
private
|
|
26
|
-
|
|
27
|
-
def start_traverse(stmt)
|
|
28
|
-
case stmt
|
|
29
|
-
when Hash
|
|
30
|
-
traverse(converter.convert(stmt))
|
|
31
|
-
when Array
|
|
32
|
-
traverse(stmt)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def traverse(stmt)
|
|
37
|
-
stmt.recurse(Array, Hash) do |arr_or_hash|
|
|
38
|
-
if arr_or_hash.is_a?(Array)
|
|
39
|
-
type = arr_or_hash.shift
|
|
40
|
-
obj = nodifier.create(scope, type, *arr_or_hash)
|
|
41
|
-
obj.extend(behavior) if behavior
|
|
42
|
-
obj
|
|
43
|
-
else
|
|
44
|
-
arr_or_hash
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def converter
|
|
50
|
-
@converter ||= Converter.new
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
require 'zlib'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
# TempTable coordinates the creation of any temporary tables a statement
|
|
5
|
-
# might need.
|
|
6
|
-
#
|
|
7
|
-
# Currently, temp tables are used to share a set of results when a Recall
|
|
8
|
-
# operator is present in a statement.
|
|
9
|
-
#
|
|
10
|
-
# It also provides an API to generate the SQL that Sequel would use to create
|
|
11
|
-
# and populate the temp table
|
|
12
|
-
class TempTable
|
|
13
|
-
attr :operator
|
|
14
|
-
def initialize(operator, db)
|
|
15
|
-
@operator = operator
|
|
16
|
-
fake_it!(db)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def build(db)
|
|
20
|
-
@built ||= build_it(db)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def sql(db)
|
|
24
|
-
# Sequel doesn't (currently) provide an API for getting the SQL for the
|
|
25
|
-
# creation of tables, so we're calling one of the private methods
|
|
26
|
-
sql = db[db.send(:create_table_as_sql, table_name, operator.evaluate(db), temp: true)].sql
|
|
27
|
-
["-- #{operator.label}", sql].join("\n")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def from(db)
|
|
31
|
-
db[table_name]
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def table_name
|
|
37
|
-
namify(operator.label)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def build_it(db)
|
|
41
|
-
db.create_table!(table_name, as: operator.evaluate(db), temp: true)
|
|
42
|
-
true
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def namify(name)
|
|
46
|
-
digest = Zlib.crc32 name
|
|
47
|
-
('_' + digest.to_s).to_sym
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Creates the temp table, but populates it with a single fake row of null
|
|
51
|
-
# values. Some operations, such as generating the SQL for a statement
|
|
52
|
-
# Want the temp tables to exist, but we don't _really_ need the actual
|
|
53
|
-
# results in the temp table since they might take a long time to calculate.
|
|
54
|
-
def fake_it!(db)
|
|
55
|
-
db.create_table!(table_name, temp: true, as: fake_row(db))
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def fake_row(db)
|
|
59
|
-
db
|
|
60
|
-
.select(Sequel.cast(nil, Bignum).as(:person_id))
|
|
61
|
-
.select_append(Sequel.cast(nil, Bignum).as(:criterion_id))
|
|
62
|
-
.select_append(Sequel.cast(nil, String).as(:criterion_type))
|
|
63
|
-
.select_append(Sequel.cast(nil, Date).as(:start_date))
|
|
64
|
-
.select_append(Sequel.cast(nil, Date).as(:end_date))
|
|
65
|
-
.select_append(Sequel.cast(nil, Bignum).as(:value_as_number))
|
|
66
|
-
.select_append(Sequel.cast(nil, String).as(:value_as_string))
|
|
67
|
-
.select_append(Sequel.cast(nil, Bignum).as(:value_as_concept_id))
|
|
68
|
-
.select_append(Sequel.cast(nil, String).as(:units_source_value))
|
|
69
|
-
.select_append(Sequel.cast(nil, String).as(:source_value))
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/operator'
|
|
3
|
-
require 'conceptql/behaviors/dottable'
|
|
4
|
-
|
|
5
|
-
class OperatorDouble < ConceptQL::Operators::Operator
|
|
6
|
-
include ConceptQL::Behaviors::Dottable
|
|
7
|
-
|
|
8
|
-
def initialize(*args)
|
|
9
|
-
super
|
|
10
|
-
@types = []
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
describe ConceptQL::Behaviors::Dottable do
|
|
15
|
-
before do
|
|
16
|
-
@obj = OperatorDouble.new
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
describe '#display_name' do
|
|
20
|
-
it 'should show just the name if no upstreams or arguments' do
|
|
21
|
-
@obj.values = []
|
|
22
|
-
expect(@obj.display_name).to match(/Operator Double( \d+)?/)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'should show name and args' do
|
|
26
|
-
@obj.values = [5, 10]
|
|
27
|
-
expect(@obj.display_name).to match(/Operator Double( \d+)?: 5, 10/)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'should not include upstreams' do
|
|
31
|
-
@obj.values = [::ConceptQL::Operators::Operator.new]
|
|
32
|
-
expect(@obj.display_name).to match(/Operator Double( \d+)?/)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
describe '#operator_name' do
|
|
37
|
-
it 'should show just the name and digit if no upstreams' do
|
|
38
|
-
@obj.values = [::ConceptQL::Operators::Operator.new]
|
|
39
|
-
expect(@obj.operator_name).to match(/^operator_double_\d+$/)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'should not show args' do
|
|
43
|
-
@obj.values = [5, 10]
|
|
44
|
-
expect(@obj.operator_name).to match(/^operator_double_\d+$/)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it 'should not include upstreams' do
|
|
48
|
-
@obj.values = [::ConceptQL::Operators::Operator.new]
|
|
49
|
-
expect(@obj.operator_name).to match(/^operator_double_\d+$/)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
describe '#graph_it' do
|
|
54
|
-
it 'should add itself as a operator if no upstreams' do
|
|
55
|
-
@obj.values = []
|
|
56
|
-
mock_graph = double("graph")
|
|
57
|
-
mock_operator = double("operator")
|
|
58
|
-
expect(mock_graph).to receive(:add_nodes).with(@obj.operator_name).and_return(mock_operator)
|
|
59
|
-
expect(mock_operator).to receive(:[]=).with(:label, @obj.display_name).and_return(nil)
|
|
60
|
-
expect(mock_operator).to receive(:[]=).with(:color, 'black').and_return(nil)
|
|
61
|
-
@obj.graph_it(mock_graph, Sequel.mock)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'should add its upstreams, then link itself as a operator if upstreams' do
|
|
65
|
-
class MockUpstream < ConceptQL::Operators::Operator
|
|
66
|
-
include ConceptQL::Behaviors::Dottable
|
|
67
|
-
|
|
68
|
-
attr_accessor :mock
|
|
69
|
-
def graph_it(graph, db)
|
|
70
|
-
mock.graph_it(graph, db)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def types
|
|
74
|
-
mock.types
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def link_to(mock_graph, mock_operator, db)
|
|
78
|
-
mock.link_to(mock_graph, mock_operator, db)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
mock_operator = double("operator")
|
|
83
|
-
expect(mock_operator).to receive(:[]=).with(:label, @obj.display_name).and_return(nil)
|
|
84
|
-
expect(mock_operator).to receive(:[]=).with(:color, 'black').and_return(nil)
|
|
85
|
-
|
|
86
|
-
mock_graph = double("graph")
|
|
87
|
-
expect(mock_graph).to receive(:add_nodes).with(@obj.operator_name).and_return(mock_operator)
|
|
88
|
-
|
|
89
|
-
mock_upstream = MockUpstream.new
|
|
90
|
-
mock_upstream.mock = double("upstream")
|
|
91
|
-
expect(mock_upstream.mock).to receive(:graph_it).with(mock_graph, :db).and_return(:upstream_operator)
|
|
92
|
-
expect(mock_upstream.mock).to receive(:link_to).with(mock_graph, mock_operator, :db).and_return(nil)
|
|
93
|
-
|
|
94
|
-
@obj.values = mock_upstream
|
|
95
|
-
|
|
96
|
-
@obj.graph_it(mock_graph, :db)
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/converter'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Converter do
|
|
5
|
-
describe '#convert' do
|
|
6
|
-
it 'convert {icd9: 412} to [:icd9, "412"]' do
|
|
7
|
-
statement = { icd9: '412' }
|
|
8
|
-
expect(ConceptQL::Converter.new.convert(statement)).to eq([:icd9, '412'])
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it 'convert {icd9: ["412", "200"]} to [:icd9, "412"]' do
|
|
12
|
-
statement = { icd9: %w(412 200) }
|
|
13
|
-
expect(ConceptQL::Converter.new.convert(statement)).to eq([:icd9, '412', '200'])
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'convert { first: {icd9: ["412", "200"]}} to [:first, [:icd9, "412"] ]' do
|
|
17
|
-
statement = {
|
|
18
|
-
first: {
|
|
19
|
-
icd9: %w(412 200)
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
expect(ConceptQL::Converter.new.convert(statement)).to eq([:first, [:icd9, '412', '200'] ])
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it 'convert operators in options to list-syntax' do
|
|
26
|
-
statement = {
|
|
27
|
-
after: {
|
|
28
|
-
left: {
|
|
29
|
-
icd9: '412'
|
|
30
|
-
},
|
|
31
|
-
right: {
|
|
32
|
-
icd9: '200'
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
expect(ConceptQL::Converter.new.convert(statement)).to eq([:after, { left: [:icd9, '412'], right: [:icd9, '200'] }])
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it 'converts operators with an array of upstreams' do
|
|
41
|
-
statement = {
|
|
42
|
-
intersect: [
|
|
43
|
-
{ icd9: '412' },
|
|
44
|
-
{ condition_type: :inpatient_header }
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
expect(ConceptQL::Converter.new.convert(statement)).to eq([:intersect, [ :icd9, '412' ], [ :condition_type, :inpatient_header ] ])
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/date_adjuster'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::DateAdjuster do
|
|
5
|
-
describe '#adjustments' do
|
|
6
|
-
it 'returns nothing for input of ""' do
|
|
7
|
-
expect(ConceptQL::DateAdjuster.new('').adjustments).to eq([])
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it 'returns nothing for input of "0"' do
|
|
11
|
-
expect(ConceptQL::DateAdjuster.new('').adjustments).to eq([])
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it 'returns nothing for input of nil' do
|
|
15
|
-
expect(ConceptQL::DateAdjuster.new(nil).adjustments).to eq([])
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it 'returns single day for input of "1"' do
|
|
19
|
-
expect(ConceptQL::DateAdjuster.new('1').adjustments).to eq([[:days, 1]])
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it 'returns 20 days for input of "20"' do
|
|
23
|
-
expect(ConceptQL::DateAdjuster.new('20').adjustments).to eq([[:days, 20]])
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'returns single day for input of "d"' do
|
|
27
|
-
expect(ConceptQL::DateAdjuster.new('d').adjustments).to eq([[:days, 1]])
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'returns single month for input of "m"' do
|
|
31
|
-
expect(ConceptQL::DateAdjuster.new('m').adjustments).to eq([[:months, 1]])
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'returns single year for input of "y"' do
|
|
35
|
-
expect(ConceptQL::DateAdjuster.new('y').adjustments).to eq([[:years, 1]])
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it 'returns 2 days for input of "2d"' do
|
|
39
|
-
expect(ConceptQL::DateAdjuster.new('2d').adjustments).to eq([[:days, 2]])
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'returns 2 months for input of "2m"' do
|
|
43
|
-
expect(ConceptQL::DateAdjuster.new('2m').adjustments).to eq([[:months, 2]])
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'returns 2 years for input of "2y"' do
|
|
47
|
-
expect(ConceptQL::DateAdjuster.new('2y').adjustments).to eq([[:years, 2]])
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'returns negative single day for input of "-d"' do
|
|
51
|
-
expect(ConceptQL::DateAdjuster.new('-d').adjustments).to eq([[:days, -1]])
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it 'returns negative single day, positive single month for "-dm"' do
|
|
55
|
-
expect(ConceptQL::DateAdjuster.new('-dm').adjustments).to eq([[:days, -1], [:months, 1]])
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'returns negative 2 days for "-2d"' do
|
|
59
|
-
expect(ConceptQL::DateAdjuster.new('-2d').adjustments).to eq([[:days, -2]])
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
it 'returns positive 2 days for "2d"' do
|
|
63
|
-
expect(ConceptQL::DateAdjuster.new('2d').adjustments).to eq([[:days, 2]])
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/after'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::After do
|
|
6
|
-
it_behaves_like(:temporal_operator)
|
|
7
|
-
|
|
8
|
-
subject do
|
|
9
|
-
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it 'should use proper where clause' do
|
|
13
|
-
expect(subject.query(Sequel.mock).sql).to match('l.start_date > r.end_date')
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/before'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::Before do
|
|
6
|
-
it_behaves_like(:temporal_operator)
|
|
7
|
-
|
|
8
|
-
subject do
|
|
9
|
-
described_class.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it 'should use proper where clause' do
|
|
13
|
-
expect(subject.query(Sequel.mock).sql).to match('l.end_date < r.start_date')
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/casting_operator'
|
|
3
|
-
require_double('stream_for_casting')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::CastingOperator do
|
|
6
|
-
it_behaves_like(:evaluator)
|
|
7
|
-
|
|
8
|
-
class CastingDouble < ConceptQL::Operators::CastingOperator
|
|
9
|
-
def my_type
|
|
10
|
-
:my_type
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def i_point_at
|
|
14
|
-
[ :i_point1, :i_point2 ]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def these_point_at_me
|
|
18
|
-
[ :at_me1, :at_me2 ]
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
describe CastingDouble do
|
|
23
|
-
it_behaves_like(:casting_operator)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
describe '#query' do
|
|
27
|
-
it 'uses person_ids when an uncastable type is encountered' do
|
|
28
|
-
stream = StreamForCastingDouble.new
|
|
29
|
-
stream.types = [:uncastable]
|
|
30
|
-
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
|
31
|
-
expect(sql).to match('person_id IN')
|
|
32
|
-
expect(sql).to match('GROUP BY person_id')
|
|
33
|
-
expect(sql).to match('FROM table')
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it 'uses person_ids when an uncastable type is included among castable types' do
|
|
37
|
-
stream = StreamForCastingDouble.new
|
|
38
|
-
stream.types = [:i_point1, :uncastable]
|
|
39
|
-
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
|
40
|
-
expect(sql).to match('person_id IN')
|
|
41
|
-
expect(sql).to match('GROUP BY person_id')
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it 'uses castable types if possible' do
|
|
45
|
-
stream = StreamForCastingDouble.new
|
|
46
|
-
stream.types = [:i_point1]
|
|
47
|
-
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
|
48
|
-
expect(sql).to match('i_point1_id IN')
|
|
49
|
-
expect(sql).to match("criterion_type = 'i_point1'")
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it 'uses and unions multiple castable types if possible' do
|
|
53
|
-
stream = StreamForCastingDouble.new
|
|
54
|
-
stream.types = [:i_point1, :at_me2]
|
|
55
|
-
sql = CastingDouble.new(stream).query(Sequel.mock).sql
|
|
56
|
-
expect(sql).to match('my_type_id IN')
|
|
57
|
-
expect(sql).to match('i_point1_id IN')
|
|
58
|
-
expect(sql).to match("criterion_type = 'i_point1'")
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it 'returns all rows of a table if passed the argument "true"' do
|
|
62
|
-
sql = CastingDouble.new(true).query(Sequel.mock).sql
|
|
63
|
-
expect(sql).to match("SELECT * FROM my_type AS tab")
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/operators/complement'
|
|
3
|
-
require_relative 'query_double'
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Operators::Complement do
|
|
6
|
-
it_behaves_like(:evaluator)
|
|
7
|
-
|
|
8
|
-
it 'generates complement for single criteria' do
|
|
9
|
-
double1 = QueryDouble.new(1)
|
|
10
|
-
sql = ConceptQL::Operators::Complement.new(double1).query(Sequel.mock).sql
|
|
11
|
-
expect(sql).to match("criterion_id IS NOT NULL")
|
|
12
|
-
expect(sql).to match("visit_occurrence_id NOT IN")
|
|
13
|
-
expect(sql).to match("criterion_type = 'visit_occurrence'")
|
|
14
|
-
end
|
|
15
|
-
end
|