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.
Files changed (242) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +226 -117
  3. data/LICENSE +21 -0
  4. data/README.md +35 -83
  5. data/bin/conceptql +2 -1
  6. data/bin/conceptql_utils +6 -0
  7. data/config/multiple_vocabularies.csv +4 -0
  8. data/config/provenance.yml +489 -0
  9. data/config/race.yml +50 -0
  10. data/config/vocabularies.csv +87 -0
  11. data/lib/conceptql/behaviors/code_lister.rb +23 -0
  12. data/lib/conceptql/behaviors/drugish.rb +17 -0
  13. data/lib/conceptql/behaviors/labish.rb +19 -0
  14. data/lib/conceptql/behaviors/metadatable.rb +226 -73
  15. data/lib/conceptql/behaviors/provenanceable.rb +26 -0
  16. data/lib/conceptql/behaviors/single_event.rb +11 -0
  17. data/lib/conceptql/behaviors/timeless.rb +11 -0
  18. data/lib/conceptql/behaviors/utilizable.rb +206 -0
  19. data/lib/conceptql/behaviors/windowable.rb +27 -0
  20. data/lib/conceptql/cli.rb +117 -108
  21. data/lib/conceptql/columnizer.rb +75 -0
  22. data/lib/conceptql/data_model/base.rb +462 -0
  23. data/lib/conceptql/data_model/gdm.rb +155 -0
  24. data/lib/conceptql/data_model/gdm_wide.rb +42 -0
  25. data/lib/conceptql/data_model/omopv4_plus.rb +12 -0
  26. data/lib/conceptql/data_model.rb +30 -0
  27. data/lib/conceptql/database.rb +214 -0
  28. data/lib/conceptql/date_adjuster.rb +66 -18
  29. data/lib/conceptql/diagram.rb +243 -0
  30. data/lib/conceptql/lexicon/lexicon_gdm.rb +47 -0
  31. data/lib/conceptql/lexicon/lexicon_no_db.rb +49 -0
  32. data/lib/conceptql/lexicon/lexicon_ohdsi.rb +63 -0
  33. data/lib/conceptql/lexicon/lexicon_strategy.rb +116 -0
  34. data/lib/conceptql/lexicon.rb +111 -0
  35. data/lib/conceptql/nodifier.rb +65 -24
  36. data/lib/conceptql/operators/after.rb +34 -14
  37. data/lib/conceptql/operators/any_overlap.rb +8 -6
  38. data/lib/conceptql/operators/before.rb +34 -10
  39. data/lib/conceptql/operators/binary_operator_operator.rb +66 -23
  40. data/lib/conceptql/operators/casting_operator.rb +51 -36
  41. data/lib/conceptql/operators/co_reported.rb +111 -0
  42. data/lib/conceptql/operators/concurrent_within.rb +69 -0
  43. data/lib/conceptql/operators/contains.rb +12 -8
  44. data/lib/conceptql/operators/count.rb +17 -9
  45. data/lib/conceptql/operators/date_range.rb +48 -14
  46. data/lib/conceptql/operators/death.rb +14 -4
  47. data/lib/conceptql/operators/dedup.rb +31 -0
  48. data/lib/conceptql/operators/during.rb +7 -12
  49. data/lib/conceptql/operators/episode.rb +146 -0
  50. data/lib/conceptql/operators/equal.rb +9 -3
  51. data/lib/conceptql/operators/ethnicity.rb +49 -0
  52. data/lib/conceptql/operators/except.rb +19 -12
  53. data/lib/conceptql/operators/filter.rb +23 -8
  54. data/lib/conceptql/operators/first.rb +16 -3
  55. data/lib/conceptql/operators/from.rb +52 -4
  56. data/lib/conceptql/operators/gender.rb +34 -11
  57. data/lib/conceptql/operators/hospice.rb +19 -0
  58. data/lib/conceptql/operators/hospitalization.rb +19 -0
  59. data/lib/conceptql/operators/information_periods.rb +36 -0
  60. data/lib/conceptql/operators/invalid.rb +35 -0
  61. data/lib/conceptql/operators/last.rb +16 -3
  62. data/lib/conceptql/operators/match.rb +91 -0
  63. data/lib/conceptql/operators/multiple_vocabularies.rb +172 -0
  64. data/lib/conceptql/operators/numeric.rb +65 -23
  65. data/lib/conceptql/operators/numeric_filter.rb +68 -0
  66. data/lib/conceptql/operators/occurrence.rb +153 -32
  67. data/lib/conceptql/operators/one_in_two_out.rb +237 -38
  68. data/lib/conceptql/operators/operator.rb +624 -178
  69. data/lib/conceptql/operators/pass_thru.rb +17 -3
  70. data/lib/conceptql/operators/person.rb +18 -6
  71. data/lib/conceptql/operators/person_filter.rb +9 -3
  72. data/lib/conceptql/operators/place_of_service_filter.rb +43 -0
  73. data/lib/conceptql/operators/provenance.rb +55 -0
  74. data/lib/conceptql/operators/provider_filter.rb +62 -0
  75. data/lib/conceptql/operators/race.rb +55 -7
  76. data/lib/conceptql/operators/read.rb +168 -0
  77. data/lib/conceptql/operators/recall.rb +49 -14
  78. data/lib/conceptql/operators/snf.rb +19 -0
  79. data/lib/conceptql/operators/sum.rb +29 -12
  80. data/lib/conceptql/operators/temporal_operator.rb +108 -16
  81. data/lib/conceptql/operators/time_window.rb +20 -32
  82. data/lib/conceptql/operators/trim_date.rb +71 -0
  83. data/lib/conceptql/operators/trim_date_end.rb +28 -40
  84. data/lib/conceptql/operators/trim_date_start.rb +28 -41
  85. data/lib/conceptql/operators/union.rb +67 -6
  86. data/lib/conceptql/operators/vocabulary.rb +151 -0
  87. data/lib/conceptql/paths.rb +41 -0
  88. data/lib/conceptql/query.rb +191 -26
  89. data/lib/conceptql/query_modifiers/gdm/admission_date_query_modifier.rb +46 -0
  90. data/lib/conceptql/query_modifiers/gdm/drug_query_modifier.rb +54 -0
  91. data/lib/conceptql/query_modifiers/gdm/lab_query_modifier.rb +57 -0
  92. data/lib/conceptql/query_modifiers/gdm/pos_query_modifier.rb +46 -0
  93. data/lib/conceptql/query_modifiers/gdm/provenance_query_modifier.rb +45 -0
  94. data/lib/conceptql/query_modifiers/gdm/provider_query_modifier.rb +53 -0
  95. data/lib/conceptql/query_modifiers/gdm_wide/admission_date_query_modifier.rb +42 -0
  96. data/lib/conceptql/query_modifiers/gdm_wide/drug_query_modifier.rb +52 -0
  97. data/lib/conceptql/query_modifiers/gdm_wide/lab_query_modifier.rb +55 -0
  98. data/lib/conceptql/query_modifiers/gdm_wide/pos_query_modifier.rb +37 -0
  99. data/lib/conceptql/query_modifiers/gdm_wide/provenance_query_modifier.rb +38 -0
  100. data/lib/conceptql/query_modifiers/omopv4_plus/admission_date_query_modifier.rb +45 -0
  101. data/lib/conceptql/query_modifiers/omopv4_plus/drug_query_modifier.rb +80 -0
  102. data/lib/conceptql/query_modifiers/omopv4_plus/pos_query_modifier.rb +47 -0
  103. data/lib/conceptql/query_modifiers/omopv4_plus/provenance_query_modifier.rb +45 -0
  104. data/lib/conceptql/query_modifiers/omopv4_plus/provider_query_modifier.rb +26 -0
  105. data/lib/conceptql/query_modifiers/query_modifier.rb +20 -0
  106. data/lib/conceptql/rdbms/duckdb.rb +25 -0
  107. data/lib/conceptql/rdbms/generic.rb +120 -0
  108. data/lib/conceptql/rdbms/postgres.rb +51 -0
  109. data/lib/conceptql/rdbms/spark.rb +22 -0
  110. data/lib/conceptql/rdbms.rb +22 -0
  111. data/lib/conceptql/scope.rb +481 -31
  112. data/lib/conceptql/sql_formatters/formatter.rb +25 -0
  113. data/lib/conceptql/sql_formatters.rb +22 -0
  114. data/lib/conceptql/utils.rb +113 -0
  115. data/lib/conceptql/utils_cli.rb +17 -0
  116. data/lib/conceptql/version.rb +3 -1
  117. data/lib/conceptql/visitors/metadata_extractor.rb +54 -0
  118. data/lib/conceptql/vocabularies/behaviors/costish.rb +24 -0
  119. data/lib/conceptql/vocabularies/behaviors/gdmish.rb +19 -0
  120. data/lib/conceptql/vocabularies/behaviors/omopish.rb +32 -0
  121. data/lib/conceptql/vocabularies/dynamic_vocabularies.rb +63 -0
  122. data/lib/conceptql/vocabularies/entry.rb +138 -0
  123. data/lib/conceptql/vocabularies/vocabulary_class_factory.rb +85 -0
  124. data/lib/conceptql/window/base.rb +26 -0
  125. data/lib/conceptql/window/date_range.rb +25 -0
  126. data/lib/conceptql/window/table.rb +116 -0
  127. data/lib/conceptql/window.rb +72 -0
  128. data/lib/conceptql.rb +65 -2
  129. data/lib/sequel/extensions/pg_ctas_explain.rb +22 -0
  130. data/lib/sequel/extensions/pg_vacuum_table.rb +23 -0
  131. data/schemas/gdm.yml +882 -0
  132. data/schemas/gdm_wide.yml +757 -0
  133. data/schemas/ohdsi_vocabs.yml +143 -0
  134. data/schemas/omopv4_plus.yml +729 -0
  135. data/schemas/omopv4_plus_more_ignorables.tsv +13 -0
  136. metadata +267 -207
  137. data/.gitignore +0 -23
  138. data/Gemfile +0 -4
  139. data/Guardfile +0 -56
  140. data/LICENSE.txt +0 -22
  141. data/Rakefile +0 -1
  142. data/conceptql.gemspec +0 -32
  143. data/doc/ConceptQL Specification (alpha).pdf +0 -0
  144. data/doc/diagram_0.png +0 -0
  145. data/doc/implementation_notes.md +0 -39
  146. data/doc/spec.md +0 -1344
  147. data/lib/conceptql/behaviors/debuggable.rb +0 -70
  148. data/lib/conceptql/behaviors/dottable.rb +0 -103
  149. data/lib/conceptql/behaviors/preppable.rb +0 -20
  150. data/lib/conceptql/converter.rb +0 -65
  151. data/lib/conceptql/debugger.rb +0 -48
  152. data/lib/conceptql/fake_grapher.rb +0 -20
  153. data/lib/conceptql/graph.rb +0 -52
  154. data/lib/conceptql/graph_nodifier.rb +0 -203
  155. data/lib/conceptql/logger.rb +0 -10
  156. data/lib/conceptql/operators/complement.rb +0 -38
  157. data/lib/conceptql/operators/concept.rb +0 -70
  158. data/lib/conceptql/operators/condition_type.rb +0 -71
  159. data/lib/conceptql/operators/cpt.rb +0 -25
  160. data/lib/conceptql/operators/drug_type_concept.rb +0 -21
  161. data/lib/conceptql/operators/from_seer_visits.rb +0 -23
  162. data/lib/conceptql/operators/hcpcs.rb +0 -25
  163. data/lib/conceptql/operators/icd10.rb +0 -28
  164. data/lib/conceptql/operators/icd9.rb +0 -28
  165. data/lib/conceptql/operators/icd9_procedure.rb +0 -25
  166. data/lib/conceptql/operators/intersect.rb +0 -34
  167. data/lib/conceptql/operators/loinc.rb +0 -25
  168. data/lib/conceptql/operators/medcode.rb +0 -28
  169. data/lib/conceptql/operators/medcode_procedure.rb +0 -27
  170. data/lib/conceptql/operators/ndc.rb +0 -29
  171. data/lib/conceptql/operators/observation_by_enttype.rb +0 -29
  172. data/lib/conceptql/operators/observation_period.rb +0 -30
  173. data/lib/conceptql/operators/overlapped_by.rb +0 -23
  174. data/lib/conceptql/operators/overlaps.rb +0 -19
  175. data/lib/conceptql/operators/place_of_service_code.rb +0 -24
  176. data/lib/conceptql/operators/procedure_occurrence.rb +0 -25
  177. data/lib/conceptql/operators/prodcode.rb +0 -29
  178. data/lib/conceptql/operators/rxnorm.rb +0 -24
  179. data/lib/conceptql/operators/snomed.rb +0 -24
  180. data/lib/conceptql/operators/snomed_condition.rb +0 -26
  181. data/lib/conceptql/operators/source_vocabulary_operator.rb +0 -58
  182. data/lib/conceptql/operators/standard_vocabulary_operator.rb +0 -45
  183. data/lib/conceptql/operators/started_by.rb +0 -22
  184. data/lib/conceptql/operators/to_seer_visits.rb +0 -24
  185. data/lib/conceptql/operators/visit.rb +0 -15
  186. data/lib/conceptql/operators/visit_occurrence.rb +0 -30
  187. data/lib/conceptql/tree.rb +0 -53
  188. data/lib/conceptql/utils/temp_table.rb +0 -72
  189. data/spec/conceptql/behaviors/dottable_spec.rb +0 -99
  190. data/spec/conceptql/converter_spec.rb +0 -51
  191. data/spec/conceptql/date_adjuster_spec.rb +0 -68
  192. data/spec/conceptql/operators/after_spec.rb +0 -16
  193. data/spec/conceptql/operators/before_spec.rb +0 -16
  194. data/spec/conceptql/operators/casting_operator_spec.rb +0 -68
  195. data/spec/conceptql/operators/complement_spec.rb +0 -15
  196. data/spec/conceptql/operators/concept_spec.rb +0 -40
  197. data/spec/conceptql/operators/condition_type_spec.rb +0 -128
  198. data/spec/conceptql/operators/contains_spec.rb +0 -19
  199. data/spec/conceptql/operators/cpt_spec.rb +0 -29
  200. data/spec/conceptql/operators/date_range_spec.rb +0 -33
  201. data/spec/conceptql/operators/death_spec.rb +0 -10
  202. data/spec/conceptql/operators/during_spec.rb +0 -30
  203. data/spec/conceptql/operators/except_spec.rb +0 -15
  204. data/spec/conceptql/operators/first_spec.rb +0 -35
  205. data/spec/conceptql/operators/from_spec.rb +0 -13
  206. data/spec/conceptql/operators/gender_spec.rb +0 -27
  207. data/spec/conceptql/operators/hcpcs_spec.rb +0 -29
  208. data/spec/conceptql/operators/icd10_spec.rb +0 -34
  209. data/spec/conceptql/operators/icd9_procedure_spec.rb +0 -29
  210. data/spec/conceptql/operators/icd9_spec.rb +0 -34
  211. data/spec/conceptql/operators/intersect_spec.rb +0 -28
  212. data/spec/conceptql/operators/last_spec.rb +0 -36
  213. data/spec/conceptql/operators/loinc_spec.rb +0 -29
  214. data/spec/conceptql/operators/medcode_procedure_spec.rb +0 -34
  215. data/spec/conceptql/operators/medcode_spec.rb +0 -34
  216. data/spec/conceptql/operators/observation_period_spec.rb +0 -10
  217. data/spec/conceptql/operators/occurrence_spec.rb +0 -87
  218. data/spec/conceptql/operators/overlapped_by_spec.rb +0 -32
  219. data/spec/conceptql/operators/overlaps_spec.rb +0 -21
  220. data/spec/conceptql/operators/person_filter_spec.rb +0 -15
  221. data/spec/conceptql/operators/person_spec.rb +0 -10
  222. data/spec/conceptql/operators/place_of_service_code_spec.rb +0 -24
  223. data/spec/conceptql/operators/procedure_occurrence_spec.rb +0 -10
  224. data/spec/conceptql/operators/prodcode_spec.rb +0 -35
  225. data/spec/conceptql/operators/query_double.rb +0 -20
  226. data/spec/conceptql/operators/query_double_spec.rb +0 -7
  227. data/spec/conceptql/operators/race_spec.rb +0 -21
  228. data/spec/conceptql/operators/rxnorm_spec.rb +0 -29
  229. data/spec/conceptql/operators/snomed_spec.rb +0 -29
  230. data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +0 -35
  231. data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +0 -35
  232. data/spec/conceptql/operators/started_by_spec.rb +0 -22
  233. data/spec/conceptql/operators/temporal_operator_spec.rb +0 -51
  234. data/spec/conceptql/operators/time_window_spec.rb +0 -77
  235. data/spec/conceptql/operators/union_spec.rb +0 -21
  236. data/spec/conceptql/operators/visit_occurrence_spec.rb +0 -10
  237. data/spec/conceptql/query_spec.rb +0 -22
  238. data/spec/conceptql/tree_spec.rb +0 -50
  239. data/spec/doubles/stream_for_casting_double.rb +0 -9
  240. data/spec/doubles/stream_for_occurrence_double.rb +0 -25
  241. data/spec/doubles/stream_for_temporal_double.rb +0 -6
  242. 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
-
@@ -1,20 +0,0 @@
1
- module ConceptQL
2
- module Behaviors
3
- module Preppable
4
- attr_accessor :prep_proc
5
- def prep
6
- prep_proc.call if prep_proc
7
- end
8
-
9
- def all(*args)
10
- prep
11
- super
12
- end
13
-
14
- def count(*args)
15
- prep
16
- super
17
- end
18
- end
19
- end
20
- end
@@ -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
@@ -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
@@ -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
@@ -1,10 +0,0 @@
1
- require 'logger'
2
- module ConceptQL
3
- def self.logger
4
- @logger ||= begin
5
- l = Logger.new('/tmp/cql.log')
6
- l.level = Logger::DEBUG
7
- l
8
- end
9
- end
10
- end
@@ -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
-