conceptql 0.1.1 → 0.2.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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +53 -1
- data/Guardfile +52 -24
- data/conceptql.gemspec +5 -3
- data/doc/spec.md +2 -2
- data/lib/conceptql/behaviors/debuggable.rb +70 -0
- data/lib/conceptql/behaviors/dottable.rb +28 -14
- data/lib/conceptql/behaviors/metadatable.rb +97 -0
- data/lib/conceptql/behaviors/preppable.rb +20 -0
- data/lib/conceptql/cli.rb +31 -5
- data/lib/conceptql/converter.rb +65 -0
- data/lib/conceptql/debugger.rb +48 -0
- data/lib/conceptql/graph.rb +14 -13
- data/lib/conceptql/graph_nodifier.rb +49 -17
- data/lib/conceptql/nodifier.rb +31 -6
- data/lib/conceptql/operators/after.rb +25 -0
- data/lib/conceptql/operators/any_overlap.rb +15 -0
- data/lib/conceptql/operators/before.rb +21 -0
- data/lib/conceptql/{nodes/binary_operator_node.rb → operators/binary_operator_operator.rb} +12 -8
- data/lib/conceptql/{nodes/casting_node.rb → operators/casting_operator.rb} +8 -7
- data/lib/conceptql/{nodes → operators}/complement.rb +14 -11
- data/lib/conceptql/operators/concept.rb +70 -0
- data/lib/conceptql/{nodes → operators}/condition_type.rb +13 -5
- data/lib/conceptql/operators/contains.rb +17 -0
- data/lib/conceptql/operators/count.rb +26 -0
- data/lib/conceptql/operators/cpt.rb +25 -0
- data/lib/conceptql/{nodes → operators}/date_range.rb +11 -6
- data/lib/conceptql/operators/death.rb +23 -0
- data/lib/conceptql/operators/drug_type_concept.rb +21 -0
- data/lib/conceptql/{nodes → operators}/during.rb +9 -3
- data/lib/conceptql/operators/equal.rb +13 -0
- data/lib/conceptql/operators/except.rb +28 -0
- data/lib/conceptql/operators/filter.rb +21 -0
- data/lib/conceptql/{nodes → operators}/first.rb +7 -5
- data/lib/conceptql/{nodes → operators}/from.rb +2 -2
- data/lib/conceptql/operators/from_seer_visits.rb +23 -0
- data/lib/conceptql/{nodes → operators}/gender.rb +6 -6
- data/lib/conceptql/operators/hcpcs.rb +25 -0
- data/lib/conceptql/operators/icd10.rb +28 -0
- data/lib/conceptql/operators/icd9.rb +28 -0
- data/lib/conceptql/operators/icd9_procedure.rb +25 -0
- data/lib/conceptql/{nodes → operators}/intersect.rb +7 -3
- data/lib/conceptql/{nodes → operators}/last.rb +7 -5
- data/lib/conceptql/operators/loinc.rb +25 -0
- data/lib/conceptql/operators/medcode.rb +28 -0
- data/lib/conceptql/operators/medcode_procedure.rb +27 -0
- data/lib/conceptql/operators/ndc.rb +29 -0
- data/lib/conceptql/operators/numeric.rb +54 -0
- data/lib/conceptql/operators/observation_by_enttype.rb +29 -0
- data/lib/conceptql/operators/observation_period.rb +30 -0
- data/lib/conceptql/operators/occurrence.rb +70 -0
- data/lib/conceptql/operators/one_in_two_out.rb +62 -0
- data/lib/conceptql/{nodes/node.rb → operators/operator.rb} +84 -52
- data/lib/conceptql/operators/overlapped_by.rb +23 -0
- data/lib/conceptql/operators/overlaps.rb +19 -0
- data/lib/conceptql/operators/pass_thru.rb +11 -0
- data/lib/conceptql/{nodes → operators}/person.rb +8 -4
- data/lib/conceptql/operators/person_filter.rb +13 -0
- data/lib/conceptql/{nodes → operators}/place_of_service_code.rb +7 -7
- data/lib/conceptql/operators/procedure_occurrence.rb +25 -0
- data/lib/conceptql/operators/prodcode.rb +29 -0
- data/lib/conceptql/{nodes → operators}/race.rb +7 -7
- data/lib/conceptql/operators/recall.rb +38 -0
- data/lib/conceptql/operators/rxnorm.rb +24 -0
- data/lib/conceptql/operators/snomed.rb +24 -0
- data/lib/conceptql/operators/snomed_condition.rb +26 -0
- data/lib/conceptql/{nodes/source_vocabulary_node.rb → operators/source_vocabulary_operator.rb} +7 -4
- data/lib/conceptql/{nodes/standard_vocabulary_node.rb → operators/standard_vocabulary_operator.rb} +6 -4
- data/lib/conceptql/{nodes → operators}/started_by.rb +9 -3
- data/lib/conceptql/{nodes → operators}/sum.rb +9 -4
- data/lib/conceptql/{nodes/temporal_node.rb → operators/temporal_operator.rb} +7 -4
- data/lib/conceptql/{nodes → operators}/time_window.rb +19 -7
- data/lib/conceptql/operators/to_seer_visits.rb +24 -0
- data/lib/conceptql/operators/trim_date_end.rb +55 -0
- data/lib/conceptql/operators/trim_date_start.rb +56 -0
- data/lib/conceptql/{nodes → operators}/union.rb +6 -2
- data/lib/conceptql/operators/visit.rb +15 -0
- data/lib/conceptql/{nodes → operators}/visit_occurrence.rb +7 -3
- data/lib/conceptql/query.rb +19 -17
- data/lib/conceptql/scope.rb +69 -0
- data/lib/conceptql/tree.rb +33 -18
- data/lib/conceptql/utils/temp_table.rb +72 -0
- data/lib/conceptql/version.rb +1 -1
- data/spec/conceptql/behaviors/dottable_spec.rb +39 -51
- data/spec/conceptql/converter_spec.rb +51 -0
- data/spec/conceptql/date_adjuster_spec.rb +15 -15
- data/spec/conceptql/operators/after_spec.rb +16 -0
- data/spec/conceptql/operators/before_spec.rb +16 -0
- data/spec/conceptql/{nodes/casting_node_spec.rb → operators/casting_operator_spec.rb} +16 -20
- data/spec/conceptql/operators/complement_spec.rb +15 -0
- data/spec/conceptql/operators/concept_spec.rb +40 -0
- data/spec/conceptql/{nodes → operators}/condition_type_spec.rb +39 -24
- data/spec/conceptql/operators/contains_spec.rb +19 -0
- data/spec/conceptql/operators/cpt_spec.rb +29 -0
- data/spec/conceptql/operators/date_range_spec.rb +33 -0
- data/spec/conceptql/operators/death_spec.rb +10 -0
- data/spec/conceptql/operators/during_spec.rb +30 -0
- data/spec/conceptql/operators/except_spec.rb +15 -0
- data/spec/conceptql/operators/first_spec.rb +35 -0
- data/spec/conceptql/operators/from_spec.rb +13 -0
- data/spec/conceptql/operators/gender_spec.rb +27 -0
- data/spec/conceptql/operators/hcpcs_spec.rb +29 -0
- data/spec/conceptql/operators/icd10_spec.rb +34 -0
- data/spec/conceptql/operators/icd9_procedure_spec.rb +29 -0
- data/spec/conceptql/operators/icd9_spec.rb +34 -0
- data/spec/conceptql/operators/intersect_spec.rb +28 -0
- data/spec/conceptql/operators/last_spec.rb +36 -0
- data/spec/conceptql/operators/loinc_spec.rb +29 -0
- data/spec/conceptql/operators/medcode_procedure_spec.rb +34 -0
- data/spec/conceptql/operators/medcode_spec.rb +34 -0
- data/spec/conceptql/operators/observation_period_spec.rb +10 -0
- data/spec/conceptql/operators/occurrence_spec.rb +87 -0
- data/spec/conceptql/operators/overlapped_by_spec.rb +32 -0
- data/spec/conceptql/operators/overlaps_spec.rb +21 -0
- data/spec/conceptql/operators/person_filter_spec.rb +15 -0
- data/spec/conceptql/operators/person_spec.rb +10 -0
- data/spec/conceptql/{nodes → operators}/place_of_service_code_spec.rb +6 -8
- data/spec/conceptql/operators/procedure_occurrence_spec.rb +10 -0
- data/spec/conceptql/operators/prodcode_spec.rb +35 -0
- data/spec/conceptql/operators/query_double.rb +20 -0
- data/spec/conceptql/operators/query_double_spec.rb +7 -0
- data/spec/conceptql/operators/race_spec.rb +21 -0
- data/spec/conceptql/operators/rxnorm_spec.rb +29 -0
- data/spec/conceptql/operators/snomed_spec.rb +29 -0
- data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +35 -0
- data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +35 -0
- data/spec/conceptql/operators/started_by_spec.rb +22 -0
- data/spec/conceptql/{nodes/temporal_node_spec.rb → operators/temporal_operator_spec.rb} +11 -17
- data/spec/conceptql/operators/time_window_spec.rb +77 -0
- data/spec/conceptql/operators/union_spec.rb +21 -0
- data/spec/conceptql/operators/visit_occurrence_spec.rb +10 -0
- data/spec/conceptql/query_spec.rb +10 -9
- data/spec/conceptql/tree_spec.rb +24 -28
- data/spec/doubles/stream_for_casting_double.rb +1 -1
- data/spec/doubles/stream_for_occurrence_double.rb +1 -1
- data/spec/doubles/stream_for_temporal_double.rb +1 -1
- data/spec/spec_helper.rb +74 -58
- metadata +202 -133
- data/lib/conceptql/nodes/after.rb +0 -12
- data/lib/conceptql/nodes/before.rb +0 -11
- data/lib/conceptql/nodes/concept.rb +0 -38
- data/lib/conceptql/nodes/count.rb +0 -23
- data/lib/conceptql/nodes/cpt.rb +0 -20
- data/lib/conceptql/nodes/death.rb +0 -19
- data/lib/conceptql/nodes/define.rb +0 -96
- data/lib/conceptql/nodes/drug_type_concept.rb +0 -18
- data/lib/conceptql/nodes/equal.rb +0 -11
- data/lib/conceptql/nodes/except.rb +0 -11
- data/lib/conceptql/nodes/hcpcs.rb +0 -20
- data/lib/conceptql/nodes/icd10.rb +0 -23
- data/lib/conceptql/nodes/icd9.rb +0 -23
- data/lib/conceptql/nodes/icd9_procedure.rb +0 -20
- data/lib/conceptql/nodes/loinc.rb +0 -20
- data/lib/conceptql/nodes/numeric.rb +0 -40
- data/lib/conceptql/nodes/occurrence.rb +0 -49
- data/lib/conceptql/nodes/pass_thru.rb +0 -11
- data/lib/conceptql/nodes/person_filter.rb +0 -12
- data/lib/conceptql/nodes/procedure_occurrence.rb +0 -21
- data/lib/conceptql/nodes/recall.rb +0 -50
- data/lib/conceptql/nodes/rxnorm.rb +0 -20
- data/lib/conceptql/nodes/snomed.rb +0 -19
- data/lib/conceptql/nodes/visit.rb +0 -11
- data/spec/conceptql/nodes/after_spec.rb +0 -18
- data/spec/conceptql/nodes/before_spec.rb +0 -18
- data/spec/conceptql/nodes/complement_spec.rb +0 -15
- data/spec/conceptql/nodes/concept_spec.rb +0 -34
- data/spec/conceptql/nodes/cpt_spec.rb +0 -31
- data/spec/conceptql/nodes/date_range_spec.rb +0 -35
- data/spec/conceptql/nodes/death_spec.rb +0 -12
- data/spec/conceptql/nodes/during_spec.rb +0 -32
- data/spec/conceptql/nodes/except_spec.rb +0 -18
- data/spec/conceptql/nodes/first_spec.rb +0 -37
- data/spec/conceptql/nodes/from_spec.rb +0 -15
- data/spec/conceptql/nodes/gender_spec.rb +0 -29
- data/spec/conceptql/nodes/hcpcs_spec.rb +0 -31
- data/spec/conceptql/nodes/icd10_spec.rb +0 -36
- data/spec/conceptql/nodes/icd9_procedure_spec.rb +0 -31
- data/spec/conceptql/nodes/icd9_spec.rb +0 -36
- data/spec/conceptql/nodes/intersect_spec.rb +0 -33
- data/spec/conceptql/nodes/last_spec.rb +0 -38
- data/spec/conceptql/nodes/loinc_spec.rb +0 -31
- data/spec/conceptql/nodes/occurrence_spec.rb +0 -89
- data/spec/conceptql/nodes/person_filter_spec.rb +0 -18
- data/spec/conceptql/nodes/person_spec.rb +0 -12
- data/spec/conceptql/nodes/procedure_occurrence_spec.rb +0 -12
- data/spec/conceptql/nodes/query_double.rb +0 -19
- data/spec/conceptql/nodes/race_spec.rb +0 -23
- data/spec/conceptql/nodes/rxnorm_spec.rb +0 -31
- data/spec/conceptql/nodes/snomed_spec.rb +0 -31
- data/spec/conceptql/nodes/source_vocabulary_node_spec.rb +0 -37
- data/spec/conceptql/nodes/standard_vocabulary_node_spec.rb +0 -40
- data/spec/conceptql/nodes/started_by_spec.rb +0 -25
- data/spec/conceptql/nodes/time_window_spec.rb +0 -85
- data/spec/conceptql/nodes/union_spec.rb +0 -25
- data/spec/conceptql/nodes/visit_occurrence_spec.rb +0 -12
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
require_relative 'pass_thru'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Count < PassThru
|
|
6
|
-
def query(db)
|
|
7
|
-
db.from(unioned(db))
|
|
8
|
-
.group(*COLUMNS)
|
|
9
|
-
.select(*(COLUMNS - [:value_as_numeric]))
|
|
10
|
-
.select_append{count(1).as(:value_as_numeric)}
|
|
11
|
-
.from_self
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def unioned(db)
|
|
15
|
-
children.map { |c| c.evaluate(db) }.inject do |uni, q|
|
|
16
|
-
uni.union(q)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
|
data/lib/conceptql/nodes/cpt.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require_relative 'standard_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Cpt < StandardVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:procedure_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
4
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def concept_column
|
|
15
|
-
:procedure_concept_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
require_relative 'node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
# Mimics creating a variable name that stores an itermediate result as
|
|
6
|
-
# part of a larger concept
|
|
7
|
-
#
|
|
8
|
-
# The idea is that a concept might be very complex and it helps to break
|
|
9
|
-
# that complex concept into a set of sub-concepts to better understand it.
|
|
10
|
-
#
|
|
11
|
-
# Also, sometimes a particular piece of a concept is used in many places,
|
|
12
|
-
# so it makes sense to write that piece out once, store it as a "variable"
|
|
13
|
-
# and then insert that variable into the concept as needed.
|
|
14
|
-
# run the query once and subsequent calls
|
|
15
|
-
class Define < Node
|
|
16
|
-
def initialize(*args)
|
|
17
|
-
super
|
|
18
|
-
end
|
|
19
|
-
# Create a temporary table and store the stream of results in that table.
|
|
20
|
-
# This "caches" the results so we only have to execute stream's query
|
|
21
|
-
# once.
|
|
22
|
-
#
|
|
23
|
-
# The logic here is that if something is assigned to a variable, chances
|
|
24
|
-
# are that it will be used more than once, so why run the query more than
|
|
25
|
-
# once?
|
|
26
|
-
#
|
|
27
|
-
# ConceptQL's SQL generator normally translates the entire statement into
|
|
28
|
-
# one, large query that can be executed later.
|
|
29
|
-
#
|
|
30
|
-
# Unfortunately, Sequel's "create_table" function actually executes the
|
|
31
|
-
# 'CREATE TABLE' SQL right away, meaning that the "define" node will
|
|
32
|
-
# execute immediately _during_ the processing of the ConceptQL statement.
|
|
33
|
-
# We'll see what kinds of problems this causes
|
|
34
|
-
#
|
|
35
|
-
# Lastly, this node does NOT pass its results to the next node. The
|
|
36
|
-
# reason for this exception is to allow us to return the SQL that
|
|
37
|
-
# generates the temp table. This is done so that the ConceptQL sandbox
|
|
38
|
-
# can return the entire set of SQL statements needed to run a query.
|
|
39
|
-
#
|
|
40
|
-
# Perhaps in the future we can find a way around this.
|
|
41
|
-
#
|
|
42
|
-
# Also, things will blow up if you try to use a variable that hasn't been
|
|
43
|
-
# defined yet.
|
|
44
|
-
def query(db)
|
|
45
|
-
# We'll wrap the creation of the temp table in memoization
|
|
46
|
-
# That way we can call #query multiple times, but only suffer the
|
|
47
|
-
# cost of creating the temp table just once
|
|
48
|
-
@_run ||= begin
|
|
49
|
-
if tree.opts[:sql_only]
|
|
50
|
-
db.create_table!(table_name, temp: true, as: fake_row(db))
|
|
51
|
-
else
|
|
52
|
-
db.create_table!(table_name, temp: true, as: stream.evaluate(db))
|
|
53
|
-
end
|
|
54
|
-
true
|
|
55
|
-
end
|
|
56
|
-
db.from(table_name)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def columns(query, local_type)
|
|
60
|
-
COLUMNS
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def types
|
|
64
|
-
stream.types
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def sql(db)
|
|
68
|
-
db[db.send(:create_table_as_sql, table_name, stream.evaluate(db).sql, temp: true)].sql
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def tree=(tree)
|
|
72
|
-
super
|
|
73
|
-
tree.defined[table_name] = self
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
private
|
|
77
|
-
|
|
78
|
-
def table_name
|
|
79
|
-
@table_name ||= namify(arguments.first)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def fake_row(db)
|
|
83
|
-
db
|
|
84
|
-
.select(Sequel.cast(nil, Bignum).as(:person_id))
|
|
85
|
-
.select_append(Sequel.cast(nil, Bignum).as(:criterion_id))
|
|
86
|
-
.select_append(Sequel.cast(nil, String).as(:criterion_type))
|
|
87
|
-
.select_append(Sequel.cast(nil, Date).as(:start_date))
|
|
88
|
-
.select_append(Sequel.cast(nil, Date).as(:end_date))
|
|
89
|
-
.select_append(Sequel.cast(nil, Bignum).as(:value_as_numeric))
|
|
90
|
-
.select_append(Sequel.cast(nil, String).as(:value_as_string))
|
|
91
|
-
.select_append(Sequel.cast(nil, Bignum).as(:value_as_concept_id))
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require_relative 'node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class DrugTypeConcept < Node
|
|
6
|
-
def type
|
|
7
|
-
:drug_exposure
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def query(db)
|
|
11
|
-
db.from(:drug_exposure)
|
|
12
|
-
.where(drug_type_concept_id: arguments)
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require_relative 'standard_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Hcpcs < StandardVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:procedure_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
5
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def concept_column
|
|
15
|
-
:procedure_concept_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
require_relative 'source_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Icd10 < SourceVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:condition_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
34
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def source_column
|
|
15
|
-
:condition_source_value
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def concept_column
|
|
19
|
-
:condition_concept_id
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
data/lib/conceptql/nodes/icd9.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
require_relative 'source_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Icd9 < SourceVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:condition_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
2
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def source_column
|
|
15
|
-
:condition_source_value
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def concept_column
|
|
19
|
-
:condition_concept_id
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require_relative 'standard_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Icd9Procedure < StandardVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:procedure_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
3
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def concept_column
|
|
15
|
-
:procedure_concept_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require_relative 'standard_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Loinc < StandardVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:observation
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
6
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def concept_column
|
|
15
|
-
:observation_concept_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
require_relative 'pass_thru'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
# Represents a node that will either:
|
|
6
|
-
# - create a value_as_numeric value for every person in the database
|
|
7
|
-
# - change the value_as_numeric value for every every result passed in
|
|
8
|
-
# - either to a numeric
|
|
9
|
-
# - or a value from a column in the origin row
|
|
10
|
-
#
|
|
11
|
-
# Accepts two params:
|
|
12
|
-
# - Either a numeric value or a symbol representing a column name
|
|
13
|
-
# - An optional stream
|
|
14
|
-
class Numeric < PassThru
|
|
15
|
-
def query(db)
|
|
16
|
-
stream.nil? ? as_criterion(db) : with_kids(db)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def types
|
|
20
|
-
stream.nil? ? [:person] : super
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
def with_kids(db)
|
|
25
|
-
db.from(stream.evaluate(db))
|
|
26
|
-
.select(*(COLUMNS - [:value_as_numeric]))
|
|
27
|
-
.select_append(Sequel.lit('?', arguments.first).cast(Float).as(:value_as_numeric))
|
|
28
|
-
.from_self
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def as_criterion(db)
|
|
32
|
-
db.from(select_it(db.from(:person), :person))
|
|
33
|
-
.select(*(COLUMNS - [:value_as_numeric]))
|
|
34
|
-
.select_append(Sequel.lit('?', arguments.first).cast(Float).as(:value_as_numeric))
|
|
35
|
-
.from_self
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
require_relative 'node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
# Represents a node that will grab the Nth occurrence of something
|
|
6
|
-
#
|
|
7
|
-
# Specify occurrences as integers, excluding O
|
|
8
|
-
# 1 => first
|
|
9
|
-
# 2 => second
|
|
10
|
-
# ...
|
|
11
|
-
# -1 => last
|
|
12
|
-
# -2 => second-to-last
|
|
13
|
-
#
|
|
14
|
-
# The node treats all streams as a single, large stream. It partitions
|
|
15
|
-
# that larget stream by person_id, then sorts within those groupings
|
|
16
|
-
# by start_date and then select at most one row per person, regardless
|
|
17
|
-
# of how many different types of streams enter the node
|
|
18
|
-
#
|
|
19
|
-
# If two rows have the same start_date, the order of their ranking
|
|
20
|
-
# is arbitrary
|
|
21
|
-
#
|
|
22
|
-
# If we ask for the second occurrence of something and a person has only one
|
|
23
|
-
# occurrence, this node returns nothing for that person
|
|
24
|
-
class Occurrence < Node
|
|
25
|
-
def query(db)
|
|
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
|
|
30
|
-
.where(rn: occurrence.abs)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def occurrence
|
|
34
|
-
@occurrence ||= arguments.first
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
def asc_or_desc
|
|
39
|
-
occurrence < 0 ? :desc : :asc
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def ordered_columns
|
|
43
|
-
ordered_columns = [Sequel.send(asc_or_desc, :start_date)]
|
|
44
|
-
ordered_columns += [:criterion_type, :criterion_id]
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
require_relative 'casting_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class ProcedureOccurrence < CastingNode
|
|
6
|
-
def my_type
|
|
7
|
-
:procedure_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def i_point_at
|
|
11
|
-
[ :person ]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def these_point_at_me
|
|
15
|
-
%i[
|
|
16
|
-
procedure_cost
|
|
17
|
-
]
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
require_relative 'pass_thru'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
# Mimics using a variable that has been set via "define" node
|
|
6
|
-
#
|
|
7
|
-
# The idea is that a concept might be very complex and it helps to break
|
|
8
|
-
# that complex concept into a set of sub-concepts to better understand it.
|
|
9
|
-
#
|
|
10
|
-
# This node will look for a sub-concept that has been created through the
|
|
11
|
-
# "define" node and will fetch the results cached in the corresponding table
|
|
12
|
-
class Recall < Node
|
|
13
|
-
# Behind the scenes we simply fetch all rows from the temp table that
|
|
14
|
-
# corresponds to the name fed to "recall"
|
|
15
|
-
#
|
|
16
|
-
# We also set the @types variable by pulling the type information out
|
|
17
|
-
# of the hash piggybacking on the database connection.
|
|
18
|
-
#
|
|
19
|
-
# TODO: This might be an issue since we might need the type information
|
|
20
|
-
# before we call #query. Probably time to reevaluate how we're caching
|
|
21
|
-
# the type information.
|
|
22
|
-
def query(db)
|
|
23
|
-
# We're going to call evaluate on definition to ensure the definition
|
|
24
|
-
# has been created. We were running into odd timing issues when
|
|
25
|
-
# drawing graphs where the recall node was being drawn before definition
|
|
26
|
-
# was drawn.
|
|
27
|
-
definition.evaluate(db)
|
|
28
|
-
db.from(table_name)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def columns(query, local_type)
|
|
32
|
-
COLUMNS
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def types
|
|
36
|
-
definition.types
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private
|
|
40
|
-
def table_name
|
|
41
|
-
@table_name ||= namify(arguments.first)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def definition
|
|
45
|
-
tree.defined[table_name]
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require_relative 'standard_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Rxnorm < StandardVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:drug_exposure
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
8
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def concept_column
|
|
15
|
-
:drug_concept_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
require_relative 'standard_vocabulary_node'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Nodes
|
|
5
|
-
class Snomed < StandardVocabularyNode
|
|
6
|
-
def table
|
|
7
|
-
:condition_occurrence
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def vocabulary_id
|
|
11
|
-
1
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def concept_column
|
|
15
|
-
:condition_concept_id
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/nodes/after'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Nodes::After do
|
|
6
|
-
it 'behaves itself' do
|
|
7
|
-
ConceptQL::Nodes::After.new.must_behave_like(:temporal_node)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
subject do
|
|
11
|
-
ConceptQL::Nodes::After.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it 'should use proper where clause' do
|
|
15
|
-
subject.query(Sequel.mock).sql.must_match 'l.start_date > r.end_date'
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/nodes/before'
|
|
3
|
-
require_double('stream_for_temporal')
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Nodes::Before do
|
|
6
|
-
it 'behaves itself' do
|
|
7
|
-
ConceptQL::Nodes::Before.new.must_behave_like(:temporal_node)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
subject do
|
|
11
|
-
ConceptQL::Nodes::Before.new(left: StreamForTemporalDouble.new, right: StreamForTemporalDouble.new)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it 'should use proper where clause' do
|
|
15
|
-
subject.query(Sequel.mock).sql.must_match 'l.end_date < r.start_date'
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/nodes/complement'
|
|
3
|
-
require_relative 'query_double'
|
|
4
|
-
|
|
5
|
-
describe ConceptQL::Nodes::Complement do
|
|
6
|
-
it 'behaves itself' do
|
|
7
|
-
ConceptQL::Nodes::Complement.new.must_behave_like(:evaluator)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it 'generates complement for single criteria' do
|
|
11
|
-
double1 = QueryDouble.new(1)
|
|
12
|
-
double1.must_behave_like(:evaluator)
|
|
13
|
-
ConceptQL::Nodes::Complement.new(double1).query(Sequel.mock).sql.must_equal "SELECT * FROM (SELECT 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, CAST(NULL AS numeric) AS value_as_numeric, CAST(NULL AS varchar(255)) AS value_as_string, CAST(NULL AS integer) AS value_as_concept_id 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
|
-
end
|
|
15
|
-
end
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/nodes/concept'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Nodes::Concept do
|
|
5
|
-
it 'behaves itself' do
|
|
6
|
-
ConceptQL::Nodes::Concept.new.must_behave_like(:evaluator)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
class ConceptDouble < ConceptQL::Nodes::Concept
|
|
10
|
-
def arguments
|
|
11
|
-
[1]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def set_statement(value)
|
|
15
|
-
# Do Nothing
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def stream
|
|
19
|
-
@stream ||= Minitest::Mock.new
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe '#query' do
|
|
24
|
-
it 'evaluates child' do
|
|
25
|
-
cd = ConceptDouble.new(1)
|
|
26
|
-
cd.stream.expect :evaluate, nil, [:db]
|
|
27
|
-
cd.query(:db)
|
|
28
|
-
cd.stream.verify
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
require 'conceptql/nodes/cpt'
|
|
3
|
-
|
|
4
|
-
describe ConceptQL::Nodes::Cpt do
|
|
5
|
-
it 'behaves itself' do
|
|
6
|
-
ConceptQL::Nodes::Cpt.new.must_behave_like(:standard_vocabulary_node)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
subject do
|
|
10
|
-
ConceptQL::Nodes::Cpt.new
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
describe '#table' do
|
|
14
|
-
it 'should be procedure_occurrence' do
|
|
15
|
-
subject.table.must_equal :procedure_occurrence
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
describe '#concept_column' do
|
|
20
|
-
it 'should be procedure_concept_id' do
|
|
21
|
-
subject.concept_column.must_equal :procedure_concept_id
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe '#vocabulary_id' do
|
|
26
|
-
it 'should be 4' do
|
|
27
|
-
subject.vocabulary_id.must_equal 4
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|