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,70 +0,0 @@
|
|
|
1
|
-
require_relative '../behaviors/dottable'
|
|
2
|
-
require_relative '../operators/operator'
|
|
3
|
-
require_relative '../operators/binary_operator_operator'
|
|
4
|
-
require 'csv'
|
|
5
|
-
module ConceptQL
|
|
6
|
-
module Behaviors
|
|
7
|
-
module Debuggable
|
|
8
|
-
include Dottable
|
|
9
|
-
class ResultPrinter
|
|
10
|
-
attr :db, :dir, :type, :watch_ids, :operator
|
|
11
|
-
def initialize(db, dir, type, watch_ids, operator)
|
|
12
|
-
@db = db
|
|
13
|
-
@dir = dir
|
|
14
|
-
@type = type
|
|
15
|
-
@watch_ids = watch_ids
|
|
16
|
-
@operator = operator
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def make_file
|
|
20
|
-
CSV.open(file_path, 'w') do |csv|
|
|
21
|
-
csv << ConceptQL::Operators::Operator::COLUMNS
|
|
22
|
-
results.each do |result|
|
|
23
|
-
csv << result
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
file_path
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def file_path
|
|
30
|
-
@file_path ||= dir + file_name
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def file_name
|
|
34
|
-
@file_name ||= [operator.operator_name, abbreviate(type)].join('_')
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def results
|
|
38
|
-
q = operator.evaluate(db)
|
|
39
|
-
.from_self
|
|
40
|
-
.where(criterion_type: type.to_s)
|
|
41
|
-
unless watch_ids.empty?
|
|
42
|
-
q = q.where(person_id: watch_ids)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
q.order([:person_id, :criterion_type, :start_date, :end_date, :criterion_id])
|
|
46
|
-
.select_map(ConceptQL::Operators::Operator::COLUMNS)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def abbreviate(type)
|
|
50
|
-
type.to_s.split('_').map(&:chars).map(&:first).join('')
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def print_results(db, dir, watch_ids)
|
|
55
|
-
print_prep(db) if respond_to?(:print_prep)
|
|
56
|
-
kids = upstreams
|
|
57
|
-
if self.is_a?(ConceptQL::Operators::BinaryOperatorOperator)
|
|
58
|
-
kids = [left, right]
|
|
59
|
-
end
|
|
60
|
-
files = kids.map do |upstream|
|
|
61
|
-
upstream.print_results(db, dir, watch_ids)
|
|
62
|
-
end
|
|
63
|
-
files += types.map do |type|
|
|
64
|
-
ResultPrinter.new(db, dir, type, watch_ids, self).make_file
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
require 'facets/string/snakecase'
|
|
2
|
-
require 'facets/string/titlecase'
|
|
3
|
-
|
|
4
|
-
module ConceptQL
|
|
5
|
-
module Behaviors
|
|
6
|
-
module Dottable
|
|
7
|
-
@@counter = 0
|
|
8
|
-
TYPE_COLORS = {
|
|
9
|
-
person: 'blue',
|
|
10
|
-
visit_occurrence: 'orange',
|
|
11
|
-
condition_occurrence: 'red',
|
|
12
|
-
procedure_occurrence: 'green3',
|
|
13
|
-
procedure_cost: 'gold',
|
|
14
|
-
death: 'brown',
|
|
15
|
-
payer_plan_period: 'blue',
|
|
16
|
-
drug_exposure: 'purple',
|
|
17
|
-
observation: 'magenta',
|
|
18
|
-
misc: 'black'
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
def operator_number
|
|
22
|
-
@__operator_number ||= (@@counter += 1)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def reset_operator_number
|
|
26
|
-
@@counter = 0
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def operator_name
|
|
30
|
-
@__operator_name ||= self.class.name.split('::').last.snakecase.gsub(/\W/, '_').downcase + "_#{operator_number}"
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def display_name
|
|
34
|
-
@__display_name ||= begin
|
|
35
|
-
output = self.class.name.split('::').last.snakecase.titlecase
|
|
36
|
-
#output += " #{operator_number}"
|
|
37
|
-
output += ": #{arguments.join(', ')}" unless arguments.empty?
|
|
38
|
-
if output.length > 100
|
|
39
|
-
parts = output.split
|
|
40
|
-
output = parts.each_slice(output.length / parts.count).map do |subparts|
|
|
41
|
-
subparts.join(' ')
|
|
42
|
-
end.join ('\n')
|
|
43
|
-
end
|
|
44
|
-
output += "\n#{options.map{|k,v| "#{k}: #{v}"}.join("\n")}" unless options.nil? || options.empty?
|
|
45
|
-
output
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def type_color(*types)
|
|
50
|
-
types.flatten!
|
|
51
|
-
types.length == 1 ? TYPE_COLORS[types.first] || 'black' : 'black'
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def graph_operator(g)
|
|
55
|
-
@__graph_operator ||= begin
|
|
56
|
-
me = g.add_nodes(operator_name)
|
|
57
|
-
me[:label] = display_name
|
|
58
|
-
me[:color] = type_color(types)
|
|
59
|
-
me[:shape] = shape if respond_to?(:shape)
|
|
60
|
-
me
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def link_to(g, dest_operator, db = nil)
|
|
65
|
-
edge_options = {}
|
|
66
|
-
|
|
67
|
-
types.each do |type|
|
|
68
|
-
if db
|
|
69
|
-
my_n = my_n(db, type)
|
|
70
|
-
label = [' rows=' + my_count(db, type).to_s + ' ']
|
|
71
|
-
label << ' n=' + my_n.to_s + ' '
|
|
72
|
-
edge_options[:label] = label.join("\n")
|
|
73
|
-
edge_options[:style] = 'dashed' if my_n.zero?
|
|
74
|
-
end
|
|
75
|
-
e = g.add_edges(graph_operator(g), dest_operator, edge_options)
|
|
76
|
-
e[:color] = type_color(type)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def graph_it(g, db)
|
|
81
|
-
graph_prep(db) if respond_to?(:graph_prep)
|
|
82
|
-
upstreams.each do |upstream|
|
|
83
|
-
upstream.graph_it(g, db)
|
|
84
|
-
end
|
|
85
|
-
operator = graph_operator(g)
|
|
86
|
-
upstreams.each do |upstream|
|
|
87
|
-
upstream.link_to(g, graph_operator(g), db)
|
|
88
|
-
end
|
|
89
|
-
operator
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def my_count(db, type)
|
|
93
|
-
puts "counting #{operator_name} #{type}"
|
|
94
|
-
evaluate(db).from_self.where(criterion_type: type.to_s).count
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def my_n(db, type)
|
|
98
|
-
evaluate(db).from_self.where(criterion_type: type.to_s).select_group(:person_id).count
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
data/lib/conceptql/converter.rb
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
require 'facets/array/extract_options'
|
|
2
|
-
require 'facets/hash/deep_rekey'
|
|
3
|
-
require 'facets/hash/update_values'
|
|
4
|
-
|
|
5
|
-
module ConceptQL
|
|
6
|
-
class Converter
|
|
7
|
-
def convert(statement)
|
|
8
|
-
traverse(statement).to_list_syntax
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
class Operator
|
|
13
|
-
attr :type, :values, :options
|
|
14
|
-
def initialize(type, *values)
|
|
15
|
-
@type, @values = type, values.flatten
|
|
16
|
-
@options = @values.extract_options!.deep_rekey
|
|
17
|
-
@values = @values
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def args
|
|
21
|
-
values.select { |s| !s.is_a?(Operator) }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def upstreams
|
|
25
|
-
values.select { |s| s.is_a?(Operator) }
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def converted_options
|
|
29
|
-
options.update_values do |value|
|
|
30
|
-
if value.is_a?(Operator)
|
|
31
|
-
value.to_list_syntax
|
|
32
|
-
else
|
|
33
|
-
value
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def to_list_syntax
|
|
39
|
-
stmt = [type]
|
|
40
|
-
stmt += args unless args.empty?
|
|
41
|
-
stmt += upstreams.map(&:to_list_syntax) unless upstreams.empty?
|
|
42
|
-
stmt << converted_options unless options.empty?
|
|
43
|
-
stmt
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def traverse(obj)
|
|
48
|
-
case obj
|
|
49
|
-
when Hash
|
|
50
|
-
if obj.keys.length > 1
|
|
51
|
-
obj = Hash[obj.map { |key, value| [ key, traverse(value) ]}]
|
|
52
|
-
return obj
|
|
53
|
-
end
|
|
54
|
-
type = obj.keys.first
|
|
55
|
-
values = traverse(obj[type])
|
|
56
|
-
obj = Operator.new(type, values)
|
|
57
|
-
obj
|
|
58
|
-
when Array
|
|
59
|
-
obj.map { |value| traverse(value) }
|
|
60
|
-
else
|
|
61
|
-
obj
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
data/lib/conceptql/debugger.rb
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
require_relative 'tree'
|
|
2
|
-
require_relative 'operators/operator'
|
|
3
|
-
require_relative 'behaviors/debuggable'
|
|
4
|
-
|
|
5
|
-
module ConceptQL
|
|
6
|
-
class Debugger
|
|
7
|
-
attr :statement, :db, :watch_ids
|
|
8
|
-
def initialize(statement, opts = {})
|
|
9
|
-
@statement = statement
|
|
10
|
-
@db = opts.fetch(:db, nil)
|
|
11
|
-
@tree = opts.fetch(:tree, Tree.new)
|
|
12
|
-
ConceptQL::Operators::Operator.send(:include, ConceptQL::Behaviors::Debuggable)
|
|
13
|
-
@watch_ids = opts.fetch(:watch_ids, [])
|
|
14
|
-
raise "Please specify one or more person_ids you'd like to debug" unless @watch_ids
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def capture_results(path)
|
|
18
|
-
raise "Please specify path for debug file" unless path
|
|
19
|
-
Dir.mktmpdir do |dir|
|
|
20
|
-
dir = Pathname.new(dir)
|
|
21
|
-
operators = tree.root(self)
|
|
22
|
-
operators.first.reset_operator_number
|
|
23
|
-
csv_files = operators.map.with_index do |last_operator, index|
|
|
24
|
-
last_operator.print_results(db, dir, watch_ids)
|
|
25
|
-
end.flatten
|
|
26
|
-
system("csv2xlsx #{path} #{csv_files.join(' ')}")
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
attr :yaml, :tree, :db
|
|
32
|
-
|
|
33
|
-
def build_graph(g)
|
|
34
|
-
tree.root(self).each.with_index do |last_operator, index|
|
|
35
|
-
last_operator.graph_it(g, db)
|
|
36
|
-
if dangler
|
|
37
|
-
blank_operator = g.add_nodes("_#{index}")
|
|
38
|
-
blank_operator[:shape] = 'none'
|
|
39
|
-
blank_operator[:height] = 0
|
|
40
|
-
blank_operator[:label] = ''
|
|
41
|
-
blank_operator[:fixedsize] = true
|
|
42
|
-
last_operator.link_to(g, blank_operator, db)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
require_relative 'graph'
|
|
2
|
-
require_relative 'tree'
|
|
3
|
-
require_relative 'graph_nodifier'
|
|
4
|
-
|
|
5
|
-
module ConceptQL
|
|
6
|
-
class FakeGrapher
|
|
7
|
-
attr :options
|
|
8
|
-
|
|
9
|
-
def initialize(options = {})
|
|
10
|
-
@options = {
|
|
11
|
-
dangler: true,
|
|
12
|
-
tree: ConceptQL::Tree.new(nodifier: ConceptQL::GraphNodifier.new)
|
|
13
|
-
}.merge(options)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def graph_it(statement, output_file)
|
|
17
|
-
ConceptQL::Graph.new(statement, options).graph_it(output_file)
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
data/lib/conceptql/graph.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require 'psych'
|
|
2
|
-
require 'graphviz'
|
|
3
|
-
require_relative 'tree'
|
|
4
|
-
require_relative 'operators/operator'
|
|
5
|
-
require_relative 'behaviors/dottable'
|
|
6
|
-
|
|
7
|
-
module ConceptQL
|
|
8
|
-
class Graph
|
|
9
|
-
attr :g, :file_path, :dangler, :title, :statement, :db, :suffix
|
|
10
|
-
def initialize(statement, opts = {})
|
|
11
|
-
@statement = statement
|
|
12
|
-
@db = opts.fetch(:db, nil)
|
|
13
|
-
@dangler = opts.fetch(:dangler, false)
|
|
14
|
-
@tree = opts.fetch(:tree, Tree.new)
|
|
15
|
-
@title = opts.fetch(:title, nil)
|
|
16
|
-
@suffix = opts.fetch(:suffix, 'pdf')
|
|
17
|
-
ConceptQL::Operators::Operator.send(:include, ConceptQL::Behaviors::Dottable)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def graph_it(file_path)
|
|
21
|
-
build_graph(g)
|
|
22
|
-
graph.output(suffix.to_sym => file_path + ".#{suffix}")
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def graph
|
|
26
|
-
@graph ||= begin
|
|
27
|
-
opts = { type: :digraph }
|
|
28
|
-
opts[:label] = title if title
|
|
29
|
-
GraphViz.new(:G, opts)
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
private
|
|
34
|
-
attr :yaml, :tree, :db
|
|
35
|
-
|
|
36
|
-
def build_graph(g)
|
|
37
|
-
tree.root(self).each.with_index do |last_operator, index|
|
|
38
|
-
last_operator.build_temp_tables(db)
|
|
39
|
-
last_operator.graph_it(g, db)
|
|
40
|
-
if dangler
|
|
41
|
-
blank_operator = g.add_nodes("_#{index}")
|
|
42
|
-
blank_operator[:shape] = 'none'
|
|
43
|
-
blank_operator[:height] = 0
|
|
44
|
-
blank_operator[:label] = ''
|
|
45
|
-
blank_operator[:fixedsize] = true
|
|
46
|
-
last_operator.link_to(g, blank_operator, db)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
require_relative 'behaviors/dottable'
|
|
2
|
-
require_relative 'operators/operator'
|
|
3
|
-
|
|
4
|
-
module ConceptQL
|
|
5
|
-
class GraphNodifier
|
|
6
|
-
class DotOperator < ConceptQL::Operators::Operator
|
|
7
|
-
include ConceptQL::Behaviors::Dottable
|
|
8
|
-
|
|
9
|
-
TYPES = {
|
|
10
|
-
# Conditions
|
|
11
|
-
condition: :condition_occurrence,
|
|
12
|
-
primary_diagnosis: :condition_occurrence,
|
|
13
|
-
icd9: :condition_occurrence,
|
|
14
|
-
icd10: :condition_occurrence,
|
|
15
|
-
condition_type: :condition_occurrence,
|
|
16
|
-
medcode: :condition_occurrence,
|
|
17
|
-
|
|
18
|
-
# Procedures
|
|
19
|
-
procedure: :procedure_occurrence,
|
|
20
|
-
cpt: :procedure_occurrence,
|
|
21
|
-
drg: :procedure_occurrence,
|
|
22
|
-
hcpcs: :procedure_occurrence,
|
|
23
|
-
icd9_procedure: :procedure_occurrence,
|
|
24
|
-
procedure_cost: :procedure_cost,
|
|
25
|
-
medcode_procedure: :procedure_occurrence,
|
|
26
|
-
|
|
27
|
-
# Visits
|
|
28
|
-
visit_occurrence: :visit_occurrence,
|
|
29
|
-
place_of_service: :visit_occurrence,
|
|
30
|
-
place_of_service_code: :visit_occurrence,
|
|
31
|
-
|
|
32
|
-
# Person
|
|
33
|
-
person: :person,
|
|
34
|
-
gender: :person,
|
|
35
|
-
race: :person,
|
|
36
|
-
|
|
37
|
-
# Payer
|
|
38
|
-
payer: :payer_plan_period,
|
|
39
|
-
|
|
40
|
-
# Death
|
|
41
|
-
death: :death,
|
|
42
|
-
|
|
43
|
-
# Observation
|
|
44
|
-
loinc: :observation,
|
|
45
|
-
from_seer_visits: :observation,
|
|
46
|
-
to_seer_visits: :observation,
|
|
47
|
-
|
|
48
|
-
# Drug
|
|
49
|
-
drug_exposure: :drug_exposure,
|
|
50
|
-
rxnorm: :drug_exposure,
|
|
51
|
-
drug_cost: :drug_cost,
|
|
52
|
-
drug_type_concept_id: :drug_exposure,
|
|
53
|
-
drug_type_concept: :drug_exposure,
|
|
54
|
-
prodcode: :drug_exposure,
|
|
55
|
-
|
|
56
|
-
# Date Operators
|
|
57
|
-
date_range: :date,
|
|
58
|
-
|
|
59
|
-
# Miscelaneous operators
|
|
60
|
-
concept: :misc,
|
|
61
|
-
vsac: :misc
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
attr :values, :name
|
|
65
|
-
def initialize(name, values)
|
|
66
|
-
@name = name.to_s
|
|
67
|
-
super(values)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def display_name
|
|
71
|
-
@__display_name ||= begin
|
|
72
|
-
output = @name.dup
|
|
73
|
-
output += ": #{arguments.join(', ')}" unless arguments.empty?
|
|
74
|
-
if output.length > 100
|
|
75
|
-
parts = output.split
|
|
76
|
-
output = parts.each_slice(output.length / parts.count).map do |subparts|
|
|
77
|
-
subparts.join(' ')
|
|
78
|
-
end.join ('\n')
|
|
79
|
-
end
|
|
80
|
-
output += "\n#{options.map{|k,v| "#{k}: #{v}"}.join("\n")}" unless options.nil? || options.empty?
|
|
81
|
-
output
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def types
|
|
86
|
-
types = [TYPES[name.to_sym] || upstreams.map(&:types)].flatten.uniq
|
|
87
|
-
types.empty? ? [:misc] : types
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
class BinaryOperatorOperator < DotOperator
|
|
92
|
-
def display_name
|
|
93
|
-
output = name
|
|
94
|
-
output += "\n#{displayable_options.map{|k,v| "#{k}: #{v}"}.join("\n")}"
|
|
95
|
-
output
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def displayable_options
|
|
99
|
-
options.select{ |k,v| ![:left, :right].include?(k) } || {}
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def left
|
|
103
|
-
options[:left]
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def right
|
|
107
|
-
options[:right]
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def graph_it(g, db)
|
|
111
|
-
left.graph_it(g, db)
|
|
112
|
-
right.graph_it(g, db)
|
|
113
|
-
cluster_name = "cluster_#{operator_name}"
|
|
114
|
-
me = g.send(cluster_name) do |sub|
|
|
115
|
-
sub[rank: 'same', label: display_name, color: 'black']
|
|
116
|
-
sub.send("#{cluster_name}_left").send('[]', shape: 'point', color: type_color(types))
|
|
117
|
-
sub.send("#{cluster_name}_right").send('[]', shape: 'point')
|
|
118
|
-
end
|
|
119
|
-
left.link_to(g, me.send("#{cluster_name}_left"))
|
|
120
|
-
right.link_to(g, me.send("#{cluster_name}_right"))
|
|
121
|
-
@__graph_operator = me.send("#{cluster_name}_left")
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def types
|
|
125
|
-
left.types
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def arguments
|
|
129
|
-
options.values
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
class LetOperator < DotOperator
|
|
134
|
-
def graph_it(g, db)
|
|
135
|
-
cluster_name = "cluster_#{operator_name}"
|
|
136
|
-
linkable = nil
|
|
137
|
-
g.send(cluster_name) do |sub|
|
|
138
|
-
linkable = upstreams.reverse.map do |upstream|
|
|
139
|
-
upstream.graph_it(sub, db)
|
|
140
|
-
end.first
|
|
141
|
-
sub[label: display_name, color: 'black']
|
|
142
|
-
end
|
|
143
|
-
@__graph_operator = linkable
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def types
|
|
147
|
-
upstreams.last.types
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
class DefineOperator < DotOperator
|
|
152
|
-
def shape
|
|
153
|
-
:cds
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
class RecallOperator < DotOperator
|
|
158
|
-
def shape
|
|
159
|
-
:cds
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
class VsacOperator < DotOperator
|
|
164
|
-
def initialize(name, values, types)
|
|
165
|
-
@types = types
|
|
166
|
-
super(name, values)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def types
|
|
170
|
-
[ @types ].flatten.compact.map(&:to_sym)
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
BINARY_OPERATOR_TYPES = %w(before after meets met_by started_by starts contains during overlaps overlapped_by finished_by finishes coincides except person_filter less_than less_than_or_equal equal not_equal greater_than greater_than_or_equal filter).map { |temp| [temp, "not_#{temp}"] }.flatten.map(&:to_sym)
|
|
175
|
-
|
|
176
|
-
def temp_tables
|
|
177
|
-
@temp_tables ||= {}
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def types
|
|
181
|
-
@types ||= {}
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def create(type, values, tree)
|
|
185
|
-
operator = if BINARY_OPERATOR_TYPES.include?(type)
|
|
186
|
-
BinaryOperatorOperator.new(type, values)
|
|
187
|
-
elsif type == :let
|
|
188
|
-
LetOperator.new(type, values)
|
|
189
|
-
elsif type == :define
|
|
190
|
-
DefineOperator.new(type, values)
|
|
191
|
-
elsif type == :recall
|
|
192
|
-
RecallOperator.new(type, values)
|
|
193
|
-
elsif type == :vsac
|
|
194
|
-
types = values.pop
|
|
195
|
-
VsacOperator.new(type, values, types)
|
|
196
|
-
else
|
|
197
|
-
DotOperator.new(type, values)
|
|
198
|
-
end
|
|
199
|
-
operator.tree = self
|
|
200
|
-
operator
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
data/lib/conceptql/logger.rb
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
require_relative 'pass_thru'
|
|
2
|
-
|
|
3
|
-
module ConceptQL
|
|
4
|
-
module Operators
|
|
5
|
-
class Complement < PassThru
|
|
6
|
-
desc 'Splits up the incoming result set by type and passes through all results for each type that are NOT in the current set.'
|
|
7
|
-
allows_one_upstream
|
|
8
|
-
category 'Set Logic'
|
|
9
|
-
|
|
10
|
-
def query(db)
|
|
11
|
-
upstream = upstreams.first
|
|
12
|
-
upstream.types.map do |type|
|
|
13
|
-
positive_query = db.from(upstream.evaluate(db))
|
|
14
|
-
.select(:criterion_id)
|
|
15
|
-
.exclude(:criterion_id => nil)
|
|
16
|
-
.where(:criterion_type => type.to_s)
|
|
17
|
-
query = db.from(make_table_name(type))
|
|
18
|
-
.exclude(make_type_id(type) => positive_query)
|
|
19
|
-
db.from(select_it(query, type))
|
|
20
|
-
end.inject do |union_query, q|
|
|
21
|
-
union_query.union(q, all: true)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
# This is an alternate, but equally accurate way to do complement.
|
|
27
|
-
# We'll need to benchmark which is faster.
|
|
28
|
-
def query2(db)
|
|
29
|
-
upstream = upstreams.first
|
|
30
|
-
froms = upstream.types.map do |type|
|
|
31
|
-
select_it(db.from(make_table_name(type)), type)
|
|
32
|
-
end
|
|
33
|
-
big_from = froms.inject { |union_query, q| union_query.union(q, all:true) }
|
|
34
|
-
db.from(big_from).except(upstream.evaluate(db))
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
require_relative 'operator'
|
|
2
|
-
require_relative '../query'
|
|
3
|
-
|
|
4
|
-
module ConceptQL
|
|
5
|
-
module Operators
|
|
6
|
-
class Concept < Operator
|
|
7
|
-
desc 'Given the UUID of another ConceptQL statement, returns the results of that statement.'
|
|
8
|
-
attr :cql_query
|
|
9
|
-
def query(db)
|
|
10
|
-
set_cql_query(db)
|
|
11
|
-
db.from(cql_query.query.from_self)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def upstreams
|
|
15
|
-
@upstreams ||= cql_query.operators
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def graph_prep(db)
|
|
19
|
-
set_cql_query(db)
|
|
20
|
-
puts statement.inspect
|
|
21
|
-
@arguments = [description(db)]
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def print_prep(db)
|
|
25
|
-
set_cql_query(db)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def ensure_temp_tables(db)
|
|
29
|
-
set_cql_query(db)
|
|
30
|
-
super
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def build_temp_tables(db)
|
|
34
|
-
set_cql_query(db)
|
|
35
|
-
super
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def set_cql_query(db)
|
|
41
|
-
@cql_query ||= begin
|
|
42
|
-
set_statement(db)
|
|
43
|
-
Query.new(db, statement)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def statement
|
|
48
|
-
raise "Statement is nil!" unless @statement
|
|
49
|
-
@statement
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def set_statement(db)
|
|
53
|
-
@statement ||= get_statement(db)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def get_statement(db)
|
|
57
|
-
concept = db[:concepts].where(concept_id: arguments.first).limit(1)
|
|
58
|
-
statement = concept.select_map(:statement).first.tap { |f| ConceptQL.logger.debug f.inspect }
|
|
59
|
-
statement = JSON.parse(statement) if statement.is_a?(String)
|
|
60
|
-
statement
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def description(db)
|
|
64
|
-
@description ||= db[:concepts].where(concept_id: arguments.first).select_map(:label).first
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
|