conceptql 0.6.0 → 0.7.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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +176 -0
  3. data/README.md +4 -2
  4. data/assets/diagram/diagram.css +331 -0
  5. data/assets/diagram/fonts/OFL.txt +93 -0
  6. data/assets/diagram/fonts/Roboto-400.ttf +0 -0
  7. data/assets/diagram/fonts/Roboto-700.ttf +0 -0
  8. data/assets/diagram/fonts/Roboto-Italic-400.ttf +0 -0
  9. data/assets/diagram/fonts/Roboto-Italic-Latin.woff2 +0 -0
  10. data/assets/diagram/fonts/Roboto-Normal-Latin.woff2 +0 -0
  11. data/assets/diagram/operators.svg +224 -0
  12. data/config/vocabularies.csv +85 -85
  13. data/docs/spec/README.md +2624 -0
  14. data/docs/spec/examples/after-operator.json +562 -0
  15. data/docs/spec/examples/any-overlap-operator.json +106 -0
  16. data/docs/spec/examples/before-operator.json +437 -0
  17. data/docs/spec/examples/co-reported-operator.json +168 -0
  18. data/docs/spec/examples/contains-operator.json +97 -0
  19. data/docs/spec/examples/date-range-operator.json +275 -0
  20. data/docs/spec/examples/death-operator.json +103 -0
  21. data/docs/spec/examples/during-operator.json +178 -0
  22. data/docs/spec/examples/episode-operator.json +80 -0
  23. data/docs/spec/examples/equal-operator.json +79 -0
  24. data/docs/spec/examples/ethnicity-operator.json +86 -0
  25. data/docs/spec/examples/except-operator.json +536 -0
  26. data/docs/spec/examples/filter-operator.json +218 -0
  27. data/docs/spec/examples/first-operator.json +148 -0
  28. data/docs/spec/examples/gender-operator.json +257 -0
  29. data/docs/spec/examples/hospice-operator.json +40 -0
  30. data/docs/spec/examples/hospitalization-operator.json +131 -0
  31. data/docs/spec/examples/information-periods-operator.json +131 -0
  32. data/docs/spec/examples/last-operator.json +148 -0
  33. data/docs/spec/examples/match-operator.json +186 -0
  34. data/docs/spec/examples/nth-occurrence-operator.json +300 -0
  35. data/docs/spec/examples/numeric-filter-operator.json +77 -0
  36. data/docs/spec/examples/one-in-two-out-operator.json +158 -0
  37. data/docs/spec/examples/person-filter-operator.json +919 -0
  38. data/docs/spec/examples/person-operator.json +274 -0
  39. data/docs/spec/examples/place-of-service-filter-operator.json +57 -0
  40. data/docs/spec/examples/provenance-operator.json +148 -0
  41. data/docs/spec/examples/provider-filter-operator.json +77 -0
  42. data/docs/spec/examples/race-operator.json +131 -0
  43. data/docs/spec/examples/recall-operator.json +289 -0
  44. data/docs/spec/examples/snf-operator.json +40 -0
  45. data/docs/spec/examples/time-window-operator.json +736 -0
  46. data/docs/spec/examples/trim-date-end-operator.json +201 -0
  47. data/docs/spec/examples/trim-date-start-operator.json +201 -0
  48. data/docs/spec/examples/union-operator.json +547 -0
  49. data/docs/spec/examples/vocabulary-operator.json +232 -0
  50. data/lib/conceptql/behaviors/metadatable.rb +68 -2
  51. data/lib/conceptql/behaviors/provenanceable.rb +4 -1
  52. data/lib/conceptql/behaviors/utilizable.rb +3 -0
  53. data/lib/conceptql/code_case_mismatch_error.rb +50 -0
  54. data/lib/conceptql/data_model/gdm.rb +23 -2
  55. data/lib/conceptql/diagram_renderer/app.rb +59 -0
  56. data/lib/conceptql/diagram_renderer/configuration.rb +87 -0
  57. data/lib/conceptql/diagram_renderer/diagram_data.rb +80 -0
  58. data/lib/conceptql/diagram_renderer/drawing.rb +255 -0
  59. data/lib/conceptql/diagram_renderer/geometry.rb +380 -0
  60. data/lib/conceptql/diagram_renderer/input_error.rb +11 -0
  61. data/lib/conceptql/diagram_renderer/js_format.rb +112 -0
  62. data/lib/conceptql/diagram_renderer/resvg.rb +120 -0
  63. data/lib/conceptql/diagram_renderer/sprite.rb +73 -0
  64. data/lib/conceptql/diagram_renderer/static.rb +70 -0
  65. data/lib/conceptql/diagram_renderer/svg.rb +73 -0
  66. data/lib/conceptql/diagram_renderer/tree_layout.rb +287 -0
  67. data/lib/conceptql/diagram_renderer.rb +82 -0
  68. data/lib/conceptql/lexicon/lexicon_strategy.rb +16 -0
  69. data/lib/conceptql/lexicon.rb +63 -11
  70. data/lib/conceptql/nodifier.rb +5 -3
  71. data/lib/conceptql/operators/after.rb +15 -1
  72. data/lib/conceptql/operators/any_overlap.rb +6 -1
  73. data/lib/conceptql/operators/before.rb +11 -1
  74. data/lib/conceptql/operators/binary_operator_operator.rb +12 -2
  75. data/lib/conceptql/operators/co_reported.rb +9 -4
  76. data/lib/conceptql/operators/contains.rb +6 -1
  77. data/lib/conceptql/operators/count.rb +2 -0
  78. data/lib/conceptql/operators/date_range.rb +15 -3
  79. data/lib/conceptql/operators/death.rb +5 -1
  80. data/lib/conceptql/operators/dedup.rb +2 -0
  81. data/lib/conceptql/operators/during.rb +6 -1
  82. data/lib/conceptql/operators/episode.rb +13 -2
  83. data/lib/conceptql/operators/equal.rb +11 -1
  84. data/lib/conceptql/operators/ethnicity.rb +19 -7
  85. data/lib/conceptql/operators/except.rb +10 -1
  86. data/lib/conceptql/operators/filter.rb +6 -1
  87. data/lib/conceptql/operators/first.rb +19 -9
  88. data/lib/conceptql/operators/from.rb +3 -0
  89. data/lib/conceptql/operators/gender.rb +10 -2
  90. data/lib/conceptql/operators/hospice.rb +7 -1
  91. data/lib/conceptql/operators/hospitalization.rb +6 -1
  92. data/lib/conceptql/operators/information_periods.rb +26 -7
  93. data/lib/conceptql/operators/invalid.rb +4 -0
  94. data/lib/conceptql/operators/last.rb +19 -9
  95. data/lib/conceptql/operators/match.rb +6 -1
  96. data/lib/conceptql/operators/multiple_vocabularies.rb +17 -3
  97. data/lib/conceptql/operators/numeric.rb +4 -0
  98. data/lib/conceptql/operators/numeric_filter.rb +13 -3
  99. data/lib/conceptql/operators/occurrence.rb +33 -12
  100. data/lib/conceptql/operators/one_in_two_out.rb +22 -5
  101. data/lib/conceptql/operators/operator.rb +8 -4
  102. data/lib/conceptql/operators/person.rb +5 -1
  103. data/lib/conceptql/operators/person_filter.rb +14 -1
  104. data/lib/conceptql/operators/place_of_service_filter.rb +14 -3
  105. data/lib/conceptql/operators/provenance.rb +17 -8
  106. data/lib/conceptql/operators/provider_filter.rb +18 -6
  107. data/lib/conceptql/operators/race.rb +14 -9
  108. data/lib/conceptql/operators/read.rb +11 -1
  109. data/lib/conceptql/operators/recall.rb +34 -2
  110. data/lib/conceptql/operators/snf.rb +7 -1
  111. data/lib/conceptql/operators/sum.rb +4 -0
  112. data/lib/conceptql/operators/temporal_operator.rb +4 -2
  113. data/lib/conceptql/operators/time_window.rb +27 -4
  114. data/lib/conceptql/operators/trim_date.rb +6 -14
  115. data/lib/conceptql/operators/trim_date_end.rb +9 -3
  116. data/lib/conceptql/operators/trim_date_start.rb +9 -3
  117. data/lib/conceptql/operators/union.rb +13 -1
  118. data/lib/conceptql/operators/vocabulary.rb +80 -6
  119. data/lib/conceptql/paths.rb +9 -1
  120. data/lib/conceptql/version.rb +1 -1
  121. data/lib/conceptql/vocabularies/drg_systems.rb +3 -2
  122. data/lib/conceptql/vocabularies/entry.rb +14 -11
  123. data/lib/conceptql/vocabularies/vocabulary_class_factory.rb +2 -1
  124. data/lib/conceptql.rb +3 -0
  125. metadata +75 -2
  126. data/doc/spec.md +0 -2091
@@ -5,16 +5,54 @@ require_relative "operator"
5
5
  module ConceptQL
6
6
  module Operators
7
7
  class Vocabulary < Operator
8
+ # The vocabulary operators share one reference section (spec_id
9
+ # vocabulary-operator): each generated vocabulary operator, read and
10
+ # the multiple vocabulary operators. So the section's texts are written
11
+ # on this class: `returns`, the meaning: of the codes argument, and each
12
+ # `example`. An operator of the section extends this module and serves
13
+ # the returns text, and only the examples whose statement starts with
14
+ # its own name, so no operator shows an example of another one.
15
+ module SharedDocumentation
16
+ def get_returns
17
+ super || Vocabulary.returns
18
+ end
19
+
20
+ def examples_for(name)
21
+ Vocabulary.examples.select { |example| example[:statement].first.to_s == name }
22
+ end
23
+ end
24
+
25
+ extend SharedDocumentation
26
+
8
27
  include ConceptQL::Behaviors::Windowable
9
28
  include ConceptQL::Behaviors::CodeLister
10
29
 
11
30
  category "Select by Clinical Codes"
12
31
  basic_type :selection
13
- desc "Selects records based on the given vocabulary."
32
+ desc "Selects the records whose code is one of the given codes in a vocabulary, such as ICD-9-CM diagnoses or CPT procedures. " \
33
+ "Each vocabulary has its own operator, and a few operators search several vocabularies at once."
14
34
  validate_no_upstreams
15
35
  validate_at_least_one_argument
16
36
  validate_codes_match
17
37
 
38
+ # VocabularyClassFactory gives each vocabulary operator a copy of this
39
+ # argument, with the label "<preferred name> Codes"
40
+ argument :codes, type: :codelist,
41
+ meaning: "One or more codes of the vocabulary. Write each code as the vocabulary writes it, " \
42
+ "including any dots: 250.01, not 25001. A code matches exactly, including case, " \
43
+ "and it does not select its child codes. A code alone of * selects every record " \
44
+ "of the vocabulary, and there is no other wildcard. A code that does not have the " \
45
+ "vocabulary's format matches nothing and gives a warning."
46
+
47
+ returns "Every record whose code is one of the given codes in the operator's vocabulary. " \
48
+ "The type of the records depends on the vocabulary, for example condition_occurrence for icd9cm " \
49
+ "and procedure_occurrence for cpt4. An operator does not follow mappings to other vocabularies."
50
+ example "All records with the ICD-9-CM diagnosis code 412 (old myocardial infarction)", [ "icd9cm", "412" ]
51
+ example "All MS-DRG 205 records: other respiratory system diagnoses with a major complication or comorbidity",
52
+ [ "ms_drg", "205" ]
53
+ # The test data has no DRG record before 2007-10-01
54
+ example "All CMS-DRG 205 records (a liver disorder)", [ "cms_drg", "205" ], help: false
55
+
18
56
  def source_table
19
57
  domain_map(op_name)
20
58
  end
@@ -31,25 +69,61 @@ module ConceptQL
31
69
  vocab_entry.predominant_domains.map(&:to_sym)
32
70
  end
33
71
 
72
+ # Production ETL data stores CPT-4 and HCPCS codes only under the merged
73
+ # vocabulary CPT4_HCPCS. cpt and hcpcs read only their own vocabulary,
74
+ # so they select no rows there (known issue conceptql-rpy3). Each key is
75
+ # a vocabulary whose codes can be stored under the merged vocabulary,
76
+ # and each value names that vocabulary and the operator that reads it.
77
+ MERGED_VOCABULARIES = {
78
+ "CPT4" => { vocabulary_id: "CPT4_HCPCS", operator: "cpt_or_hcpcs" },
79
+ "HCPCS" => { vocabulary_id: "CPT4_HCPCS", operator: "cpt_or_hcpcs" }
80
+ }.freeze
81
+ NO_RECORDS_IN_DATA = "the data has no records of this vocabulary"
82
+
83
+ # MultipleVocabularies passes skip_merged_vocabulary_check to its
84
+ # vocabulary operators. It reads the merged vocabulary itself, and it
85
+ # would drop this warning anyway (see #warn_about_merged_vocabulary).
34
86
  def additional_validation(db, opts = {})
35
- return unless add_warnings?(db, opts) && !select_all?
87
+ return unless add_warnings?(db, opts)
88
+
89
+ warn_about_merged_vocabulary(db) unless opts[:skip_merged_vocabulary_check]
90
+ return if select_all?
36
91
 
37
92
  args = arguments.dup
38
93
  args -= bad_arguments
39
94
 
40
- missing_args = args - dm.known_codes(db, vocabulary_id, args)
95
+ # A statement warns about a code in another case than the stored one,
96
+ # so its lookups do not raise CodeCaseMismatchError (bead conceptql-rz8s).
97
+ missing_args = args - dm.known_codes(db, vocabulary_id, args, check_case: false)
41
98
  add_warning(UNKNOWN_CODE, *missing_args) unless missing_args.empty?
42
99
 
43
100
  warn_about_reused_codes(db, args - missing_args)
44
101
  end
45
102
 
103
+ # Warns when the data has no record of this vocabulary but has records
104
+ # of the merged vocabulary that holds its codes, and the Database's
105
+ # lexicon carries that merged vocabulary (bead conceptql-k5ho). The
106
+ # warning names the operator to use instead. The test fixture keeps
107
+ # CPT4 and HCPCS rows, so it never shows this warning.
108
+ def warn_about_merged_vocabulary(db)
109
+ merged = MERGED_VOCABULARIES[vocabulary_id]
110
+ return unless merged && nodifier.operators.key?(merged[:vocabulary_id].downcase)
111
+
112
+ table = db[criterion_table]
113
+ return unless table.where(vocabulary_condition).empty?
114
+ return if table.where(vocabulary_condition.transform_values { merged[:vocabulary_id] }).empty?
115
+
116
+ add_warning(NO_RECORDS_IN_DATA,
117
+ "the data stores #{vocabulary_id} codes as #{merged[:vocabulary_id]}, so use #{merged[:operator]}")
118
+ end
119
+
46
120
  # A code that the vocabulary reused for a new meaning selects records of
47
121
  # both meanings: DRG 410 selects chemotherapy stays before 2007-10-01 and
48
122
  # biliary tract procedures after it (conceptql-ttk). Each item names the
49
123
  # code and all of its names, so the user sees the problem without a
50
124
  # vocabulary lookup.
51
125
  def warn_about_reused_codes(db, codes)
52
- meanings = dm.code_meanings(db, vocabulary_id, codes)
126
+ meanings = dm.code_meanings(db, vocabulary_id, codes, check_case: false)
53
127
  reused = codes.filter_map do |code|
54
128
  names = meanings[code.downcase]
55
129
  "#{code}: #{names.join(' | ')}" if names
@@ -60,7 +134,7 @@ module ConceptQL
60
134
  def describe_codes(db, codes)
61
135
  return [ [ "*", "ALL CODES" ] ] if select_all?
62
136
 
63
- found_codes = dm.concepts_to_codes(db, vocabulary_id, codes)
137
+ found_codes = dm.concepts_to_codes(db, vocabulary_id, codes, check_case: false)
64
138
 
65
139
  found_codes + (codes - found_codes.map(&:first)).zip([])
66
140
  end
@@ -112,7 +186,7 @@ module ConceptQL
112
186
  wheres = vocabulary_condition
113
187
 
114
188
  unless select_all?
115
- concept_ids = dm.concept_ids(db, vocabulary_id, arguments)
189
+ concept_ids = dm.concept_ids(db, vocabulary_id, arguments, check_case: false)
116
190
 
117
191
  wheres = wheres.merge({ clinical_code_concept_id: concept_ids })
118
192
  end
@@ -51,7 +51,15 @@ module ConceptQL
51
51
  # The ConceptQL specification, shipped in the gem for applications that
52
52
  # serve it to readers (the Jigsaw diagram editor serves it over MCP).
53
53
  def spec_path
54
- root / "doc" / "spec.md"
54
+ root / "docs" / "spec" / "README.md"
55
+ end
56
+
57
+ # The directory of the spec's example files, one <spec_id>.json for each
58
+ # published spec_id: the title, statement, help flag, result columns and
59
+ # rows, and diagram tree (conceptql-diagram/v1) of each example. An
60
+ # application reads the file of the operator it shows.
61
+ def spec_examples_path
62
+ root / "docs" / "spec" / "examples"
55
63
  end
56
64
  end
57
65
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConceptQL
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -76,7 +76,7 @@ module ConceptQL
76
76
  omopv5_vocabulary_id: VOCABULARY_ID,
77
77
  preferred_name: system.name,
78
78
  vocabulary_short_name: system.name,
79
- vocabulary_long_name: system.long_name))
79
+ vocabulary_full_name: system.long_name))
80
80
  end
81
81
  end
82
82
  end
@@ -95,7 +95,8 @@ module ConceptQL
95
95
  def describe_codes(db, codes)
96
96
  return super if select_all?
97
97
 
98
- in_system = dm.concepts_to_codes_in_class(db, vocabulary_id, drg_system.concept_class_id, codes)
98
+ in_system = dm.concepts_to_codes_in_class(db, vocabulary_id, drg_system.concept_class_id, codes,
99
+ check_case: false)
99
100
  return super if in_system.blank?
100
101
 
101
102
  named = in_system.map { |code, _| code.downcase }
@@ -13,7 +13,7 @@ module ConceptQL
13
13
  omopv5_vocabulary_id
14
14
  domain
15
15
  vocabulary_short_name
16
- vocabulary_long_name
16
+ vocabulary_full_name
17
17
  ].freeze
18
18
 
19
19
  METHODS.each do |meth|
@@ -28,8 +28,14 @@ module ConceptQL
28
28
  predominant_domains
29
29
  ]
30
30
 
31
+ # A blank domain is no domain (bead conceptql-7azx). The GDM vocabulary
32
+ # table gives a vocabulary without a domain the domain '', and that
33
+ # became the criterion_domain of its operators. Without the key, the
34
+ # vocabulary selects condition_occurrence records (predominant_domains),
35
+ # and a merge keeps the other entry's domain.
31
36
  def initialize(hash)
32
37
  @hash = hash
38
+ @hash.delete(:domain) if @hash[:domain].blank?
33
39
  @hash[:omopv5_vocabulary_id] ||= @hash[:id]
34
40
  @hash[:aliases_arr] ||= []
35
41
  @hash[:aliases_arr] |= (@hash[:aliases] || "").split(";")
@@ -63,12 +69,17 @@ module ConceptQL
63
69
  Formats.pattern(omopv5_id)
64
70
  end
65
71
 
72
+ # A vocabulary without a short name has none. It does not fall back to
73
+ # the long name: the operator's preferred_name falls back to the
74
+ # vocabulary ID (Operators::Vocabulary#preferred_name).
66
75
  def short_name
67
- vocabulary_short_name || vocabulary_long_name
76
+ vocabulary_short_name
68
77
  end
69
78
 
79
+ # The column vocabulary_full_name of config/vocabularies.csv and of both
80
+ # lexicons (bead conceptql-txmo)
70
81
  def long_name
71
- vocabulary_long_name || vocabulary_short_name
82
+ vocabulary_full_name || vocabulary_short_name
72
83
  end
73
84
 
74
85
  # A preferred_name in the hash wins: ms_drg and cms_drg select vocabulary
@@ -102,10 +113,6 @@ module ConceptQL
102
113
  hash[:domain].present?
103
114
  end
104
115
 
105
- def hidden?
106
- hash[:hidden].present?
107
- end
108
-
109
116
  def is_labish?
110
117
  hash[:domain] =~ /observation|measurement/i
111
118
  end
@@ -114,10 +121,6 @@ module ConceptQL
114
121
  hash[:domain] =~ /drug_exposure/i
115
122
  end
116
123
 
117
- def visible?
118
- !hidden?
119
- end
120
-
121
124
  def omopv5_id
122
125
  omopv5_vocabulary_id || id
123
126
  end
@@ -38,7 +38,8 @@ module ConceptQL
38
38
  end
39
39
 
40
40
  preferred_name entry.preferred_name
41
- argument :codes, type: :codelist
41
+ # The label is "<preferred name> Codes" (Metadatable#auto_label)
42
+ argument :codes, ConceptQL::Operators::Vocabulary.argument_options(:codes).except(:label)
42
43
  aliases entry.aliases
43
44
  predominant_domains(*entry.predominant_domains)
44
45
  short_name entry.short_name
data/lib/conceptql.rb CHANGED
@@ -30,6 +30,9 @@ end
30
30
  module ConceptQL
31
31
  DEFAULT_DATA_MODEL = :gdm
32
32
 
33
+ # The diagram renderer (docs/diagram_renderer.md) loads on first use.
34
+ autoload :DiagramRenderer, "conceptql/diagram_renderer"
35
+
33
36
  def self.avoid_ctes?
34
37
  ENV["CONCEPTQL_AVOID_CTES"] == "true"
35
38
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conceptql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Duryea
@@ -183,6 +183,20 @@ dependencies:
183
183
  - - "~>"
184
184
  - !ruby/object:Gem::Version
185
185
  version: '5.0'
186
+ - !ruby/object:Gem::Dependency
187
+ name: nokogiri
188
+ requirement: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: '1.19'
193
+ type: :development
194
+ prerelease: false
195
+ version_requirements: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '1.19'
186
200
  - !ruby/object:Gem::Dependency
187
201
  name: pry-byebug
188
202
  requirement: !ruby/object:Gem::Requirement
@@ -322,6 +336,14 @@ files:
322
336
  - CHANGELOG.md
323
337
  - LICENSE
324
338
  - README.md
339
+ - assets/diagram/diagram.css
340
+ - assets/diagram/fonts/OFL.txt
341
+ - assets/diagram/fonts/Roboto-400.ttf
342
+ - assets/diagram/fonts/Roboto-700.ttf
343
+ - assets/diagram/fonts/Roboto-Italic-400.ttf
344
+ - assets/diagram/fonts/Roboto-Italic-Latin.woff2
345
+ - assets/diagram/fonts/Roboto-Normal-Latin.woff2
346
+ - assets/diagram/operators.svg
325
347
  - bin/conceptql
326
348
  - bin/conceptql_utils
327
349
  - config/multiple_vocabularies.csv
@@ -330,7 +352,43 @@ files:
330
352
  - config/vocabularies.csv
331
353
  - config/vocabulary_formats.sha
332
354
  - config/vocabulary_formats.tsv
333
- - doc/spec.md
355
+ - docs/spec/README.md
356
+ - docs/spec/examples/after-operator.json
357
+ - docs/spec/examples/any-overlap-operator.json
358
+ - docs/spec/examples/before-operator.json
359
+ - docs/spec/examples/co-reported-operator.json
360
+ - docs/spec/examples/contains-operator.json
361
+ - docs/spec/examples/date-range-operator.json
362
+ - docs/spec/examples/death-operator.json
363
+ - docs/spec/examples/during-operator.json
364
+ - docs/spec/examples/episode-operator.json
365
+ - docs/spec/examples/equal-operator.json
366
+ - docs/spec/examples/ethnicity-operator.json
367
+ - docs/spec/examples/except-operator.json
368
+ - docs/spec/examples/filter-operator.json
369
+ - docs/spec/examples/first-operator.json
370
+ - docs/spec/examples/gender-operator.json
371
+ - docs/spec/examples/hospice-operator.json
372
+ - docs/spec/examples/hospitalization-operator.json
373
+ - docs/spec/examples/information-periods-operator.json
374
+ - docs/spec/examples/last-operator.json
375
+ - docs/spec/examples/match-operator.json
376
+ - docs/spec/examples/nth-occurrence-operator.json
377
+ - docs/spec/examples/numeric-filter-operator.json
378
+ - docs/spec/examples/one-in-two-out-operator.json
379
+ - docs/spec/examples/person-filter-operator.json
380
+ - docs/spec/examples/person-operator.json
381
+ - docs/spec/examples/place-of-service-filter-operator.json
382
+ - docs/spec/examples/provenance-operator.json
383
+ - docs/spec/examples/provider-filter-operator.json
384
+ - docs/spec/examples/race-operator.json
385
+ - docs/spec/examples/recall-operator.json
386
+ - docs/spec/examples/snf-operator.json
387
+ - docs/spec/examples/time-window-operator.json
388
+ - docs/spec/examples/trim-date-end-operator.json
389
+ - docs/spec/examples/trim-date-start-operator.json
390
+ - docs/spec/examples/union-operator.json
391
+ - docs/spec/examples/vocabulary-operator.json
334
392
  - lib/conceptql.rb
335
393
  - lib/conceptql/behaviors/code_lister.rb
336
394
  - lib/conceptql/behaviors/drugish.rb
@@ -342,6 +400,7 @@ files:
342
400
  - lib/conceptql/behaviors/utilizable.rb
343
401
  - lib/conceptql/behaviors/windowable.rb
344
402
  - lib/conceptql/cli.rb
403
+ - lib/conceptql/code_case_mismatch_error.rb
345
404
  - lib/conceptql/columnizer.rb
346
405
  - lib/conceptql/data_model.rb
347
406
  - lib/conceptql/data_model/base.rb
@@ -350,6 +409,19 @@ files:
350
409
  - lib/conceptql/database.rb
351
410
  - lib/conceptql/date_adjuster.rb
352
411
  - lib/conceptql/diagram.rb
412
+ - lib/conceptql/diagram_renderer.rb
413
+ - lib/conceptql/diagram_renderer/app.rb
414
+ - lib/conceptql/diagram_renderer/configuration.rb
415
+ - lib/conceptql/diagram_renderer/diagram_data.rb
416
+ - lib/conceptql/diagram_renderer/drawing.rb
417
+ - lib/conceptql/diagram_renderer/geometry.rb
418
+ - lib/conceptql/diagram_renderer/input_error.rb
419
+ - lib/conceptql/diagram_renderer/js_format.rb
420
+ - lib/conceptql/diagram_renderer/resvg.rb
421
+ - lib/conceptql/diagram_renderer/sprite.rb
422
+ - lib/conceptql/diagram_renderer/static.rb
423
+ - lib/conceptql/diagram_renderer/svg.rb
424
+ - lib/conceptql/diagram_renderer/tree_layout.rb
353
425
  - lib/conceptql/lexicon.rb
354
426
  - lib/conceptql/lexicon/lexicon_gdm.rb
355
427
  - lib/conceptql/lexicon/lexicon_no_db.rb
@@ -449,6 +521,7 @@ files:
449
521
  homepage: https://github.com/outcomesinsights/conceptql
450
522
  licenses:
451
523
  - MIT
524
+ - OFL-1.1
452
525
  metadata:
453
526
  rubygems_mfa_required: 'true'
454
527
  rdoc_options: []