conceptql 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (1192) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +32 -104
  4. data/Gemfile +2 -0
  5. data/README.md +43 -21
  6. data/Rakefile +34 -0
  7. data/conceptql.gemspec +3 -4
  8. data/config/provenance.yml +454 -0
  9. data/doc/converter.rb +33 -0
  10. data/doc/metadata.md +89 -0
  11. data/doc/spec.md +1775 -861
  12. data/doc/spec.md.cql +1930 -0
  13. data/doc/spec/02f44ad35d266ddd0a4df1691d26bf4a297b30604fc3f44b0391d6d852d23a9f.png +0 -0
  14. data/doc/spec/0360fc0c2b7a88fd82ffc4d13387b76766649d5d42aa8f9349bbf60a81ac6119.png +0 -0
  15. data/doc/spec/04491942fcbd741982514f9eb12aeecf3d54b5b69a2b50c8331f7700169d5521.png +0 -0
  16. data/doc/spec/05f9b844571ffceeed2def3025fb60c68552817b8b73d3c8a76939dbc08b7c65.png +0 -0
  17. data/doc/spec/067241a3579767a802d4f8e20fd35b60adbe377c9a6512ef135f164a5accfb27.png +0 -0
  18. data/doc/spec/1102fa717b1c2df67af5220bf3ae219afafd79be7bba0c117e301983385ada52.png +0 -0
  19. data/doc/spec/11f57941951bad5a75f9a16f38a31a3c6bf3046a475aac6e398e780892fab4ad.png +0 -0
  20. data/doc/spec/15268bc45993d3f57ccf915877f91e48bdee684f24faa614249915833cac4af9.png +0 -0
  21. data/doc/spec/253845fe6162621af407ebd110296ff4f6d8a3f23ec75dfb4ea8cda30be71262.png +0 -0
  22. data/doc/spec/26fd52b5ac55438dd9f81b4a3f3913f1058c9f225c8a5e129007c1e9413d5881.png +0 -0
  23. data/doc/spec/2b57886a9cba66bb696e4b399c51ad0dc95cd64b952709fafc819a79d573f09e.png +0 -0
  24. data/doc/spec/307a8b5a7edd6e42f8be16523a4c939faf1a0533385c861d7004b6af8addd7d1.png +0 -0
  25. data/doc/spec/328467a6a419c7c05e299b8097e5e000686068ded8dc6d5f2e2de6f51976c315.png +0 -0
  26. data/doc/spec/39d6a8eb71cae51b1d6937c97134e51f04fd47c54535ff0915fe6a8b4f197fb2.png +0 -0
  27. data/doc/spec/3f46dee4d775d1a29d52b68af6552f8ea3abd8303094e749714fc77bd7958155.png +0 -0
  28. data/doc/spec/44ec6743d5d77d15b8a487c2058bf3e455d34adc91c46ea05767f6e0e471a75e.png +0 -0
  29. data/doc/spec/462153be527b28dc2cb5259c0aec62e1f529e8b60dc6e9c23fd1e06e8be933c9.png +0 -0
  30. data/doc/spec/4a3b47ed1c54f96ebdae693d41c36c51884c4546ef799a4108085708fb7b964e.png +0 -0
  31. data/doc/spec/514f263e976d07c0d9e0a86c79bcbdcddc7d444d7b72135294ad78758effd28f.png +0 -0
  32. data/doc/spec/58113a57a37431a402d2547369eba3a481bf1dbbfd82dc384406a5c91f6df01f.png +0 -0
  33. data/doc/spec/5d331d74c460d75814b2d3138a9b7d90b5ddb2dcd85e1f5f260d183745fc3a1e.png +0 -0
  34. data/doc/spec/5d6ff62038b75d6f240d65f35d1520a131c221f47d3801554c8c2be5d528ebb0.png +0 -0
  35. data/doc/spec/62323426e381ec21c967971a67e1f4a6d89dae92154bd937284e00b67f67fdd3.png +0 -0
  36. data/doc/spec/6705af65d728c0d5c50d6c4d46253017a91eb459dbb1f40f92449f05d5562f4a.png +0 -0
  37. data/doc/spec/68fac940a32c7e40caacf8e560c61da552d57633d015ba98f2e98ec040a00c5b.png +0 -0
  38. data/doc/spec/6a34c0ef589c9c976fe41f3e67e799e198499f5b9c3ebfd240fb91f73e893573.png +0 -0
  39. data/doc/spec/6b48534236697d1ccfa1f5403764782f9d228f9eb706789cfa80203882b7b13a.png +0 -0
  40. data/doc/spec/7aa76b4d29874719466c2cbafc9936e9f12e504bf31e1a09d26ca3fffa8ba1a6.png +0 -0
  41. data/doc/spec/7b9db2986ab9ada45cfb9451ef87ff1a2d99c908083334b7ccdceb8a92387fa9.png +0 -0
  42. data/doc/spec/8101d9b89d9ba8070d585432707b43a8acdb4c2a3e9d37c3f7114b5e3ea9e800.png +0 -0
  43. data/doc/spec/886bf85249a704668a55c5161bceaac10be4a41a94b91606f49851dfa017526c.png +0 -0
  44. data/doc/spec/8ed478d8c81a58a202d0c51348fca246df206fc24a0567b163d4e0bdab56ca46.png +0 -0
  45. data/doc/spec/9139440329dcb815df89bc70182c3827868402a74ff64d0253706dcaff723dca.png +0 -0
  46. data/doc/spec/99392f56dfb0e5be3f45a12a7f1ba846d094e430f526dfeaa30b606837cd34c0.png +0 -0
  47. data/doc/spec/a4450e8c0fe0e2fde92fe9bd61952f907b1976c1aa3ba963b809bed079d42b09.png +0 -0
  48. data/doc/spec/a4bc7382a1154ea9856544fd48418f3dd9ce474ca94b8859fc323749c6cc1f55.png +0 -0
  49. data/doc/spec/a79274742cf6fac6f6c9f4a0eb651aeb452f9c43b537c8e6ccaefecd05b7105c.png +0 -0
  50. data/doc/spec/a9b4528726adec2a90f3f00139d8d0492f13c51f03c2f9ed6a5134b1b26b44a9.png +0 -0
  51. data/doc/spec/af5ae3787e80bf0771f18f1a04fe4c5d9291e1e0f963ac408a7bc198d2f1ee28.png +0 -0
  52. data/doc/spec/ba572c4f4dbade65be55f141df16cf7b3e7d09e0aec4e4e5debc4f2075277371.png +0 -0
  53. data/doc/spec/ba90ef705f7be91c53c5eb4a81a439fa0f7c48532214bd3db3cc5c069160543e.png +0 -0
  54. data/doc/spec/c1d0402862221d85aceedc7d76b3f82149b612cbd972f14d0ca9011e1e2c455c.png +0 -0
  55. data/doc/spec/c2157d8a6b73abe4f22ba5042159f32502c74bf6d762be28d2df6831586822c7.png +0 -0
  56. data/doc/spec/c5329a7f4937096a57b2e01efb9d542f84a4e2329a1e9381d08c630583ccad37.png +0 -0
  57. data/doc/spec/c82077b9455d0f9abc2c45ee1a298e38b99c9ce9cd685f65d87b376d7718d7ad.png +0 -0
  58. data/doc/spec/c93dd18894a245a5647f99e1867d3779e4cd34c9c8f8860600ff0c837a5ffa53.png +0 -0
  59. data/doc/spec/cc960a268d51ccf2ebde657d36848f780213834844900018bce3d111843f7b0f.png +0 -0
  60. data/doc/spec/d39452b58257c95a7cba07afed4877417b0c227f3690e2bff22c9eca89eac845.png +0 -0
  61. data/doc/spec/d64993258ffbef9406d9ab9136de7af530626b3a69e9eeb75835e11f11dabf62.png +0 -0
  62. data/doc/spec/da450cdd0c94a1301bd98560339a45caa8041e09974352a56ecfb144e9a5e4d4.png +0 -0
  63. data/doc/spec/dbc66b3ae6bd7123d77dd04b64f8a24498d048725a55c5340b15f5ae0a1ff307.png +0 -0
  64. data/doc/spec/de589af36fa854e006a1563c93e644e2210f2a5616babb779f7f38aadb6c1ed7.png +0 -0
  65. data/doc/spec/defbd0b853d895802663f507761ad297d82e167f516c6082686a2a19b76012c5.png +0 -0
  66. data/doc/spec/e1cb0863b21e14256d61a54200316791f6547c78ba2f0156c110f4500f9bbd49.png +0 -0
  67. data/doc/spec/e8630103287f7c9d28eff40b3b1826e24846e776b877f7b8554257acbe621e1c.png +0 -0
  68. data/doc/spec/e9b384fa7dec5f1a06479c4b289e06b1e60e4f23f7630aff6d03c52595f500f8.png +0 -0
  69. data/doc/spec/ea935ac31f3b57ff373646780a1fba34a38c9e086dc771eb7fc16c65a7e20cfc.png +0 -0
  70. data/doc/spec/eb8f5511f7d88bd0f8ba73420fc10f7c78405db7f4373d778a827058707f888e.png +0 -0
  71. data/doc/spec/ebacbd092e3d1a3c7b745a381e51e8ff9d63a21db23a16940193e18e57bc866f.png +0 -0
  72. data/doc/spec/ed039f82867241393b1a6a7153d3690461103934c72c1f3eaa3d99a12bb40885.png +0 -0
  73. data/doc/spec/ee283d6a4b69cf10da2df703be3a16830be9cd8cd4f68c5f7afdf558ea28fa76.png +0 -0
  74. data/doc/spec/f0c734b099841a754ae0366afb00e992ad4814479b65e4a7de23c6e3dd85c09a.png +0 -0
  75. data/doc/spec/f6b4fc31703cfb6327bbbd4614af8bb72da6d39fa3d53ada63a70157f2fad80e.png +0 -0
  76. data/doc/spec/f766f2e3aa13420e3ba0f823ac7956b311ed7c6c20be26b72324fadd87f36712.png +0 -0
  77. data/doc/spec/ff7d5b5573d09bd7c4cdd3aeda124d18bf82ec46673a62881b399a75d69f3f53.png +0 -0
  78. data/lib/conceptql.rb +21 -1
  79. data/lib/conceptql/annotate_grapher.rb +127 -0
  80. data/lib/conceptql/behaviors/drugish.rb +12 -0
  81. data/lib/conceptql/behaviors/labish.rb +13 -0
  82. data/lib/conceptql/behaviors/metadatable.rb +156 -71
  83. data/lib/conceptql/behaviors/provenanceable.rb +30 -0
  84. data/lib/conceptql/cli.rb +81 -37
  85. data/lib/conceptql/database.rb +42 -0
  86. data/lib/conceptql/date_adjuster.rb +22 -4
  87. data/lib/conceptql/fake_annotater.rb +129 -0
  88. data/lib/conceptql/knitter.rb +221 -0
  89. data/lib/conceptql/nodifier.rb +34 -23
  90. data/lib/conceptql/operators/after.rb +20 -3
  91. data/lib/conceptql/operators/any_overlap.rb +3 -1
  92. data/lib/conceptql/operators/before.rb +19 -3
  93. data/lib/conceptql/operators/binary_operator_operator.rb +24 -20
  94. data/lib/conceptql/operators/casting_operator.rb +39 -31
  95. data/lib/conceptql/operators/co_reported.rb +42 -0
  96. data/lib/conceptql/operators/complement.rb +21 -16
  97. data/lib/conceptql/operators/concurrent_within.rb +57 -0
  98. data/lib/conceptql/operators/condition_occurrence_source_vocabulary_operator.rb +34 -0
  99. data/lib/conceptql/operators/condition_occurrence_source_vocabulary_operator_union.rb +28 -0
  100. data/lib/conceptql/operators/condition_type.rb +12 -4
  101. data/lib/conceptql/operators/contains.rb +6 -2
  102. data/lib/conceptql/operators/count.rb +10 -2
  103. data/lib/conceptql/operators/cpt.rb +5 -2
  104. data/lib/conceptql/operators/cpt_or_hcpcs.rb +27 -0
  105. data/lib/conceptql/operators/date_range.rb +20 -8
  106. data/lib/conceptql/operators/death.rb +4 -2
  107. data/lib/conceptql/operators/drg.rb +42 -0
  108. data/lib/conceptql/operators/drug_type_concept.rb +11 -2
  109. data/lib/conceptql/operators/during.rb +4 -2
  110. data/lib/conceptql/operators/equal.rb +4 -1
  111. data/lib/conceptql/operators/except.rb +16 -4
  112. data/lib/conceptql/operators/filter.rb +6 -3
  113. data/lib/conceptql/operators/first.rb +3 -1
  114. data/lib/conceptql/operators/from.rb +32 -5
  115. data/lib/conceptql/operators/from_seer_visits.rb +11 -5
  116. data/lib/conceptql/operators/gender.rb +9 -2
  117. data/lib/conceptql/operators/hcpcs.rb +5 -2
  118. data/lib/conceptql/operators/icd10.rb +6 -15
  119. data/lib/conceptql/operators/icd10_pcs.rb +28 -0
  120. data/lib/conceptql/operators/icd9.rb +6 -15
  121. data/lib/conceptql/operators/icd9_procedure.rb +5 -2
  122. data/lib/conceptql/operators/intersect.rb +15 -10
  123. data/lib/conceptql/operators/invalid.rb +36 -0
  124. data/lib/conceptql/operators/last.rb +3 -1
  125. data/lib/conceptql/operators/loinc.rb +5 -2
  126. data/lib/conceptql/operators/medcode.rb +5 -16
  127. data/lib/conceptql/operators/medcode_procedure.rb +3 -2
  128. data/lib/conceptql/operators/ndc.rb +5 -2
  129. data/lib/conceptql/operators/numeric.rb +30 -11
  130. data/lib/conceptql/operators/observation_by_enttype.rb +5 -2
  131. data/lib/conceptql/operators/observation_period.rb +6 -4
  132. data/lib/conceptql/operators/occurrence.rb +47 -11
  133. data/lib/conceptql/operators/one_in_two_out.rb +96 -33
  134. data/lib/conceptql/operators/operator.rb +628 -95
  135. data/lib/conceptql/operators/overlapped_by.rb +8 -5
  136. data/lib/conceptql/operators/overlaps.rb +7 -5
  137. data/lib/conceptql/operators/pass_thru.rb +12 -2
  138. data/lib/conceptql/operators/person.rb +7 -5
  139. data/lib/conceptql/operators/person_filter.rb +5 -1
  140. data/lib/conceptql/operators/place_of_service_code.rb +12 -5
  141. data/lib/conceptql/operators/place_of_service_filter.rb +47 -0
  142. data/lib/conceptql/operators/procedure_occurrence.rb +4 -2
  143. data/lib/conceptql/operators/prodcode.rb +5 -2
  144. data/lib/conceptql/operators/provenance.rb +66 -0
  145. data/lib/conceptql/operators/provider_filter.rb +36 -0
  146. data/lib/conceptql/operators/race.rb +11 -4
  147. data/lib/conceptql/operators/read.rb +149 -0
  148. data/lib/conceptql/operators/recall.rb +42 -7
  149. data/lib/conceptql/operators/revenue_code.rb +40 -0
  150. data/lib/conceptql/operators/rxnorm.rb +5 -1
  151. data/lib/conceptql/operators/snomed.rb +3 -2
  152. data/lib/conceptql/operators/source_vocabulary_operator.rb +44 -14
  153. data/lib/conceptql/operators/standard_vocabulary_operator.rb +36 -15
  154. data/lib/conceptql/operators/started_by.rb +2 -1
  155. data/lib/conceptql/operators/sum.rb +7 -1
  156. data/lib/conceptql/operators/temporal_operator.rb +75 -9
  157. data/lib/conceptql/operators/time_window.rb +13 -23
  158. data/lib/conceptql/operators/to_seer_visits.rb +6 -1
  159. data/lib/conceptql/operators/trim_date_end.rb +20 -12
  160. data/lib/conceptql/operators/trim_date_start.rb +22 -12
  161. data/lib/conceptql/operators/union.rb +39 -2
  162. data/lib/conceptql/operators/visit_occurrence.rb +5 -3
  163. data/lib/conceptql/operators/vocabulary_operator.rb +45 -0
  164. data/lib/conceptql/query.rb +68 -22
  165. data/lib/conceptql/query_modifiers/drug_query_modifier.rb +45 -0
  166. data/lib/conceptql/query_modifiers/pos_query_modifier.rb +31 -0
  167. data/lib/conceptql/query_modifiers/query_modifier.rb +16 -0
  168. data/lib/conceptql/scope.rb +169 -31
  169. data/lib/conceptql/sql_formatter.rb +22 -0
  170. data/lib/conceptql/version.rb +1 -1
  171. data/test/all.rb +3 -0
  172. data/test/all_operations_test.rb +45 -0
  173. data/test/code_list_test.rb +23 -0
  174. data/test/data/omopv4/care_site.csv +0 -0
  175. data/test/data/omopv4/cohort.csv +0 -0
  176. data/test/data/omopv4/condition_era.csv +0 -0
  177. data/test/data/omopv4/condition_occurrence.csv +34044 -0
  178. data/test/data/omopv4/death.csv +1 -0
  179. data/test/data/omopv4/drug_cost.csv +0 -0
  180. data/test/data/omopv4/drug_era.csv +0 -0
  181. data/test/data/omopv4/drug_exposure.csv +2 -0
  182. data/test/data/omopv4/location.csv +0 -0
  183. data/test/data/omopv4/observation.csv +2 -0
  184. data/test/data/omopv4/observation_period.csv +1 -0
  185. data/test/data/omopv4/organization.csv +0 -0
  186. data/test/data/omopv4/payer_plan_period.csv +0 -0
  187. data/test/data/omopv4/person.csv +250 -0
  188. data/test/data/omopv4/procedure_cost.csv +0 -0
  189. data/test/data/omopv4/procedure_occurrence.csv +35099 -0
  190. data/test/data/omopv4/provider.csv +0 -0
  191. data/test/data/omopv4/visit_occurrence.csv +14931 -0
  192. data/test/data/omopv4_plus/care_site.csv +0 -0
  193. data/test/data/omopv4_plus/cohort.csv +0 -0
  194. data/test/data/omopv4_plus/concept.csv +352 -0
  195. data/test/data/omopv4_plus/condition_era.csv +0 -0
  196. data/test/data/omopv4_plus/condition_occurrence.csv +46673 -0
  197. data/test/data/omopv4_plus/death.csv +9 -0
  198. data/test/data/omopv4_plus/drug_cost.csv +13921 -0
  199. data/test/data/omopv4_plus/drug_era.csv +0 -0
  200. data/test/data/omopv4_plus/drug_exposure.csv +13921 -0
  201. data/test/data/omopv4_plus/headers/care_site.csv +1 -0
  202. data/test/data/omopv4_plus/headers/cohort.csv +1 -0
  203. data/test/data/omopv4_plus/headers/concept.csv +1 -0
  204. data/test/data/omopv4_plus/headers/condition_era.csv +1 -0
  205. data/test/data/omopv4_plus/headers/condition_occurrence.csv +1 -0
  206. data/test/data/omopv4_plus/headers/death.csv +1 -0
  207. data/test/data/omopv4_plus/headers/drug_cost.csv +1 -0
  208. data/test/data/omopv4_plus/headers/drug_era.csv +1 -0
  209. data/test/data/omopv4_plus/headers/drug_exposure.csv +1 -0
  210. data/test/data/omopv4_plus/headers/location.csv +1 -0
  211. data/test/data/omopv4_plus/headers/observation.csv +1 -0
  212. data/test/data/omopv4_plus/headers/observation_period.csv +1 -0
  213. data/test/data/omopv4_plus/headers/organization.csv +1 -0
  214. data/test/data/omopv4_plus/headers/payer_plan_period.csv +1 -0
  215. data/test/data/omopv4_plus/headers/person.csv +1 -0
  216. data/test/data/omopv4_plus/headers/procedure_cost.csv +1 -0
  217. data/test/data/omopv4_plus/headers/procedure_occurrence.csv +1 -0
  218. data/test/data/omopv4_plus/headers/provider.csv +1 -0
  219. data/test/data/omopv4_plus/headers/source_to_concept_map.csv +1 -0
  220. data/test/data/omopv4_plus/headers/visit_occurrence.csv +1 -0
  221. data/test/data/omopv4_plus/headers/vocabulary.csv +1 -0
  222. data/test/data/omopv4_plus/location.csv +0 -0
  223. data/test/data/omopv4_plus/observation.csv +0 -0
  224. data/test/data/omopv4_plus/observation_period.csv +147 -0
  225. data/test/data/omopv4_plus/organization.csv +736 -0
  226. data/test/data/omopv4_plus/payer_plan_period.csv +808 -0
  227. data/test/data/omopv4_plus/person.csv +250 -0
  228. data/test/data/omopv4_plus/procedure_cost.csv +20123 -0
  229. data/test/data/omopv4_plus/procedure_occurrence.csv +27273 -0
  230. data/test/data/omopv4_plus/provider.csv +10193 -0
  231. data/test/data/omopv4_plus/source_to_concept_map.csv +285 -0
  232. data/test/data/omopv4_plus/visit_occurrence.csv +45125 -0
  233. data/test/data/omopv4_plus/vocabulary.csv +60 -0
  234. data/test/db.rb +15 -0
  235. data/test/db_setup.rb +408 -0
  236. data/test/db_teardown.rb +33 -0
  237. data/test/fake_annotater_test.rb +31 -0
  238. data/test/helper.rb +129 -0
  239. data/test/knitter/conceptql.md.cql +39 -0
  240. data/test/knitter/conceptql.md.expect +43 -0
  241. data/test/knitter/empty.md.cql +0 -0
  242. data/test/knitter/except.md.cql +13 -0
  243. data/test/knitter/except.md.expect +14 -0
  244. data/test/knitter/fake.md.cql +10 -0
  245. data/test/knitter/fake.md.expect +13 -0
  246. data/test/knitter/many.md.cql +7 -0
  247. data/test/knitter/many.md.expect +14 -0
  248. data/test/knitter/no_conceptql.md.cql +36 -0
  249. data/test/knitter/title.md.cql +12 -0
  250. data/test/knitter/title.md.expect +15 -0
  251. data/test/knitter/union.md.cql +11 -0
  252. data/test/knitter/union.md.expect +14 -0
  253. data/test/knitter_test.rb +69 -0
  254. data/test/query_test.rb +36 -0
  255. data/test/results/omopv4/after/anno_1 +25 -0
  256. data/test/results/omopv4/after/anno_2 +48 -0
  257. data/test/results/omopv4/after/anno_3 +34 -0
  258. data/test/results/omopv4/after/anno_4 +60 -0
  259. data/test/results/omopv4/after/anno_5 +68 -0
  260. data/test/results/omopv4/after/anno_6 +60 -0
  261. data/test/results/omopv4/after/crit_at_least +7 -0
  262. data/test/results/omopv4/after/crit_basic +32 -0
  263. data/test/results/omopv4/after/crit_occurrences +12 -0
  264. data/test/results/omopv4/after/crit_within +6 -0
  265. data/test/results/omopv4/any_overlap/crit_basic1 +15 -0
  266. data/test/results/omopv4/any_overlap/crit_basic2 +15 -0
  267. data/test/results/omopv4/any_overlap/crit_occurrences1 +2 -0
  268. data/test/results/omopv4/any_overlap/crit_occurrences2 +15 -0
  269. data/test/results/omopv4/any_overlap/crit_within +8 -0
  270. data/test/results/omopv4/before/crit_at_least +6 -0
  271. data/test/results/omopv4/before/crit_basic1 +48 -0
  272. data/test/results/omopv4/before/crit_basic2 +7 -0
  273. data/test/results/omopv4/before/crit_occurrences +13 -0
  274. data/test/results/omopv4/before/crit_within +18 -0
  275. data/test/results/omopv4/co_reported/anno_1 +43 -0
  276. data/test/results/omopv4/co_reported/anno_2 +66 -0
  277. data/test/results/omopv4/complement/anno_duplicate_params +52 -0
  278. data/test/results/omopv4/complement/anno_invalid_params +37 -0
  279. data/test/results/omopv4/complement/anno_no_params +18 -0
  280. data/test/results/omopv4/complement/count_3way_intersect +4 -0
  281. data/test/results/omopv4/complement/count_3way_union +4 -0
  282. data/test/results/omopv4/complement/count_intersect +3 -0
  283. data/test/results/omopv4/complement/count_union +3 -0
  284. data/test/results/omopv4/complement/count_union_and_intersect +4 -0
  285. data/test/results/omopv4/complement/crit_3way_intersect +1 -0
  286. data/test/results/omopv4/complement/crit_3way_union +1 -0
  287. data/test/results/omopv4/complement/crit_basic1 +33998 -0
  288. data/test/results/omopv4/complement/crit_icd9_selector +54 -0
  289. data/test/results/omopv4/complement/crit_intersect +1 -0
  290. data/test/results/omopv4/complement/crit_union +1 -0
  291. data/test/results/omopv4/complement/crit_union_and_intersect +1 -0
  292. data/test/results/omopv4/complex/anno_1 +85 -0
  293. data/test/results/omopv4/complex/crit_1 +2 -0
  294. data/test/results/omopv4/complex/crit_2 +2 -0
  295. data/test/results/omopv4/complex/crit_3 +2 -0
  296. data/test/results/omopv4/complex/crit_4 +5 -0
  297. data/test/results/omopv4/complex/crit_5 +6 -0
  298. data/test/results/omopv4/complex/crit_6 +28 -0
  299. data/test/results/omopv4/complex/crit_7 +46 -0
  300. data/test/results/omopv4/complex/crit_out_of_order_ctes +7 -0
  301. data/test/results/omopv4/complex/scanno_1 +3 -0
  302. data/test/results/omopv4/concurrent_within/crit_icd9 +54 -0
  303. data/test/results/omopv4/concurrent_within/crit_icd9_and_place_of_service +23 -0
  304. data/test/results/omopv4/concurrent_within/crit_negative_start +5 -0
  305. data/test/results/omopv4/condition_type/anno_icd9 +39 -0
  306. data/test/results/omopv4/condition_type/count_condition_era +2 -0
  307. data/test/results/omopv4/condition_type/count_condition_era_30_day_window +2 -0
  308. data/test/results/omopv4/condition_type/count_ehr_problem_list +2 -0
  309. data/test/results/omopv4/condition_type/count_era_0 +2 -0
  310. data/test/results/omopv4/condition_type/count_inpatient +3 -0
  311. data/test/results/omopv4/condition_type/count_inpatient_detail +2 -0
  312. data/test/results/omopv4/condition_type/count_inpatient_header +3 -0
  313. data/test/results/omopv4/condition_type/count_inpatient_header_2 +3 -0
  314. data/test/results/omopv4/condition_type/count_inpatient_header_3 +3 -0
  315. data/test/results/omopv4/condition_type/count_inpatient_header_4 +3 -0
  316. data/test/results/omopv4/condition_type/count_inpatient_header_5 +3 -0
  317. data/test/results/omopv4/condition_type/count_inpatient_outpatient_detail +3 -0
  318. data/test/results/omopv4/condition_type/count_inpatient_primary +2 -0
  319. data/test/results/omopv4/condition_type/count_inpatient_primary_or_first +3 -0
  320. data/test/results/omopv4/condition_type/count_outpatient +3 -0
  321. data/test/results/omopv4/condition_type/count_outpatient_detail +3 -0
  322. data/test/results/omopv4/condition_type/count_outpatient_header +2 -0
  323. data/test/results/omopv4/condition_type/count_outpatient_primary +3 -0
  324. data/test/results/omopv4/condition_type/count_primary +3 -0
  325. data/test/results/omopv4/condition_type/crit_condition_era +1 -0
  326. data/test/results/omopv4/condition_type/crit_condition_era_30_day_window +1 -0
  327. data/test/results/omopv4/condition_type/crit_ehr_problem_list +1 -0
  328. data/test/results/omopv4/condition_type/crit_era_0 +1 -0
  329. data/test/results/omopv4/condition_type/crit_inpatient +1 -0
  330. data/test/results/omopv4/condition_type/crit_inpatient_detail +1 -0
  331. data/test/results/omopv4/condition_type/crit_inpatient_header +1 -0
  332. data/test/results/omopv4/condition_type/crit_inpatient_header_2 +1 -0
  333. data/test/results/omopv4/condition_type/crit_inpatient_header_3 +1 -0
  334. data/test/results/omopv4/condition_type/crit_inpatient_header_4 +1 -0
  335. data/test/results/omopv4/condition_type/crit_inpatient_header_5 +1 -0
  336. data/test/results/omopv4/condition_type/crit_inpatient_primary +1 -0
  337. data/test/results/omopv4/condition_type/crit_inpatient_primary_or_first +1 -0
  338. data/test/results/omopv4/condition_type/crit_outpatient +1 -0
  339. data/test/results/omopv4/condition_type/crit_outpatient_detail +1 -0
  340. data/test/results/omopv4/condition_type/crit_outpatient_header +1 -0
  341. data/test/results/omopv4/condition_type/crit_outpatient_primary +1 -0
  342. data/test/results/omopv4/condition_type/crit_primary +1 -0
  343. data/test/results/omopv4/contains/crit_1 +5 -0
  344. data/test/results/omopv4/contains/crit_2 +2 -0
  345. data/test/results/omopv4/contains/crit_3 +2 -0
  346. data/test/results/omopv4/count/anno_multiple_upstreams +52 -0
  347. data/test/results/omopv4/count/anno_no_upstream1 +18 -0
  348. data/test/results/omopv4/count/anno_no_upstream2 +25 -0
  349. data/test/results/omopv4/count/crit_icd9_ndc +8 -0
  350. data/test/results/omopv4/count/crit_ndc +5 -0
  351. data/test/results/omopv4/count/crit_person +254 -0
  352. data/test/results/omopv4/cpt/anno_icd9_upstream +40 -0
  353. data/test/results/omopv4/cpt/anno_invalid_code +22 -0
  354. data/test/results/omopv4/cpt/count_1 +3 -0
  355. data/test/results/omopv4/cpt/crit_1 +174 -0
  356. data/test/results/omopv4/cpt/crit_2 +1 -0
  357. data/test/results/omopv4/cpt/scanno_1 +17 -0
  358. data/test/results/omopv4/cpt_or_hcpcs/anno_bad_format +25 -0
  359. data/test/results/omopv4/cpt_or_hcpcs/count_1 +3 -0
  360. data/test/results/omopv4/cpt_or_hcpcs/crit_1 +179 -0
  361. data/test/results/omopv4/cpt_or_hcpcs/crit_2 +1 -0
  362. data/test/results/omopv4/date_range/anno_1 +15 -0
  363. data/test/results/omopv4/date_range/anno_extra_argument +24 -0
  364. data/test/results/omopv4/date_range/anno_invalid_argument +25 -0
  365. data/test/results/omopv4/date_range/anno_missing_argument1 +20 -0
  366. data/test/results/omopv4/date_range/anno_missing_argument2 +20 -0
  367. data/test/results/omopv4/date_range/anno_no_upstreams +38 -0
  368. data/test/results/omopv4/date_range/count_1 +3 -0
  369. data/test/results/omopv4/date_range/count_2 +3 -0
  370. data/test/results/omopv4/date_range/crit_1 +1 -0
  371. data/test/results/omopv4/date_range/crit_2 +1 -0
  372. data/test/results/omopv4/death/anno_multiple_upstreams +50 -0
  373. data/test/results/omopv4/death/anno_no_upstreams +22 -0
  374. data/test/results/omopv4/death/crit_basic +5 -0
  375. data/test/results/omopv4/death/crit_person +5 -0
  376. data/test/results/omopv4/drug_type_concept/anno_has_upstreams +37 -0
  377. data/test/results/omopv4/drug_type_concept/anno_no_arguments +18 -0
  378. data/test/results/omopv4/drug_type_concept/crit_basic1 +5 -0
  379. data/test/results/omopv4/drug_type_concept/crit_basic2 +2 -0
  380. data/test/results/omopv4/during/crit_1 +15 -0
  381. data/test/results/omopv4/during/crit_2 +2 -0
  382. data/test/results/omopv4/equal/crit_1 +5 -0
  383. data/test/results/omopv4/equal/crit_2 +5 -0
  384. data/test/results/omopv4/except/anno_1 +42 -0
  385. data/test/results/omopv4/except/anno_2 +43 -0
  386. data/test/results/omopv4/except/count_complex +5 -0
  387. data/test/results/omopv4/except/crit_412_cpt +54 -0
  388. data/test/results/omopv4/except/crit_412_inpatient +46 -0
  389. data/test/results/omopv4/except/crit_complex +1 -0
  390. data/test/results/omopv4/filter/crit_1 +54 -0
  391. data/test/results/omopv4/first/anno_argument +25 -0
  392. data/test/results/omopv4/first/anno_no_upstream +18 -0
  393. data/test/results/omopv4/first/crit_cpt +207 -0
  394. data/test/results/omopv4/first/crit_icd9 +42 -0
  395. data/test/results/omopv4/first/crit_union +45 -0
  396. data/test/results/omopv4/from/anno_has_upstreams +39 -0
  397. data/test/results/omopv4/from/anno_multiple_arguments +24 -0
  398. data/test/results/omopv4/from/count_condition_occurrence +3 -0
  399. data/test/results/omopv4/from/count_observation_period +3 -0
  400. data/test/results/omopv4/from/count_person +3 -0
  401. data/test/results/omopv4/from_seer_visits/anno_multiple_upstreams +78 -0
  402. data/test/results/omopv4/from_seer_visits/anno_no_upstream +18 -0
  403. data/test/results/omopv4/from_seer_visits/crit_1 +6 -0
  404. data/test/results/omopv4/from_seer_visits/crit_2 +5 -0
  405. data/test/results/omopv4/from_seer_visits/crit_3 +5 -0
  406. data/test/results/omopv4/from_seer_visits/crit_4 +6 -0
  407. data/test/results/omopv4/gender/anno_has_upstreams +39 -0
  408. data/test/results/omopv4/gender/crit_male +130 -0
  409. data/test/results/omopv4/hcpcs/anno_bad_format +24 -0
  410. data/test/results/omopv4/hcpcs/crit_A0382 +9 -0
  411. data/test/results/omopv4/icd10/anno_bad_format +22 -0
  412. data/test/results/omopv4/icd10/anno_has_upstreams +40 -0
  413. data/test/results/omopv4/icd10/crit_1 +5 -0
  414. data/test/results/omopv4/icd10pcs/anno_bad_format +28 -0
  415. data/test/results/omopv4/icd10pcs/anno_has_upstreams +40 -0
  416. data/test/results/omopv4/icd10pcs/crit_1 +2 -0
  417. data/test/results/omopv4/icd9/anno_empty_label +15 -0
  418. data/test/results/omopv4/icd9/anno_invalid_code +21 -0
  419. data/test/results/omopv4/icd9/crit_1 +54 -0
  420. data/test/results/omopv4/icd9_procedure/crit_1 +5 -0
  421. data/test/results/omopv4/intersect/anno_412_inpatient +42 -0
  422. data/test/results/omopv4/intersect/anno_has_arguments +25 -0
  423. data/test/results/omopv4/intersect/anno_no_upstream +18 -0
  424. data/test/results/omopv4/intersect/crit_412_inpatient +12 -0
  425. data/test/results/omopv4/intersect/crit_412_male +182 -0
  426. data/test/results/omopv4/intersect/crit_complex +118 -0
  427. data/test/results/omopv4/invalid/anno_bad_op +55 -0
  428. data/test/results/omopv4/invalid/scanno_1 +23 -0
  429. data/test/results/omopv4/last/crit_icd9 +42 -0
  430. data/test/results/omopv4/loinc/crit_basic +5 -0
  431. data/test/results/omopv4/ndc/crit_basic +5 -0
  432. data/test/results/omopv4/numeric/anno_multiple_upstreams +59 -0
  433. data/test/results/omopv4/numeric/num_values_1 +254 -0
  434. data/test/results/omopv4/numeric/num_values_2 +5 -0
  435. data/test/results/omopv4/numeric/num_values_3 +5 -0
  436. data/test/results/omopv4/observation_period/anno_has_arguments +36 -0
  437. data/test/results/omopv4/observation_period/anno_multiple_upstreams +51 -0
  438. data/test/results/omopv4/observation_period/count_all_periods +3 -0
  439. data/test/results/omopv4/observation_period/crit_female +2 -0
  440. data/test/results/omopv4/observation_period/crit_icd9 +5 -0
  441. data/test/results/omopv4/observation_period/crit_male +5 -0
  442. data/test/results/omopv4/occurrence/anno_no_upstream +22 -0
  443. data/test/results/omopv4/occurrence/cc_412_410 +1 -0
  444. data/test/results/omopv4/occurrence/count_412_410 +3 -0
  445. data/test/results/omopv4/occurrence/crit_1 +16 -0
  446. data/test/results/omopv4/occurrence/crit_2 +2 -0
  447. data/test/results/omopv4/occurrence/crit_3 +42 -0
  448. data/test/results/omopv4/one_in_two_out/anno_has_arguments +27 -0
  449. data/test/results/omopv4/one_in_two_out/anno_multiple_upstreams +54 -0
  450. data/test/results/omopv4/one_in_two_out/anno_no_upstream +20 -0
  451. data/test/results/omopv4/one_in_two_out/count_1 +3 -0
  452. data/test/results/omopv4/one_in_two_out/crit_hcpcs +7 -0
  453. data/test/results/omopv4/one_in_two_out/crit_icd9 +21 -0
  454. data/test/results/omopv4/overlapped_by/crit_1 +5 -0
  455. data/test/results/omopv4/overlapped_by/crit_2 +2 -0
  456. data/test/results/omopv4/overlapped_by/crit_3 +5 -0
  457. data/test/results/omopv4/overlapped_by/crit_4 +2 -0
  458. data/test/results/omopv4/overlaps/crit_1 +5 -0
  459. data/test/results/omopv4/overlaps/crit_2 +2 -0
  460. data/test/results/omopv4/overlaps/crit_3 +5 -0
  461. data/test/results/omopv4/overlaps/crit_4 +2 -0
  462. data/test/results/omopv4/person/anno_has_arguments +22 -0
  463. data/test/results/omopv4/person/anno_multiple_upstreams +52 -0
  464. data/test/results/omopv4/person/count_2 +3 -0
  465. data/test/results/omopv4/person/crit_1 +42 -0
  466. data/test/results/omopv4/person/crit_2 +1 -0
  467. data/test/results/omopv4/person_filter/count_1 +4 -0
  468. data/test/results/omopv4/person_filter/crit_1 +54 -0
  469. data/test/results/omopv4/person_filter/crit_2 +5 -0
  470. data/test/results/omopv4/person_filter/crit_3 +32 -0
  471. data/test/results/omopv4/person_filter/crit_4 +52 -0
  472. data/test/results/omopv4/person_filter/crit_5 +1 -0
  473. data/test/results/omopv4/place_of_service_code/anno_has_upstreams +37 -0
  474. data/test/results/omopv4/place_of_service_code/anno_no_arguments +18 -0
  475. data/test/results/omopv4/place_of_service_code/crit_basic +174 -0
  476. data/test/results/omopv4/place_of_service_filter/anno_1 +29 -0
  477. data/test/results/omopv4/procedure_occurrence/anno_has_arguments +37 -0
  478. data/test/results/omopv4/procedure_occurrence/anno_multiple_upstreams +51 -0
  479. data/test/results/omopv4/procedure_occurrence/count_gender +3 -0
  480. data/test/results/omopv4/procedure_occurrence/count_icd9 +3 -0
  481. data/test/results/omopv4/procedure_occurrence/count_started_by +3 -0
  482. data/test/results/omopv4/procedure_occurrence/crit_gender +1 -0
  483. data/test/results/omopv4/procedure_occurrence/crit_icd9 +1 -0
  484. data/test/results/omopv4/procedure_occurrence/crit_started_by +1 -0
  485. data/test/results/omopv4/provenance/anno_1 +29 -0
  486. data/test/results/omopv4/provider_filter/anno_1 +29 -0
  487. data/test/results/omopv4/race/anno_1 +37 -0
  488. data/test/results/omopv4/race/anno_2 +18 -0
  489. data/test/results/omopv4/race/crit_1 +28 -0
  490. data/test/results/omopv4/read/anno_1 +21 -0
  491. data/test/results/omopv4/read/crit_1 +2 -0
  492. data/test/results/omopv4/recall/anno_1 +54 -0
  493. data/test/results/omopv4/recall/anno_2 +66 -0
  494. data/test/results/omopv4/recall/anno_3 +20 -0
  495. data/test/results/omopv4/recall/anno_4 +18 -0
  496. data/test/results/omopv4/recall/anno_5 +24 -0
  497. data/test/results/omopv4/recall/anno_6 +270 -0
  498. data/test/results/omopv4/recall/crit_1 +21 -0
  499. data/test/results/omopv4/recall/crit_2 +54 -0
  500. data/test/results/omopv4/recall/crit_3 +2 -0
  501. data/test/results/omopv4/recall/crit_cte_1 +42 -0
  502. data/test/results/omopv4/recall/crit_cte_2 +42 -0
  503. data/test/results/omopv4/recall/crit_nested_perm_0 +54 -0
  504. data/test/results/omopv4/revenue_code/crit_1 +2 -0
  505. data/test/results/omopv4/revenue_code/crit_basic +2 -0
  506. data/test/results/omopv4/revenue_code/domains_1 +3 -0
  507. data/test/results/omopv4/revenue_code/domains_drg100 +3 -0
  508. data/test/results/omopv4/rxnorm/crit_1 +5 -0
  509. data/test/results/omopv4/snomed/crit_1 +84 -0
  510. data/test/results/omopv4/started_by/crit_1 +5 -0
  511. data/test/results/omopv4/started_by/crit_2 +2 -0
  512. data/test/results/omopv4/started_by/crit_3 +2 -0
  513. data/test/results/omopv4/sum/anno_1 +18 -0
  514. data/test/results/omopv4/sum/anno_2 +36 -0
  515. data/test/results/omopv4/sum/num_1 +5 -0
  516. data/test/results/omopv4/sum/num_2 +8 -0
  517. data/test/results/omopv4/sum/num_3 +254 -0
  518. data/test/results/omopv4/time_window/anno_1 +20 -0
  519. data/test/results/omopv4/time_window/anno_2 +40 -0
  520. data/test/results/omopv4/time_window/anno_3 +36 -0
  521. data/test/results/omopv4/time_window/anno_4 +39 -0
  522. data/test/results/omopv4/time_window/anno_5 +57 -0
  523. data/test/results/omopv4/time_window/crit_1 +54 -0
  524. data/test/results/omopv4/time_window/crit_2 +174 -0
  525. data/test/results/omopv4/time_window/crit_3 +54 -0
  526. data/test/results/omopv4/time_window/crit_4 +174 -0
  527. data/test/results/omopv4/trim_date_end/crit_1 +5 -0
  528. data/test/results/omopv4/trim_date_end/crit_2 +2 -0
  529. data/test/results/omopv4/trim_date_end/crit_3 +6 -0
  530. data/test/results/omopv4/trim_date_end/crit_at_least +5 -0
  531. data/test/results/omopv4/trim_date_end/crit_occurrences_1 +2 -0
  532. data/test/results/omopv4/trim_date_end/crit_occurrences_2 +6 -0
  533. data/test/results/omopv4/trim_date_end/crit_within +5 -0
  534. data/test/results/omopv4/trim_date_start/crit_1 +5 -0
  535. data/test/results/omopv4/trim_date_start/crit_2 +2 -0
  536. data/test/results/omopv4/trim_date_start/crit_3 +6 -0
  537. data/test/results/omopv4/trim_date_start/crit_at_least +5 -0
  538. data/test/results/omopv4/trim_date_start/crit_occurrences_1 +2 -0
  539. data/test/results/omopv4/trim_date_start/crit_occurrences_2 +6 -0
  540. data/test/results/omopv4/trim_date_start/crit_within +5 -0
  541. data/test/results/omopv4/union/anno_1 +43 -0
  542. data/test/results/omopv4/union/anno_2 +74 -0
  543. data/test/results/omopv4/union/anno_3 +18 -0
  544. data/test/results/omopv4/union/anno_4 +25 -0
  545. data/test/results/omopv4/union/anno_5 +33 -0
  546. data/test/results/omopv4/union/anno_6 +46 -0
  547. data/test/results/omopv4/union/cc_1 +1 -0
  548. data/test/results/omopv4/union/cc_2 +1 -0
  549. data/test/results/omopv4/union/cc_3 +1 -0
  550. data/test/results/omopv4/union/cc_4 +1 -0
  551. data/test/results/omopv4/union/cc_5 +1 -0
  552. data/test/results/omopv4/union/count_1 +3 -0
  553. data/test/results/omopv4/union/count_2 +3 -0
  554. data/test/results/omopv4/union/count_3 +3 -0
  555. data/test/results/omopv4/union/count_4 +3 -0
  556. data/test/results/omopv4/union/count_5 +4 -0
  557. data/test/results/omopv4/union/scanno_1 +22 -0
  558. data/test/results/omopv4/union/scanno_2 +36 -0
  559. data/test/results/omopv4/visit_occurrence/anno_1 +52 -0
  560. data/test/results/omopv4/visit_occurrence/anno_2 +37 -0
  561. data/test/results/omopv4/visit_occurrence/crit_1 +54 -0
  562. data/test/results/omopv4/visit_occurrence/crit_2 +7566 -0
  563. data/test/results/omopv4/visit_occurrence/crit_3 +14935 -0
  564. data/test/results/omopv4_plus/after/anno_1 +25 -0
  565. data/test/results/omopv4_plus/after/anno_2 +48 -0
  566. data/test/results/omopv4_plus/after/anno_3 +34 -0
  567. data/test/results/omopv4_plus/after/anno_4 +60 -0
  568. data/test/results/omopv4_plus/after/anno_5 +68 -0
  569. data/test/results/omopv4_plus/after/anno_6 +60 -0
  570. data/test/results/omopv4_plus/after/crit_at_least +7 -0
  571. data/test/results/omopv4_plus/after/crit_basic +32 -0
  572. data/test/results/omopv4_plus/after/crit_occurrences +12 -0
  573. data/test/results/omopv4_plus/after/crit_within +5 -0
  574. data/test/results/omopv4_plus/any_overlap/crit_basic1 +14 -0
  575. data/test/results/omopv4_plus/any_overlap/crit_basic2 +14 -0
  576. data/test/results/omopv4_plus/any_overlap/crit_occurrences1 +2 -0
  577. data/test/results/omopv4_plus/any_overlap/crit_occurrences2 +14 -0
  578. data/test/results/omopv4_plus/any_overlap/crit_within +8 -0
  579. data/test/results/omopv4_plus/before/crit_at_least +6 -0
  580. data/test/results/omopv4_plus/before/crit_basic1 +48 -0
  581. data/test/results/omopv4_plus/before/crit_basic2 +8 -0
  582. data/test/results/omopv4_plus/before/crit_occurrences +13 -0
  583. data/test/results/omopv4_plus/before/crit_within +17 -0
  584. data/test/results/omopv4_plus/co_reported/anno_1 +43 -0
  585. data/test/results/omopv4_plus/co_reported/anno_2 +66 -0
  586. data/test/results/omopv4_plus/co_reported/anno_3 +47 -0
  587. data/test/results/omopv4_plus/complement/anno_duplicate_params +52 -0
  588. data/test/results/omopv4_plus/complement/anno_invalid_params +37 -0
  589. data/test/results/omopv4_plus/complement/anno_no_params +18 -0
  590. data/test/results/omopv4_plus/complement/count_3way_intersect +4 -0
  591. data/test/results/omopv4_plus/complement/count_3way_union +4 -0
  592. data/test/results/omopv4_plus/complement/count_intersect +3 -0
  593. data/test/results/omopv4_plus/complement/count_union +3 -0
  594. data/test/results/omopv4_plus/complement/count_union_and_intersect +4 -0
  595. data/test/results/omopv4_plus/complement/crit_basic1 +52483 -0
  596. data/test/results/omopv4_plus/complement/crit_icd9_selector +52 -0
  597. data/test/results/omopv4_plus/complex/anno_1 +85 -0
  598. data/test/results/omopv4_plus/complex/crit_1 +2 -0
  599. data/test/results/omopv4_plus/complex/crit_2 +2 -0
  600. data/test/results/omopv4_plus/complex/crit_3 +2 -0
  601. data/test/results/omopv4_plus/complex/crit_4 +2 -0
  602. data/test/results/omopv4_plus/complex/crit_5 +2 -0
  603. data/test/results/omopv4_plus/complex/crit_6 +24 -0
  604. data/test/results/omopv4_plus/complex/crit_7 +45 -0
  605. data/test/results/omopv4_plus/complex/crit_out_of_order_ctes +15 -0
  606. data/test/results/omopv4_plus/complex/scanno_1 +108 -0
  607. data/test/results/omopv4_plus/concurrent_within/crit_icd9 +52 -0
  608. data/test/results/omopv4_plus/concurrent_within/crit_icd9_and_place_of_service +21 -0
  609. data/test/results/omopv4_plus/concurrent_within/crit_negative_start +5 -0
  610. data/test/results/omopv4_plus/condition_type/anno_icd9 +39 -0
  611. data/test/results/omopv4_plus/condition_type/count_condition_era +2 -0
  612. data/test/results/omopv4_plus/condition_type/count_condition_era_30_day_window +2 -0
  613. data/test/results/omopv4_plus/condition_type/count_ehr_problem_list +2 -0
  614. data/test/results/omopv4_plus/condition_type/count_era_0 +2 -0
  615. data/test/results/omopv4_plus/condition_type/count_inpatient +3 -0
  616. data/test/results/omopv4_plus/condition_type/count_inpatient_detail +2 -0
  617. data/test/results/omopv4_plus/condition_type/count_inpatient_header +3 -0
  618. data/test/results/omopv4_plus/condition_type/count_inpatient_header_2 +3 -0
  619. data/test/results/omopv4_plus/condition_type/count_inpatient_header_3 +3 -0
  620. data/test/results/omopv4_plus/condition_type/count_inpatient_header_4 +3 -0
  621. data/test/results/omopv4_plus/condition_type/count_inpatient_header_5 +3 -0
  622. data/test/results/omopv4_plus/condition_type/count_inpatient_outpatient_detail +3 -0
  623. data/test/results/omopv4_plus/condition_type/count_inpatient_primary +3 -0
  624. data/test/results/omopv4_plus/condition_type/count_inpatient_primary_or_first +3 -0
  625. data/test/results/omopv4_plus/condition_type/count_outpatient +3 -0
  626. data/test/results/omopv4_plus/condition_type/count_outpatient_detail +2 -0
  627. data/test/results/omopv4_plus/condition_type/count_outpatient_header +3 -0
  628. data/test/results/omopv4_plus/condition_type/count_outpatient_primary +3 -0
  629. data/test/results/omopv4_plus/condition_type/count_primary +3 -0
  630. data/test/results/omopv4_plus/contains/crit_1 +5 -0
  631. data/test/results/omopv4_plus/contains/crit_2 +2 -0
  632. data/test/results/omopv4_plus/contains/crit_3 +2 -0
  633. data/test/results/omopv4_plus/count/anno_multiple_upstreams +52 -0
  634. data/test/results/omopv4_plus/count/anno_no_upstream1 +18 -0
  635. data/test/results/omopv4_plus/count/anno_no_upstream2 +25 -0
  636. data/test/results/omopv4_plus/count/crit_icd9_ndc +5 -0
  637. data/test/results/omopv4_plus/count/crit_ndc +2 -0
  638. data/test/results/omopv4_plus/count/crit_person +254 -0
  639. data/test/results/omopv4_plus/cpt/anno_icd9_upstream +40 -0
  640. data/test/results/omopv4_plus/cpt/anno_invalid_code +22 -0
  641. data/test/results/omopv4_plus/cpt/count_1 +3 -0
  642. data/test/results/omopv4_plus/cpt/crit_1 +158 -0
  643. data/test/results/omopv4_plus/cpt/scanno_1 +17 -0
  644. data/test/results/omopv4_plus/cpt_or_hcpcs/anno_bad_format +25 -0
  645. data/test/results/omopv4_plus/cpt_or_hcpcs/count_1 +3 -0
  646. data/test/results/omopv4_plus/cpt_or_hcpcs/crit_1 +161 -0
  647. data/test/results/omopv4_plus/date_range/anno_1 +15 -0
  648. data/test/results/omopv4_plus/date_range/anno_extra_argument +24 -0
  649. data/test/results/omopv4_plus/date_range/anno_invalid_argument +25 -0
  650. data/test/results/omopv4_plus/date_range/anno_missing_argument1 +20 -0
  651. data/test/results/omopv4_plus/date_range/anno_missing_argument2 +20 -0
  652. data/test/results/omopv4_plus/date_range/anno_no_upstreams +38 -0
  653. data/test/results/omopv4_plus/date_range/count_1 +3 -0
  654. data/test/results/omopv4_plus/date_range/count_2 +3 -0
  655. data/test/results/omopv4_plus/death/anno_multiple_upstreams +50 -0
  656. data/test/results/omopv4_plus/death/anno_no_upstreams +22 -0
  657. data/test/results/omopv4_plus/death/crit_basic +14 -0
  658. data/test/results/omopv4_plus/death/crit_person +14 -0
  659. data/test/results/omopv4_plus/drug_type_concept/anno_has_upstreams +37 -0
  660. data/test/results/omopv4_plus/drug_type_concept/anno_no_arguments +18 -0
  661. data/test/results/omopv4_plus/drug_type_concept/crit_basic1 +2 -0
  662. data/test/results/omopv4_plus/drug_type_concept/crit_basic2 +2 -0
  663. data/test/results/omopv4_plus/during/crit_1 +14 -0
  664. data/test/results/omopv4_plus/during/crit_2 +2 -0
  665. data/test/results/omopv4_plus/equal/crit_1 +2 -0
  666. data/test/results/omopv4_plus/equal/crit_2 +2 -0
  667. data/test/results/omopv4_plus/except/anno_1 +42 -0
  668. data/test/results/omopv4_plus/except/anno_2 +43 -0
  669. data/test/results/omopv4_plus/except/count_complex +5 -0
  670. data/test/results/omopv4_plus/except/crit_412_cpt +52 -0
  671. data/test/results/omopv4_plus/except/crit_412_inpatient +45 -0
  672. data/test/results/omopv4_plus/filter/crit_1 +52 -0
  673. data/test/results/omopv4_plus/first/anno_argument +25 -0
  674. data/test/results/omopv4_plus/first/anno_no_upstream +18 -0
  675. data/test/results/omopv4_plus/first/crit_cpt +180 -0
  676. data/test/results/omopv4_plus/first/crit_icd9 +41 -0
  677. data/test/results/omopv4_plus/first/crit_union +52 -0
  678. data/test/results/omopv4_plus/from/anno_has_upstreams +39 -0
  679. data/test/results/omopv4_plus/from/anno_multiple_arguments +24 -0
  680. data/test/results/omopv4_plus/from/count_condition_occurrence +3 -0
  681. data/test/results/omopv4_plus/from/count_observation_period +3 -0
  682. data/test/results/omopv4_plus/from/count_person +3 -0
  683. data/test/results/omopv4_plus/from_seer_visits/anno_multiple_upstreams +78 -0
  684. data/test/results/omopv4_plus/from_seer_visits/anno_no_upstream +18 -0
  685. data/test/results/omopv4_plus/from_seer_visits/crit_1 +2 -0
  686. data/test/results/omopv4_plus/from_seer_visits/crit_2 +2 -0
  687. data/test/results/omopv4_plus/from_seer_visits/crit_3 +2 -0
  688. data/test/results/omopv4_plus/from_seer_visits/crit_4 +2 -0
  689. data/test/results/omopv4_plus/gender/anno_has_upstreams +39 -0
  690. data/test/results/omopv4_plus/gender/crit_male +128 -0
  691. data/test/results/omopv4_plus/hcpcs/anno_bad_format +24 -0
  692. data/test/results/omopv4_plus/hcpcs/crit_A0382 +7 -0
  693. data/test/results/omopv4_plus/icd10/anno_bad_format +22 -0
  694. data/test/results/omopv4_plus/icd10/anno_has_upstreams +40 -0
  695. data/test/results/omopv4_plus/icd10/crit_1 +2 -0
  696. data/test/results/omopv4_plus/icd10pcs/anno_bad_format +28 -0
  697. data/test/results/omopv4_plus/icd10pcs/anno_has_upstreams +40 -0
  698. data/test/results/omopv4_plus/icd10pcs/crit_1 +2 -0
  699. data/test/results/omopv4_plus/icd9/anno_empty_label +15 -0
  700. data/test/results/omopv4_plus/icd9/anno_invalid_code +21 -0
  701. data/test/results/omopv4_plus/icd9/anno_valid_code +3 -0
  702. data/test/results/omopv4_plus/icd9/crit_1 +52 -0
  703. data/test/results/omopv4_plus/icd9_procedure/crit_1 +5 -0
  704. data/test/results/omopv4_plus/intersect/anno_412_inpatient +42 -0
  705. data/test/results/omopv4_plus/intersect/anno_has_arguments +25 -0
  706. data/test/results/omopv4_plus/intersect/anno_no_upstream +18 -0
  707. data/test/results/omopv4_plus/intersect/crit_412_inpatient +11 -0
  708. data/test/results/omopv4_plus/intersect/crit_412_male +178 -0
  709. data/test/results/omopv4_plus/intersect/crit_complex +110 -0
  710. data/test/results/omopv4_plus/invalid/anno_bad_op +55 -0
  711. data/test/results/omopv4_plus/invalid/scanno_1 +23 -0
  712. data/test/results/omopv4_plus/last/crit_icd9 +41 -0
  713. data/test/results/omopv4_plus/loinc/crit_basic +2 -0
  714. data/test/results/omopv4_plus/ndc/crit_basic +2 -0
  715. data/test/results/omopv4_plus/ndc/results_1 +41 -0
  716. data/test/results/omopv4_plus/numeric/anno_multiple_upstreams +59 -0
  717. data/test/results/omopv4_plus/numeric/num_values_1 +254 -0
  718. data/test/results/omopv4_plus/numeric/num_values_2 +5 -0
  719. data/test/results/omopv4_plus/numeric/num_values_3 +5 -0
  720. data/test/results/omopv4_plus/observation_period/anno_has_arguments +36 -0
  721. data/test/results/omopv4_plus/observation_period/anno_multiple_upstreams +51 -0
  722. data/test/results/omopv4_plus/observation_period/count_all_periods +3 -0
  723. data/test/results/omopv4_plus/observation_period/crit_female +87 -0
  724. data/test/results/omopv4_plus/observation_period/crit_icd9 +28 -0
  725. data/test/results/omopv4_plus/observation_period/crit_male +75 -0
  726. data/test/results/omopv4_plus/occurrence/anno_no_upstream +22 -0
  727. data/test/results/omopv4_plus/occurrence/count_412_410 +3 -0
  728. data/test/results/omopv4_plus/occurrence/crit_1 +15 -0
  729. data/test/results/omopv4_plus/occurrence/crit_2 +2 -0
  730. data/test/results/omopv4_plus/occurrence/crit_3 +41 -0
  731. data/test/results/omopv4_plus/one_in_two_out/anno_has_arguments +27 -0
  732. data/test/results/omopv4_plus/one_in_two_out/anno_multiple_upstreams +54 -0
  733. data/test/results/omopv4_plus/one_in_two_out/anno_no_upstream +20 -0
  734. data/test/results/omopv4_plus/one_in_two_out/count_1 +3 -0
  735. data/test/results/omopv4_plus/one_in_two_out/count_same_as_1 +3 -0
  736. data/test/results/omopv4_plus/one_in_two_out/crit_hcpcs +2 -0
  737. data/test/results/omopv4_plus/one_in_two_out/crit_icd9 +19 -0
  738. data/test/results/omopv4_plus/one_in_two_out/results_1 +803 -0
  739. data/test/results/omopv4_plus/one_in_two_out/results_2 +803 -0
  740. data/test/results/omopv4_plus/overlapped_by/crit_1 +5 -0
  741. data/test/results/omopv4_plus/overlapped_by/crit_2 +2 -0
  742. data/test/results/omopv4_plus/overlapped_by/crit_3 +5 -0
  743. data/test/results/omopv4_plus/overlapped_by/crit_4 +2 -0
  744. data/test/results/omopv4_plus/overlaps/crit_1 +5 -0
  745. data/test/results/omopv4_plus/overlaps/crit_2 +2 -0
  746. data/test/results/omopv4_plus/overlaps/crit_3 +5 -0
  747. data/test/results/omopv4_plus/overlaps/crit_4 +2 -0
  748. data/test/results/omopv4_plus/person/anno_has_arguments +22 -0
  749. data/test/results/omopv4_plus/person/anno_multiple_upstreams +52 -0
  750. data/test/results/omopv4_plus/person/count_2 +3 -0
  751. data/test/results/omopv4_plus/person/crit_1 +41 -0
  752. data/test/results/omopv4_plus/person_filter/count_1 +4 -0
  753. data/test/results/omopv4_plus/person_filter/crit_1 +52 -0
  754. data/test/results/omopv4_plus/person_filter/crit_2 +10 -0
  755. data/test/results/omopv4_plus/person_filter/crit_3 +32 -0
  756. data/test/results/omopv4_plus/person_filter/crit_4 +50 -0
  757. data/test/results/omopv4_plus/place_of_service_code/anno_has_upstreams +37 -0
  758. data/test/results/omopv4_plus/place_of_service_code/anno_no_arguments +18 -0
  759. data/test/results/omopv4_plus/place_of_service_code/crit_basic +157 -0
  760. data/test/results/omopv4_plus/place_of_service_filter/anno_1 +29 -0
  761. data/test/results/omopv4_plus/procedure_occurrence/anno_has_arguments +37 -0
  762. data/test/results/omopv4_plus/procedure_occurrence/anno_multiple_upstreams +51 -0
  763. data/test/results/omopv4_plus/procedure_occurrence/count_gender +3 -0
  764. data/test/results/omopv4_plus/procedure_occurrence/count_icd9 +3 -0
  765. data/test/results/omopv4_plus/procedure_occurrence/count_started_by +3 -0
  766. data/test/results/omopv4_plus/provenance/anno_1 +29 -0
  767. data/test/results/omopv4_plus/provenance/anno_bad_keyword +38 -0
  768. data/test/results/omopv4_plus/provenance/count_1 +3 -0
  769. data/test/results/omopv4_plus/provenance/count_2 +3 -0
  770. data/test/results/omopv4_plus/provider_filter/anno_1 +29 -0
  771. data/test/results/omopv4_plus/race/anno_1 +37 -0
  772. data/test/results/omopv4_plus/race/anno_2 +18 -0
  773. data/test/results/omopv4_plus/race/crit_1 +32 -0
  774. data/test/results/omopv4_plus/read/anno_1 +15 -0
  775. data/test/results/omopv4_plus/read/crit_1 +2 -0
  776. data/test/results/omopv4_plus/recall/anno_1 +54 -0
  777. data/test/results/omopv4_plus/recall/anno_2 +66 -0
  778. data/test/results/omopv4_plus/recall/anno_3 +20 -0
  779. data/test/results/omopv4_plus/recall/anno_4 +18 -0
  780. data/test/results/omopv4_plus/recall/anno_5 +24 -0
  781. data/test/results/omopv4_plus/recall/anno_6 +270 -0
  782. data/test/results/omopv4_plus/recall/crit_1 +19 -0
  783. data/test/results/omopv4_plus/recall/crit_2 +52 -0
  784. data/test/results/omopv4_plus/recall/crit_3 +2 -0
  785. data/test/results/omopv4_plus/recall/crit_cte_1 +41 -0
  786. data/test/results/omopv4_plus/recall/crit_cte_2 +41 -0
  787. data/test/results/omopv4_plus/recall/crit_nested_perm_0 +52 -0
  788. data/test/results/omopv4_plus/revenue_code/crit_1 +2 -0
  789. data/test/results/omopv4_plus/revenue_code/crit_basic +2 -0
  790. data/test/results/omopv4_plus/revenue_code/domains_1 +3 -0
  791. data/test/results/omopv4_plus/revenue_code/domains_drg100 +3 -0
  792. data/test/results/omopv4_plus/rxnorm/crit_1 +2 -0
  793. data/test/results/omopv4_plus/snomed/crit_1 +2 -0
  794. data/test/results/omopv4_plus/started_by/crit_1 +5 -0
  795. data/test/results/omopv4_plus/started_by/crit_2 +2 -0
  796. data/test/results/omopv4_plus/started_by/crit_3 +2 -0
  797. data/test/results/omopv4_plus/sum/anno_1 +18 -0
  798. data/test/results/omopv4_plus/sum/anno_2 +36 -0
  799. data/test/results/omopv4_plus/sum/num_1 +2 -0
  800. data/test/results/omopv4_plus/sum/num_2 +5 -0
  801. data/test/results/omopv4_plus/sum/num_3 +254 -0
  802. data/test/results/omopv4_plus/time_window/anno_1 +20 -0
  803. data/test/results/omopv4_plus/time_window/anno_2 +40 -0
  804. data/test/results/omopv4_plus/time_window/anno_3 +36 -0
  805. data/test/results/omopv4_plus/time_window/anno_4 +39 -0
  806. data/test/results/omopv4_plus/time_window/anno_5 +57 -0
  807. data/test/results/omopv4_plus/time_window/crit_1 +52 -0
  808. data/test/results/omopv4_plus/time_window/crit_2 +157 -0
  809. data/test/results/omopv4_plus/time_window/crit_3 +52 -0
  810. data/test/results/omopv4_plus/time_window/crit_4 +157 -0
  811. data/test/results/omopv4_plus/trim_date_end/crit_1 +5 -0
  812. data/test/results/omopv4_plus/trim_date_end/crit_2 +2 -0
  813. data/test/results/omopv4_plus/trim_date_end/crit_3 +6 -0
  814. data/test/results/omopv4_plus/trim_date_end/crit_at_least +5 -0
  815. data/test/results/omopv4_plus/trim_date_end/crit_occurrences_1 +2 -0
  816. data/test/results/omopv4_plus/trim_date_end/crit_occurrences_2 +6 -0
  817. data/test/results/omopv4_plus/trim_date_end/crit_within +5 -0
  818. data/test/results/omopv4_plus/trim_date_start/crit_1 +5 -0
  819. data/test/results/omopv4_plus/trim_date_start/crit_2 +2 -0
  820. data/test/results/omopv4_plus/trim_date_start/crit_3 +6 -0
  821. data/test/results/omopv4_plus/trim_date_start/crit_at_least +5 -0
  822. data/test/results/omopv4_plus/trim_date_start/crit_occurrences_1 +2 -0
  823. data/test/results/omopv4_plus/trim_date_start/crit_occurrences_2 +6 -0
  824. data/test/results/omopv4_plus/trim_date_start/crit_within +5 -0
  825. data/test/results/omopv4_plus/union/anno_1 +43 -0
  826. data/test/results/omopv4_plus/union/anno_2 +74 -0
  827. data/test/results/omopv4_plus/union/anno_3 +18 -0
  828. data/test/results/omopv4_plus/union/anno_4 +25 -0
  829. data/test/results/omopv4_plus/union/anno_5 +33 -0
  830. data/test/results/omopv4_plus/union/anno_6 +46 -0
  831. data/test/results/omopv4_plus/union/count_1 +3 -0
  832. data/test/results/omopv4_plus/union/count_2 +3 -0
  833. data/test/results/omopv4_plus/union/count_3 +3 -0
  834. data/test/results/omopv4_plus/union/count_4 +3 -0
  835. data/test/results/omopv4_plus/union/count_5 +4 -0
  836. data/test/results/omopv4_plus/union/optcc_1 +3 -0
  837. data/test/results/omopv4_plus/union/optcc_2 +3 -0
  838. data/test/results/omopv4_plus/union/optcc_3 +3 -0
  839. data/test/results/omopv4_plus/union/optcc_4 +3 -0
  840. data/test/results/omopv4_plus/union/optcc_5 +3 -0
  841. data/test/results/omopv4_plus/union/optcc_6 +3 -0
  842. data/test/results/omopv4_plus/union/scanno_1 +22 -0
  843. data/test/results/omopv4_plus/union/scanno_2 +36 -0
  844. data/test/results/omopv4_plus/visit_occurrence/anno_1 +52 -0
  845. data/test/results/omopv4_plus/visit_occurrence/anno_2 +37 -0
  846. data/test/results/omopv4_plus/visit_occurrence/crit_1 +52 -0
  847. data/test/results/omopv4_plus/visit_occurrence/crit_2 +22945 -0
  848. data/test/results/omopv4_plus/visit_occurrence/crit_3 +46851 -0
  849. data/test/statements/after/anno_1 +7 -0
  850. data/test/statements/after/anno_2 +16 -0
  851. data/test/statements/after/anno_3 +9 -0
  852. data/test/statements/after/anno_4 +19 -0
  853. data/test/statements/after/anno_5 +21 -0
  854. data/test/statements/after/anno_6 +16 -0
  855. data/test/statements/after/crit_at_least +21 -0
  856. data/test/statements/after/crit_basic +20 -0
  857. data/test/statements/after/crit_occurrences +21 -0
  858. data/test/statements/after/crit_within +21 -0
  859. data/test/statements/any_overlap/crit_basic1 +16 -0
  860. data/test/statements/any_overlap/crit_basic2 +16 -0
  861. data/test/statements/any_overlap/crit_occurrences1 +17 -0
  862. data/test/statements/any_overlap/crit_occurrences2 +17 -0
  863. data/test/statements/any_overlap/crit_within +17 -0
  864. data/test/statements/before/crit_at_least +14 -0
  865. data/test/statements/before/crit_basic1 +13 -0
  866. data/test/statements/before/crit_basic2 +16 -0
  867. data/test/statements/before/crit_occurrences +14 -0
  868. data/test/statements/before/crit_within +14 -0
  869. data/test/statements/co_reported/anno_1 +13 -0
  870. data/test/statements/co_reported/anno_2 +21 -0
  871. data/test/statements/co_reported/anno_3 +14 -0
  872. data/test/statements/complement/anno_duplicate_params +11 -0
  873. data/test/statements/complement/anno_invalid_params +8 -0
  874. data/test/statements/complement/anno_no_params +3 -0
  875. data/test/statements/complement/count_3way_intersect +24 -0
  876. data/test/statements/complement/count_3way_union +18 -0
  877. data/test/statements/complement/count_intersect +17 -0
  878. data/test/statements/complement/count_union +14 -0
  879. data/test/statements/complement/count_union_and_intersect +27 -0
  880. data/test/statements/complement/crit_basic1 +7 -0
  881. data/test/statements/complement/crit_icd9_selector +10 -0
  882. data/test/statements/complex/anno_1 +29 -0
  883. data/test/statements/complex/crit_1 +278 -0
  884. data/test/statements/complex/crit_2 +43 -0
  885. data/test/statements/complex/crit_3 +54 -0
  886. data/test/statements/complex/crit_4 +17 -0
  887. data/test/statements/complex/crit_5 +17 -0
  888. data/test/statements/complex/crit_6 +20 -0
  889. data/test/statements/complex/crit_7 +14 -0
  890. data/test/statements/complex/crit_out_of_order_ctes +39 -0
  891. data/test/statements/complex/scanno_1 +1508 -0
  892. data/test/statements/concurrent_within/crit_icd9 +11 -0
  893. data/test/statements/concurrent_within/crit_icd9_and_place_of_service +15 -0
  894. data/test/statements/concurrent_within/crit_negative_start +15 -0
  895. data/test/statements/condition_type/anno_icd9 +7 -0
  896. data/test/statements/condition_type/count_condition_era +4 -0
  897. data/test/statements/condition_type/count_condition_era_30_day_window +4 -0
  898. data/test/statements/condition_type/count_ehr_problem_list +4 -0
  899. data/test/statements/condition_type/count_era_0 +4 -0
  900. data/test/statements/condition_type/count_inpatient +4 -0
  901. data/test/statements/condition_type/count_inpatient_detail +4 -0
  902. data/test/statements/condition_type/count_inpatient_header +4 -0
  903. data/test/statements/condition_type/count_inpatient_header_2 +4 -0
  904. data/test/statements/condition_type/count_inpatient_header_3 +4 -0
  905. data/test/statements/condition_type/count_inpatient_header_4 +4 -0
  906. data/test/statements/condition_type/count_inpatient_header_5 +4 -0
  907. data/test/statements/condition_type/count_inpatient_outpatient_detail +5 -0
  908. data/test/statements/condition_type/count_inpatient_primary +4 -0
  909. data/test/statements/condition_type/count_inpatient_primary_or_first +4 -0
  910. data/test/statements/condition_type/count_outpatient +4 -0
  911. data/test/statements/condition_type/count_outpatient_detail +4 -0
  912. data/test/statements/condition_type/count_outpatient_header +4 -0
  913. data/test/statements/condition_type/count_outpatient_primary +4 -0
  914. data/test/statements/condition_type/count_primary +4 -0
  915. data/test/statements/contains/crit_1 +16 -0
  916. data/test/statements/contains/crit_2 +16 -0
  917. data/test/statements/contains/crit_3 +16 -0
  918. data/test/statements/count/anno_multiple_upstreams +11 -0
  919. data/test/statements/count/anno_no_upstream1 +3 -0
  920. data/test/statements/count/anno_no_upstream2 +4 -0
  921. data/test/statements/count/crit_icd9_ndc +15 -0
  922. data/test/statements/count/crit_ndc +11 -0
  923. data/test/statements/count/crit_person +7 -0
  924. data/test/statements/cpt/anno_icd9_upstream +7 -0
  925. data/test/statements/cpt/anno_invalid_code +5 -0
  926. data/test/statements/cpt/count_1 +4 -0
  927. data/test/statements/cpt/crit_1 +4 -0
  928. data/test/statements/cpt/scanno_1 +4 -0
  929. data/test/statements/cpt_or_hcpcs/anno_bad_format +7 -0
  930. data/test/statements/cpt_or_hcpcs/count_1 +5 -0
  931. data/test/statements/cpt_or_hcpcs/crit_1 +5 -0
  932. data/test/statements/date_range/anno_1 +7 -0
  933. data/test/statements/date_range/anno_extra_argument +8 -0
  934. data/test/statements/date_range/anno_invalid_argument +7 -0
  935. data/test/statements/date_range/anno_missing_argument1 +6 -0
  936. data/test/statements/date_range/anno_missing_argument2 +6 -0
  937. data/test/statements/date_range/anno_no_upstreams +11 -0
  938. data/test/statements/date_range/count_1 +7 -0
  939. data/test/statements/date_range/count_2 +7 -0
  940. data/test/statements/death/anno_multiple_upstreams +10 -0
  941. data/test/statements/death/anno_no_upstreams +4 -0
  942. data/test/statements/death/crit_basic +3 -0
  943. data/test/statements/death/crit_person +7 -0
  944. data/test/statements/drug_type_concept/anno_has_upstreams +8 -0
  945. data/test/statements/drug_type_concept/anno_no_arguments +3 -0
  946. data/test/statements/drug_type_concept/crit_basic1 +4 -0
  947. data/test/statements/drug_type_concept/crit_basic2 +4 -0
  948. data/test/statements/during/crit_1 +16 -0
  949. data/test/statements/during/crit_2 +16 -0
  950. data/test/statements/equal/crit_1 +17 -0
  951. data/test/statements/equal/crit_2 +21 -0
  952. data/test/statements/except/anno_1 +13 -0
  953. data/test/statements/except/anno_2 +14 -0
  954. data/test/statements/except/count_complex +31 -0
  955. data/test/statements/except/crit_412_cpt +13 -0
  956. data/test/statements/except/crit_412_inpatient +13 -0
  957. data/test/statements/filter/crit_1 +15 -0
  958. data/test/statements/first/anno_argument +4 -0
  959. data/test/statements/first/anno_no_upstream +3 -0
  960. data/test/statements/first/crit_cpt +7 -0
  961. data/test/statements/first/crit_icd9 +7 -0
  962. data/test/statements/first/crit_union +14 -0
  963. data/test/statements/from/anno_has_upstreams +7 -0
  964. data/test/statements/from/anno_multiple_arguments +5 -0
  965. data/test/statements/from_seer_visits/anno_multiple_upstreams +17 -0
  966. data/test/statements/from_seer_visits/anno_no_upstream +3 -0
  967. data/test/statements/from_seer_visits/crit_1 +10 -0
  968. data/test/statements/from_seer_visits/crit_2 +11 -0
  969. data/test/statements/from_seer_visits/crit_3 +11 -0
  970. data/test/statements/from_seer_visits/crit_4 +12 -0
  971. data/test/statements/gender/anno_has_upstreams +7 -0
  972. data/test/statements/gender/crit_male +4 -0
  973. data/test/statements/hcpcs/anno_bad_format +6 -0
  974. data/test/statements/hcpcs/crit_A0382 +4 -0
  975. data/test/statements/icd10/anno_bad_format +5 -0
  976. data/test/statements/icd10/anno_has_upstreams +7 -0
  977. data/test/statements/icd10/crit_1 +4 -0
  978. data/test/statements/icd10pcs/anno_bad_format +6 -0
  979. data/test/statements/icd10pcs/anno_has_upstreams +7 -0
  980. data/test/statements/icd10pcs/crit_1 +4 -0
  981. data/test/statements/icd9/anno_empty_label +7 -0
  982. data/test/statements/icd9/anno_invalid_code +4 -0
  983. data/test/statements/icd9/anno_valid_code +4 -0
  984. data/test/statements/icd9/crit_1 +4 -0
  985. data/test/statements/icd9_procedure/crit_1 +4 -0
  986. data/test/statements/intersect/anno_412_inpatient +11 -0
  987. data/test/statements/intersect/anno_has_arguments +4 -0
  988. data/test/statements/intersect/anno_no_upstream +3 -0
  989. data/test/statements/intersect/crit_412_inpatient +11 -0
  990. data/test/statements/intersect/crit_412_male +11 -0
  991. data/test/statements/intersect/crit_complex +19 -0
  992. data/test/statements/invalid/anno_bad_op +13 -0
  993. data/test/statements/invalid/scanno_1 +7 -0
  994. data/test/statements/last/crit_icd9 +7 -0
  995. data/test/statements/loinc/crit_basic +4 -0
  996. data/test/statements/ndc/crit_basic +4 -0
  997. data/test/statements/ndc/results_1 +4 -0
  998. data/test/statements/numeric/anno_multiple_upstreams +11 -0
  999. data/test/statements/numeric/num_values_1 +4 -0
  1000. data/test/statements/numeric/num_values_2 +8 -0
  1001. data/test/statements/numeric/num_values_3 +8 -0
  1002. data/test/statements/observation_period/anno_has_arguments +8 -0
  1003. data/test/statements/observation_period/anno_multiple_upstreams +11 -0
  1004. data/test/statements/observation_period/count_all_periods +4 -0
  1005. data/test/statements/observation_period/crit_female +7 -0
  1006. data/test/statements/observation_period/crit_icd9 +7 -0
  1007. data/test/statements/observation_period/crit_male +7 -0
  1008. data/test/statements/occurrence/anno_no_upstream +3 -0
  1009. data/test/statements/occurrence/count_412_410 +17 -0
  1010. data/test/statements/occurrence/crit_1 +8 -0
  1011. data/test/statements/occurrence/crit_2 +11 -0
  1012. data/test/statements/occurrence/crit_3 +11 -0
  1013. data/test/statements/one_in_two_out/anno_has_arguments +8 -0
  1014. data/test/statements/one_in_two_out/anno_multiple_upstreams +15 -0
  1015. data/test/statements/one_in_two_out/anno_no_upstream +7 -0
  1016. data/test/statements/one_in_two_out/count_1 +10 -0
  1017. data/test/statements/one_in_two_out/count_same_as_1 +11 -0
  1018. data/test/statements/one_in_two_out/crit_hcpcs +10 -0
  1019. data/test/statements/one_in_two_out/crit_icd9 +11 -0
  1020. data/test/statements/one_in_two_out/results_1 +9 -0
  1021. data/test/statements/one_in_two_out/results_2 +9 -0
  1022. data/test/statements/overlapped_by/crit_1 +16 -0
  1023. data/test/statements/overlapped_by/crit_2 +16 -0
  1024. data/test/statements/overlapped_by/crit_3 +16 -0
  1025. data/test/statements/overlapped_by/crit_4 +16 -0
  1026. data/test/statements/overlaps/crit_1 +16 -0
  1027. data/test/statements/overlaps/crit_2 +16 -0
  1028. data/test/statements/overlaps/crit_3 +16 -0
  1029. data/test/statements/overlaps/crit_4 +16 -0
  1030. data/test/statements/person/anno_has_arguments +4 -0
  1031. data/test/statements/person/anno_multiple_upstreams +11 -0
  1032. data/test/statements/person/count_2 +3 -0
  1033. data/test/statements/person/crit_1 +7 -0
  1034. data/test/statements/person_filter/count_1 +20 -0
  1035. data/test/statements/person_filter/crit_1 +20 -0
  1036. data/test/statements/person_filter/crit_2 +13 -0
  1037. data/test/statements/person_filter/crit_3 +13 -0
  1038. data/test/statements/person_filter/crit_4 +13 -0
  1039. data/test/statements/place_of_service_code/anno_has_upstreams +8 -0
  1040. data/test/statements/place_of_service_code/anno_no_arguments +3 -0
  1041. data/test/statements/place_of_service_code/crit_basic +4 -0
  1042. data/test/statements/place_of_service_filter/anno_1 +8 -0
  1043. data/test/statements/procedure_occurrence/anno_has_arguments +8 -0
  1044. data/test/statements/procedure_occurrence/anno_multiple_upstreams +11 -0
  1045. data/test/statements/procedure_occurrence/count_gender +7 -0
  1046. data/test/statements/procedure_occurrence/count_icd9 +7 -0
  1047. data/test/statements/procedure_occurrence/count_started_by +19 -0
  1048. data/test/statements/provenance/anno_1 +8 -0
  1049. data/test/statements/provenance/anno_bad_keyword +10 -0
  1050. data/test/statements/provenance/count_1 +8 -0
  1051. data/test/statements/provenance/count_2 +8 -0
  1052. data/test/statements/provider_filter/anno_1 +10 -0
  1053. data/test/statements/race/anno_1 +8 -0
  1054. data/test/statements/race/anno_2 +3 -0
  1055. data/test/statements/race/crit_1 +4 -0
  1056. data/test/statements/read/anno_1 +4 -0
  1057. data/test/statements/read/crit_1 +8 -0
  1058. data/test/statements/recall/anno_1 +16 -0
  1059. data/test/statements/recall/anno_2 +18 -0
  1060. data/test/statements/recall/anno_3 +4 -0
  1061. data/test/statements/recall/anno_4 +3 -0
  1062. data/test/statements/recall/anno_5 +5 -0
  1063. data/test/statements/recall/anno_6 +107 -0
  1064. data/test/statements/recall/crit_1 +17 -0
  1065. data/test/statements/recall/crit_2 +14 -0
  1066. data/test/statements/recall/crit_3 +16 -0
  1067. data/test/statements/recall/crit_cte_1 +17 -0
  1068. data/test/statements/recall/crit_cte_2 +17 -0
  1069. data/test/statements/recall/crit_nested_perm_0 +28 -0
  1070. data/test/statements/revenue_code/crit_1 +4 -0
  1071. data/test/statements/revenue_code/crit_basic +4 -0
  1072. data/test/statements/revenue_code/domains_1 +4 -0
  1073. data/test/statements/revenue_code/domains_drg100 +4 -0
  1074. data/test/statements/rxnorm/crit_1 +4 -0
  1075. data/test/statements/snomed/crit_1 +4 -0
  1076. data/test/statements/started_by/crit_1 +16 -0
  1077. data/test/statements/started_by/crit_2 +16 -0
  1078. data/test/statements/started_by/crit_3 +16 -0
  1079. data/test/statements/sum/anno_1 +3 -0
  1080. data/test/statements/sum/anno_2 +8 -0
  1081. data/test/statements/sum/num_1 +11 -0
  1082. data/test/statements/sum/num_2 +15 -0
  1083. data/test/statements/sum/num_3 +7 -0
  1084. data/test/statements/time_window/anno_1 +7 -0
  1085. data/test/statements/time_window/anno_2 +11 -0
  1086. data/test/statements/time_window/anno_3 +11 -0
  1087. data/test/statements/time_window/anno_4 +12 -0
  1088. data/test/statements/time_window/anno_5 +15 -0
  1089. data/test/statements/time_window/crit_1 +11 -0
  1090. data/test/statements/time_window/crit_2 +11 -0
  1091. data/test/statements/time_window/crit_3 +11 -0
  1092. data/test/statements/time_window/crit_4 +11 -0
  1093. data/test/statements/trim_date_end/crit_1 +16 -0
  1094. data/test/statements/trim_date_end/crit_2 +16 -0
  1095. data/test/statements/trim_date_end/crit_3 +16 -0
  1096. data/test/statements/trim_date_end/crit_at_least +17 -0
  1097. data/test/statements/trim_date_end/crit_occurrences_1 +17 -0
  1098. data/test/statements/trim_date_end/crit_occurrences_2 +17 -0
  1099. data/test/statements/trim_date_end/crit_within +17 -0
  1100. data/test/statements/trim_date_start/crit_1 +16 -0
  1101. data/test/statements/trim_date_start/crit_2 +16 -0
  1102. data/test/statements/trim_date_start/crit_3 +16 -0
  1103. data/test/statements/trim_date_start/crit_at_least +17 -0
  1104. data/test/statements/trim_date_start/crit_occurrences_1 +17 -0
  1105. data/test/statements/trim_date_start/crit_occurrences_2 +17 -0
  1106. data/test/statements/trim_date_start/crit_within +17 -0
  1107. data/test/statements/union/anno_1 +11 -0
  1108. data/test/statements/union/anno_2 +18 -0
  1109. data/test/statements/union/anno_3 +3 -0
  1110. data/test/statements/union/anno_4 +4 -0
  1111. data/test/statements/union/anno_5 +7 -0
  1112. data/test/statements/union/anno_6 +10 -0
  1113. data/test/statements/union/count_1 +11 -0
  1114. data/test/statements/union/count_2 +11 -0
  1115. data/test/statements/union/count_3 +15 -0
  1116. data/test/statements/union/count_4 +18 -0
  1117. data/test/statements/union/count_5 +18 -0
  1118. data/test/statements/union/scanno_1 +3 -0
  1119. data/test/statements/union/scanno_2 +18 -0
  1120. data/test/statements/visit_occurrence/anno_1 +11 -0
  1121. data/test/statements/visit_occurrence/anno_2 +8 -0
  1122. data/test/statements/visit_occurrence/crit_1 +7 -0
  1123. data/test/statements/visit_occurrence/crit_2 +7 -0
  1124. data/test/statements/visit_occurrence/crit_3 +3 -0
  1125. metadata +2016 -150
  1126. data/lib/conceptql/behaviors/debuggable.rb +0 -70
  1127. data/lib/conceptql/behaviors/dottable.rb +0 -103
  1128. data/lib/conceptql/behaviors/preppable.rb +0 -20
  1129. data/lib/conceptql/converter.rb +0 -65
  1130. data/lib/conceptql/debugger.rb +0 -48
  1131. data/lib/conceptql/fake_grapher.rb +0 -20
  1132. data/lib/conceptql/graph.rb +0 -52
  1133. data/lib/conceptql/graph_nodifier.rb +0 -203
  1134. data/lib/conceptql/operators/concept.rb +0 -70
  1135. data/lib/conceptql/operators/snomed_condition.rb +0 -26
  1136. data/lib/conceptql/operators/visit.rb +0 -15
  1137. data/lib/conceptql/tree.rb +0 -53
  1138. data/lib/conceptql/utils/temp_table.rb +0 -72
  1139. data/spec/conceptql/behaviors/dottable_spec.rb +0 -99
  1140. data/spec/conceptql/converter_spec.rb +0 -51
  1141. data/spec/conceptql/date_adjuster_spec.rb +0 -68
  1142. data/spec/conceptql/operators/after_spec.rb +0 -16
  1143. data/spec/conceptql/operators/before_spec.rb +0 -16
  1144. data/spec/conceptql/operators/casting_operator_spec.rb +0 -68
  1145. data/spec/conceptql/operators/complement_spec.rb +0 -15
  1146. data/spec/conceptql/operators/concept_spec.rb +0 -40
  1147. data/spec/conceptql/operators/condition_type_spec.rb +0 -128
  1148. data/spec/conceptql/operators/contains_spec.rb +0 -19
  1149. data/spec/conceptql/operators/cpt_spec.rb +0 -29
  1150. data/spec/conceptql/operators/date_range_spec.rb +0 -33
  1151. data/spec/conceptql/operators/death_spec.rb +0 -10
  1152. data/spec/conceptql/operators/during_spec.rb +0 -30
  1153. data/spec/conceptql/operators/except_spec.rb +0 -15
  1154. data/spec/conceptql/operators/first_spec.rb +0 -35
  1155. data/spec/conceptql/operators/from_spec.rb +0 -13
  1156. data/spec/conceptql/operators/gender_spec.rb +0 -27
  1157. data/spec/conceptql/operators/hcpcs_spec.rb +0 -29
  1158. data/spec/conceptql/operators/icd10_spec.rb +0 -34
  1159. data/spec/conceptql/operators/icd9_procedure_spec.rb +0 -29
  1160. data/spec/conceptql/operators/icd9_spec.rb +0 -34
  1161. data/spec/conceptql/operators/intersect_spec.rb +0 -28
  1162. data/spec/conceptql/operators/last_spec.rb +0 -36
  1163. data/spec/conceptql/operators/loinc_spec.rb +0 -29
  1164. data/spec/conceptql/operators/medcode_procedure_spec.rb +0 -34
  1165. data/spec/conceptql/operators/medcode_spec.rb +0 -34
  1166. data/spec/conceptql/operators/observation_period_spec.rb +0 -10
  1167. data/spec/conceptql/operators/occurrence_spec.rb +0 -87
  1168. data/spec/conceptql/operators/overlapped_by_spec.rb +0 -32
  1169. data/spec/conceptql/operators/overlaps_spec.rb +0 -21
  1170. data/spec/conceptql/operators/person_filter_spec.rb +0 -15
  1171. data/spec/conceptql/operators/person_spec.rb +0 -10
  1172. data/spec/conceptql/operators/place_of_service_code_spec.rb +0 -24
  1173. data/spec/conceptql/operators/procedure_occurrence_spec.rb +0 -10
  1174. data/spec/conceptql/operators/prodcode_spec.rb +0 -35
  1175. data/spec/conceptql/operators/query_double.rb +0 -20
  1176. data/spec/conceptql/operators/query_double_spec.rb +0 -7
  1177. data/spec/conceptql/operators/race_spec.rb +0 -21
  1178. data/spec/conceptql/operators/rxnorm_spec.rb +0 -29
  1179. data/spec/conceptql/operators/snomed_spec.rb +0 -29
  1180. data/spec/conceptql/operators/source_vocabulary_operator_spec.rb +0 -35
  1181. data/spec/conceptql/operators/standard_vocabulary_operator_spec.rb +0 -35
  1182. data/spec/conceptql/operators/started_by_spec.rb +0 -22
  1183. data/spec/conceptql/operators/temporal_operator_spec.rb +0 -51
  1184. data/spec/conceptql/operators/time_window_spec.rb +0 -77
  1185. data/spec/conceptql/operators/union_spec.rb +0 -21
  1186. data/spec/conceptql/operators/visit_occurrence_spec.rb +0 -10
  1187. data/spec/conceptql/query_spec.rb +0 -22
  1188. data/spec/conceptql/tree_spec.rb +0 -50
  1189. data/spec/doubles/stream_for_casting_double.rb +0 -9
  1190. data/spec/doubles/stream_for_occurrence_double.rb +0 -25
  1191. data/spec/doubles/stream_for_temporal_double.rb +0 -6
  1192. data/spec/spec_helper.rb +0 -102
data/doc/spec.md.cql ADDED
@@ -0,0 +1,1930 @@
1
+ # ConceptQL Specification
2
+
3
+ ConceptQL (pronounced concept-Q-L) is a high-level language that allows researchers to unambiguously define their research algorithms.
4
+
5
+ ## Motivation for ConceptQL
6
+
7
+ Outcomes Insights intends to build a vast library of research algorithms and apply those algorithms to large databases of claims data. Early into building the library, we realized we had to overcome two major issues:
8
+
9
+ 1. Methods sections of research papers commonly use natural language to specify the criteria used to build cohorts from a claims database.
10
+ - Algorithms defined in natural language are often imprecise, open to multiple interpretations, and generally difficult to reproduce.
11
+ - Researchers could benefit from a language that removes the ambiguity of natural language while increasing the reproducibility of their research algorithms.
12
+ 1. Querying against claims databases is often difficult.
13
+ - Hand-coding algorithms to extract cohorts from datasets is time-consuming, error-prone, and opaque.
14
+ - Researchers could benefit from a language that allows algorithms to be defined at a high-level and then gets translated into the appropriate queries against a database.
15
+
16
+ We developed ConceptQL to address these two issues.
17
+
18
+ We are writing a tool that can read research algorithms defined in ConceptQL. The tool can create a diagram for the algorithm which makes it easy to visualize and understand. The tool can also translate the algorithm into a SQL query which runs against data structured in [OMOP's Common Data Model (CDM)](http://omop.org/CDM). The purpose of the CDM is to standardize the format and content of observational data, so standardized applications, tools and methods can be applied to them.
19
+
20
+ For instance, using ConceptQL we can take a statement that looks like this:
21
+
22
+ ```YAML
23
+ :icd9: '412'
24
+ ```
25
+
26
+ And generate a diagram that looks like this:
27
+
28
+ ```ConceptQL
29
+ [
30
+ "icd9",
31
+ "412"
32
+ ]
33
+ ```
34
+
35
+ And generate SQL that looks like this:
36
+
37
+ ```SQL
38
+ SELECT *
39
+ FROM cdm_data.condition_occurrence AS co
40
+ JOIN vocabulary.source_to_concept_map AS scm ON (c.condition_concept_id = scm.target_concept_id)
41
+ WHERE scm.source_code IN ('412')
42
+ AND scm.source_vocabulary_id = 2
43
+ AND scm.source_code = co.condition_source_value
44
+ ```
45
+
46
+ As stated above, one of the goals of ConceptQL is to make it easy to assemble fairly complex queries without having to roll up our sleeves and write raw SQL. To accommodate this complexity, ConceptQL itself has some complexities of its own. That said, we believe ConceptQL will help researchers define, hone, and share their research algorithms.
47
+
48
+ ## ConceptQL Overview
49
+
50
+ ### What ConceptQL Looks Like
51
+
52
+ I find seeing examples to be the quickest way to get a sense of a language. Here is a trivial example to whet your appetite. The example is in YAML, but could just as easily be in JSON or any other markup language capable of representing nested sets of heterogeneous arrays and hashes. In fact, the ConceptQL "language" is a just set of nested hashes and arrays representing search criteria and some set operations and temporal operations to glue those criteria together.
53
+
54
+ ```YAML
55
+ # Example 1: A simple example in YAML
56
+ # This is just a simple hash with a key of :icd9 and a value of 412
57
+ # This example will search the condition_occurrence table for all conditions that match the ICD-9 code 412.
58
+ ---
59
+ :icd9: '412'
60
+ ```
61
+
62
+ ### ConceptQL Diagrams
63
+
64
+ Reading ConceptQL in YAML or JSON seems hard to me. I prefer to explore ConceptQL using directed graphs. For instance, the diagram for the simple example listed in YAML above is:
65
+
66
+ ```ConceptQL
67
+ # All Conditions Matching MI
68
+ [
69
+ "icd9",
70
+ "412"
71
+ ]
72
+ ```
73
+
74
+ Each oval depicts a "operator", or rather, a ConceptQL expression. An arrow between a pair of operators indicates that the results from the operator on the tail of the arrow pass on to the operator at the head of the arrow. A simple example should help here:
75
+
76
+ ```ConceptQL
77
+ # First Office Visit Per Patient
78
+ [
79
+ "first",
80
+ [
81
+ "cpt",
82
+ "99214"
83
+ ]
84
+ ]
85
+ ```
86
+
87
+ The diagram above reads "get all procedures that match the CPT 99214 (Office Visit) and then filter them down to the first occurrence for each person". The diagram is much more terse than that and to accurately read the diagram, you need a lot of implicit knowledge about how each operator operates. Fortunately, this document will (hopefully) impart that knowledge to you.
88
+
89
+ Please note that all of my diagrams end with an arrow pointing at nothing. You'll see why soon.
90
+
91
+ ### Think of Results as a Stream
92
+
93
+ I draw my ConceptQL diagrams with leaf operators at the top and the "trunk" operators at the bottom. I like to think of the results of a ConceptQL statement as a flowing stream of data. The leaf operators, or operators that gather results out of the database, act like tributaries. The results flow downwards and either join with other results, or filter out other results until the streams emerge at the bottom of the diagram. Think of each arrow as a stream of results, flowing down through one operator to the next.
94
+
95
+ The trailing arrow in the diagrams serves as a reminder that ConceptQL yields a stream of results.
96
+
97
+ ### Streams have Types
98
+
99
+ You might have noticed that the operators and edges in the diagrams often have a color. That color represents what "type" of stream the operator or edge represents. There are many types in ConceptQL, and you'll notice they are __strongly__ correlated with the tables found in [CDM v4.0](http://omop.org/CDM):
100
+
101
+ - condition_occurrence
102
+ - red
103
+ - death
104
+ - brown
105
+ - drug_cost
106
+ - TBD
107
+ - drug_exposure
108
+ - purple
109
+ - observation
110
+ - TBD
111
+ - payer_plan_period
112
+ - TBD
113
+ - person
114
+ - blue
115
+ - procedure_cost
116
+ - gold
117
+ - procedure_occurrence
118
+ - green
119
+ - visit_occurrence
120
+ - orange
121
+
122
+ Each stream has a point of origin (essentially, the table from which we pulled the results for a stream). Based on that origin, each stream will have a particular type. The stream carries this type information as it moves through each operator. When certain operators, particularly set and temporal operators, need to perform filtering, they can use this type information to determine how to best filter a stream. There will be much more discussion about types woven throughout this document. For now, it is sufficient to know that each stream has a type.
123
+
124
+ You'll also notice that the trailing arrow(s) at the end of the diagrams indicate which types of streams are ultimately passed on at the end of a ConceptQL statement.
125
+
126
+ ### What *are* Streams Really?
127
+
128
+ Though I think that a "stream" is a helpful abstraction when thinking in ConceptQL, on a few occasions we need to know what's going on under the hood.
129
+
130
+ Every table in the CDM structure has a surrogate key column (an ID column). When we execute a ConceptQL statement, the "streams" that are generated by the statement are just sets of these IDs for rows that matched the ConceptQL criteria. So each stream is just a set of IDs that point back to some rows in one of the CDM tables. When a stream has a "type" it is really just that the stream contains IDs associated with its table of origin.
131
+
132
+ So when we execute this ConceptQL statement, the resulting "stream" is all the person IDs for all male patients in the database:
133
+
134
+ ```ConceptQL
135
+ # All Male Patients
136
+ [
137
+ "gender",
138
+ "Male"
139
+ ]
140
+ ```
141
+
142
+ When we execute this ConceptQL statement, the resulting "stream" is all condition_occurrence IDs that match ICD-9 799.22:
143
+
144
+ ```ConceptQL
145
+ # All Condition Occurrences that match ICD-9 799.22
146
+ [
147
+ "icd9",
148
+ "799.22"
149
+ ]
150
+ ```
151
+
152
+ Generally, I find it helpful to just think of those queries generating a "stream of people" or a "stream of conditions" and not worry about the table of origin or the fact that they are just IDs.
153
+
154
+ When a ConceptQL statement is executed, it yields a final set of streams that are just all the IDs that passed through all the criteria. What is done with that set of IDs is up to the user who assembled the ConceptQL statement. If a user gathers all 799.22 Conditions, they will end up with a set of condition_occurrence_ids. They could take those IDs and do all sorts of things like:
155
+
156
+ - Gather the first and last date of occurrence per person
157
+ - Count the number of occurrences per person
158
+ - Count number of persons with the condition
159
+ - Count the total number of occurrences for the entire population
160
+
161
+ This kind of aggregation and analysis is beyond the scope of ConceptQL. ConceptQL will get you the IDs of the rows you're interested in, its up to other parts of the calling system to determine what you do with them.
162
+
163
+ ## Selection Operators
164
+
165
+ Selection operators are the parts of a ConceptQL query that search for specific values within the CDM data, e.g. searching the condition_occurrence table for a diagnosis of an old myocardial infarction (ICD-9 412) is a selection. Selection operators are always leaf operators.
166
+
167
+ There are _many_ selection operators. A list of currently implemented operators is available in Appendix A.
168
+
169
+ ## All Other Operators i.e. Mutation Operators
170
+
171
+ Virtually all other operators add, remove, filter, or otherwise alter streams of results. They are discussed in this section.
172
+
173
+ ## Set Operators
174
+
175
+ Because streams represent sets of results, its makes sense to include a operators that operate on sets
176
+
177
+ ### Union
178
+
179
+ - Takes any number of upstream operators and aggregates their streams
180
+ - Unions together streams with identical types
181
+ - Think of streams with the same type flowing together into a single stream
182
+ - We're really just gathering the union of all IDs for identically-typed streams
183
+ - Streams with the different types flow along together concurrently without interacting
184
+ - It does not make sense to union, say, condition_occurrence_ids with visit_occurrence_ids, so streams with different types won't mingle together, but will continue to flow downstream in parallel
185
+
186
+ ```ConceptQL
187
+ # Two streams of the same type (condition_occurrence) joined into a single stream
188
+ [
189
+ "union",
190
+ [
191
+ "icd9",
192
+ "412"
193
+ ],
194
+ [
195
+ "icd9",
196
+ "799.22"
197
+ ]
198
+ ]
199
+ ```
200
+
201
+ ```ConceptQL
202
+ # Two streams of the same type (condition_occurrence) joined into a single stream, then a different stream (visit_occurrence) flows concurrently
203
+ [
204
+ "union",
205
+ [
206
+ "union",
207
+ [
208
+ "icd9",
209
+ "412"
210
+ ],
211
+ [
212
+ "icd9",
213
+ "799.22"
214
+ ]
215
+ ],
216
+ [
217
+ "place_of_service_code",
218
+ "21"
219
+ ]
220
+ ]
221
+ ```
222
+
223
+ ```ConceptQL
224
+ # Two streams of the same type (condition_occurrence) joined into a single stream, along with a different stream (visit_occurrence) flows concurrently (same as above example)
225
+ [
226
+ "union",
227
+ [
228
+ "icd9",
229
+ "412"
230
+ ],
231
+ [
232
+ "icd9",
233
+ "799.22"
234
+ ],
235
+ [
236
+ "place_of_service_code",
237
+ "21"
238
+ ]
239
+ ]
240
+ ```
241
+
242
+ ### Intersect
243
+
244
+ 1. Group incoming streams by type
245
+ 1. For each group of same-type streams
246
+ a. Intersect all streams, yielding a single stream that contains only those IDs common to those streams
247
+ 1. A single stream for each incoming type is sent downstream
248
+ a. If only a single stream of a type is upstream, that stream is essentially unaltered as it is passed downstream
249
+
250
+ ```ConceptQL
251
+ # Yields a single stream of all Conditions where MI was Primary Diagnosis. This involves two Condition streams and so results are intersected
252
+ [
253
+ "intersect",
254
+ [
255
+ "icd9",
256
+ "412"
257
+ ],
258
+ [
259
+ "primary_diagnosis",
260
+ true
261
+ ]
262
+ ]
263
+ ```
264
+
265
+ ```ConceptQL
266
+ # Yields two streams: a stream of all MI Conditions and a stream of all Male patients. This is essentially the same behavior as Union in this case
267
+ [
268
+ "intersect",
269
+ [
270
+ "icd9",
271
+ "412"
272
+ ],
273
+ [
274
+ "gender",
275
+ "Male"
276
+ ]
277
+ ]
278
+ ```
279
+
280
+ ```ConceptQL
281
+ # Yields two streams: a stream of all Conditions where MI was Primary Diagnosis and a stream of all White, Male patients.
282
+ [
283
+ "intersect",
284
+ [
285
+ "icd9",
286
+ "412"
287
+ ],
288
+ [
289
+ "primary_diagnosis",
290
+ true
291
+ ],
292
+ [
293
+ "gender",
294
+ "Male"
295
+ ],
296
+ [
297
+ "race",
298
+ "White"
299
+ ]
300
+ ]
301
+ ```
302
+
303
+ ### Complement
304
+
305
+ This operator will take the complement of each set of IDs in the incoming streams.
306
+
307
+ ```ConceptQL
308
+ # All non-MI Conditions
309
+ [
310
+ "complement",
311
+ [
312
+ "icd9",
313
+ "412"
314
+ ]
315
+ ]
316
+ ```
317
+
318
+ If you're familiar with set operations, the complement of a union is the intersect of the complements of the items unioned. So in our world, these next two examples are identical:
319
+
320
+ ```ConceptQL
321
+ # All Conditions where the Condition isn't an MI as the Primary Diagnosis
322
+ [
323
+ "complement",
324
+ [
325
+ "union",
326
+ [
327
+ "icd9",
328
+ "412"
329
+ ],
330
+ [
331
+ "primary_diagnosis",
332
+ true
333
+ ]
334
+ ]
335
+ ]
336
+ ```
337
+
338
+ ```ConceptQL
339
+ # All Conditions where the Condition isn't an MI as the Primary Diagnosis (same as above)
340
+ [
341
+ "intersect",
342
+ [
343
+ "complement",
344
+ [
345
+ "icd9",
346
+ "412"
347
+ ]
348
+ ],
349
+ [
350
+ "complement",
351
+ [
352
+ "primary_diagnosis",
353
+ true
354
+ ]
355
+ ]
356
+ ]
357
+ ```
358
+
359
+ But please be aware that this behavior of complement only affects streams of the same type. If more than one stream is involved, you need to evaluate the effects of complement on a stream-by-stream basis:
360
+
361
+ ```ConceptQL
362
+ # Yields two streams: a stream of all Conditions where the conditions isn't an MI and Primary Diagnosis and a stream of all non-office visit Procedures
363
+ [
364
+ "complement",
365
+ [
366
+ "union",
367
+ [
368
+ "icd9",
369
+ "412"
370
+ ],
371
+ [
372
+ "primary_diagnosis",
373
+ true
374
+ ],
375
+ [
376
+ "cpt",
377
+ "99214"
378
+ ]
379
+ ]
380
+ ]
381
+ ```
382
+
383
+ ```ConceptQL
384
+ # Yields two streams: a stream of all Conditions where the conditions isn't an MI and Primary Diagnosis and a stream of all non-office visit Procedures (same as above)
385
+ [
386
+ "intersect",
387
+ [
388
+ "complement",
389
+ [
390
+ "icd9",
391
+ "412"
392
+ ]
393
+ ],
394
+ [
395
+ "complement",
396
+ [
397
+ "primary_diagnosis",
398
+ true
399
+ ]
400
+ ],
401
+ [
402
+ "complement",
403
+ [
404
+ "cpt",
405
+ "99214"
406
+ ]
407
+ ]
408
+ ]
409
+ ```
410
+
411
+ ```ConceptQL
412
+ # Yields two streams: a stream of all Conditions where the conditions isn't an MI and Primary Diagnosis and a stream of all non-office visit Procedures (same as above)
413
+ [
414
+ "union",
415
+ [
416
+ "intersect",
417
+ [
418
+ "complement",
419
+ [
420
+ "icd9",
421
+ "412"
422
+ ]
423
+ ],
424
+ [
425
+ "complement",
426
+ [
427
+ "primary_diagnosis",
428
+ true
429
+ ]
430
+ ]
431
+ ],
432
+ [
433
+ "complement",
434
+ [
435
+ "cpt",
436
+ "99214"
437
+ ]
438
+ ]
439
+ ]
440
+ ```
441
+
442
+ ### Except
443
+
444
+ This operator takes two sets of incoming streams, a left-hand stream and a right-hand stream. The operator matches like-type streams between the left-hand and right-hand streams. The operator removes any results in the left-hand stream if they appear in the right-hand stream. The operator passes only results for the left-hand stream downstream. The operator discards all results in the right-hand stream. For example:
445
+
446
+ ```ConceptQL
447
+ # All Conditions that are MI unless they are primary diagnoses
448
+ [
449
+ "except",
450
+ {
451
+ "left": [
452
+ "icd9",
453
+ "412"
454
+ ],
455
+ "right": [
456
+ "primary_diagnosis",
457
+ true
458
+ ]
459
+ }
460
+ ]
461
+ ```
462
+
463
+ ```ConceptQL
464
+ # All Conditions that are MI unless they are primary diagnoses (same as above)
465
+ [
466
+ "intersect",
467
+ [
468
+ "icd9",
469
+ "412"
470
+ ],
471
+ [
472
+ "complement",
473
+ [
474
+ "primary_diagnosis",
475
+ true
476
+ ]
477
+ ]
478
+ ]
479
+ ```
480
+
481
+ If the left-hand stream has no types that match the right-hand stream, the left-hand stream passes through unaffected:
482
+
483
+ ```ConceptQL
484
+ # All Conditions that are MI
485
+ [
486
+ "except",
487
+ {
488
+ "left": [
489
+ "icd9",
490
+ "412"
491
+ ],
492
+ "right": [
493
+ "cpt",
494
+ "99214"
495
+ ]
496
+ }
497
+ ]
498
+ ```
499
+
500
+ And just to show how multiple streams behave:
501
+
502
+ ```ConceptQL
503
+ # Passes three streams downstream: a stream of Conditions that are MI but not primary diagnosis, a stream of People that are Male but not White, and a stream of Procedures that are office visits (this stream is completely unaffected by the right hand stream)
504
+ [
505
+ "except",
506
+ {
507
+ "left": [
508
+ "union",
509
+ [
510
+ "icd9",
511
+ "412"
512
+ ],
513
+ [
514
+ "gender",
515
+ "Male"
516
+ ],
517
+ [
518
+ "cpt",
519
+ "99214"
520
+ ]
521
+ ],
522
+ "right": [
523
+ "union",
524
+ [
525
+ "primary_diagnosis",
526
+ true
527
+ ],
528
+ [
529
+ "race",
530
+ "White"
531
+ ]
532
+ ]
533
+ }
534
+ ]
535
+ ```
536
+
537
+ ### Discussion about Set Operators
538
+
539
+ #### Union Operators
540
+
541
+ ##### Q. Why should we allow two different types of streams to continue downstream concurrently?
542
+
543
+ - This feature lets us do interesting things, like find the first occurrence of either an MI or Death as in the example below
544
+ - Throw in a few more criteria and you could find the first occurrence of all censor events for each patient
545
+
546
+ ```ConceptQL
547
+ # First occurrence of either MI or Death for each patient
548
+ [
549
+ "first",
550
+ [
551
+ "union",
552
+ [
553
+ "icd9",
554
+ "412"
555
+ ],
556
+ [
557
+ "death",
558
+ true
559
+ ]
560
+ ]
561
+ ]
562
+ ```
563
+
564
+ ##### Q. Why aren't all streams passed forward unaltered? Why union like-typed streams?
565
+
566
+ - The way Intersect works, if we passed like-typed streams forward without unioning them, Intersect would end up intersecting the two un-unioned like-type streams and that's not what we intended
567
+ - Essentially, these two diagrams would be identical:
568
+
569
+ ```ConceptQL
570
+ # Two streams: a stream of all Conditions matching either 412 or 799.22 and a stream of Procedures matching 99214
571
+ [
572
+ "intersect",
573
+ [
574
+ "union",
575
+ [
576
+ "icd9",
577
+ "412"
578
+ ],
579
+ [
580
+ "icd9",
581
+ "799.22"
582
+ ]
583
+ ],
584
+ [
585
+ "cpt",
586
+ "99214"
587
+ ]
588
+ ]
589
+ ```
590
+
591
+ ```ConceptQL
592
+ # Two streams: a stream of all Conditions matching either 412 AND 799.22 (an empty stream, a condition cannot be both 412 and 799.22 at the same time) and a stream of Procedures matching 99214
593
+ [
594
+ "intersect",
595
+ [
596
+ "intersect",
597
+ [
598
+ "icd9",
599
+ "412"
600
+ ],
601
+ [
602
+ "icd9",
603
+ "799.22"
604
+ ]
605
+ ],
606
+ [
607
+ "cpt",
608
+ "99214"
609
+ ]
610
+ ]
611
+ ```
612
+
613
+ ## Time-oriented Operators
614
+
615
+ All results in a stream carry a start_date and end_date with them. All temporal comparisons of streams use these two date columns. Each result in a stream derives its start and end date from its corresponding row in its table of origin.
616
+
617
+ For instance, a visit_occurrence result derives its start_date from visit_start_date and its end_date from visit_end_date.
618
+
619
+ If a result comes from a table that only has a single date value, the result derives both its start_date and end_date from that single date, e.g. an observation result derives both its start_date and end_date from its corresponding row's observation_date.
620
+
621
+ The person stream is a special case. Person results use the person's date of birth as the start_date and end_date. This may sound strange, but we will explain below why this makes sense.
622
+
623
+ ### Relative Temporal Operators
624
+
625
+ When looking at a set of results for a person, perhaps we want to select just the chronologically first or last result. Or maybe we want to select the 2nd result or 2nd to last result. Relative temporal operators provide this type of filtering. Relative temporal operators use a result's start_date to do chronological ordering.
626
+
627
+ #### occurrence
628
+
629
+ - Takes a two arguments: the stream to select from and an integer argument
630
+ - For the integer argument
631
+ - Positive numbers mean 1st, 2nd, 3rd occurrence in chronological order
632
+ - e.g. 1 => first
633
+ - e.g. 4 => fourth
634
+ - Negative numbers mean 1st, 2nd, 3rd occurrence in reverse chronological order
635
+ - e.g. -1 => last
636
+ - e.g. -4 => fourth from last
637
+ - 0 is undefined?
638
+
639
+ ```ConceptQL
640
+ # For each patient, select the Condition that represents the third occurrence of an MI
641
+ [
642
+ "occurrence",
643
+ 3,
644
+ [
645
+ "icd9",
646
+ "412"
647
+ ]
648
+ ]
649
+ ```
650
+
651
+ #### first
652
+
653
+ - Operator that is shorthand for writing "occurrence: 1"
654
+
655
+ ```ConceptQL
656
+ # For each patient, select the Condition that represents the first occurrence of an MI
657
+ [
658
+ "first",
659
+ [
660
+ "icd9",
661
+ "412"
662
+ ]
663
+ ]
664
+ ```
665
+
666
+ #### last
667
+
668
+ - Operator that is just shorthand for writing "occurrence: -1"
669
+
670
+ ```ConceptQL
671
+ # For each patient, select the Condition that represents the last occurrence of an MI
672
+ [
673
+ "last",
674
+ [
675
+ "icd9",
676
+ "412"
677
+ ]
678
+ ]
679
+ ```
680
+
681
+ ### Date Literals
682
+
683
+ For situations where we need to represent pre-defined date ranges, we can use "date literal" operators.
684
+
685
+ #### date_range
686
+
687
+ - Takes a hash with two elements: { start: \<date-format\>, end: \<date-format\> }
688
+ - Creates an inclusive, continuous range of dates defined by a start and end date
689
+
690
+ #### day
691
+
692
+ - Takes a single argument: \<date-format\>
693
+ - Represents a single day
694
+ - Shorthand for creating a date range that starts and ends on the same date
695
+ - *Not yet implemented*
696
+
697
+ #### What is <date-format\>?
698
+
699
+ Dates follow these formats:
700
+
701
+ - "YYYY-MM-DD"
702
+ - Four-digit year, two-digit month with leading 0s, two-digit day with leading 0s
703
+ - "START"
704
+ - Represents the first date of information available from the data source
705
+ - "END"
706
+ - Represents the last date of information available from the data source.
707
+
708
+ ### Temporal Comparison Operators
709
+
710
+ As described above, each result carries a start and end date, defining its own date range. It is through these date ranges that we are able to do temporal filtering of streams via temporal operators.
711
+
712
+ Temporal operators work by comparing a left-hand stream (L) against a right-hand stream (R). R can be either a set of streams or a pre-defined date range. Each temporal operator has a comparison operator which defines how it compares dates between L and R. A temporal operator passes results only from L downstream. A temporal operator discards all results in the R stream after it makes all comparisons.
713
+
714
+ The available set of temporal operators comes from the work of Allen's Interval Algebra[^AIA]. Interval Algebra defines 13 distinct temporal relationships, as shown in this handy chart [borrowed from this website](http://people.kmi.open.ac.uk/carlos/174): ![](http://people.kmi.open.ac.uk/carlos/wp-content/uploads/2011/02/Allens-Algebra.png)
715
+
716
+ Our implementation of this algebra is originally going to be as strict as listed here, meaning that:
717
+
718
+ - Before/After
719
+ - There must be a minimum 1-day gap between date ranges
720
+ - Meets/Met-by
721
+ - Only if the first date range starts/ends a day before the next date range ends/starts
722
+ - Started-by/Starts
723
+ - The start dates of the two ranges must be equal and the end dates must not be
724
+ - Finished-by/Finishes
725
+ - The end dates of the two ranges must be equal and the start dates must not be
726
+ - Contains/During
727
+ - The start/end dates of the two ranges must be different from each other
728
+ - Overlaps/Overlapped-by
729
+ - The start date of one range and the end date of the other range must be outside the overlapping range
730
+ - Temporally coincides
731
+ - Start dates must be equal, end dates must be equal
732
+
733
+ Ryan's Sidebar on These Definitions:
734
+ > These strict definitions may not be particularly handy or even intuitive. It seems like contains, starts, finishes, and coincides are all examples of overlapping ranges. Starts/finishes seem to be examples of one range containing another. Meets/met-by seem to be special cases of before/after. But these definitions, if used in their strict sense, are all mutually exclusive.
735
+
736
+ > We may want to adopt a less strict set of definitions, though their meaning may not be as easily defined as the one provided by Allen's Interval Algebra
737
+
738
+ When comparing results in L against a date range, results in L continue downstream only if they pass the comparison.
739
+
740
+ ```ConceptQL
741
+ # All MIs for the year 2010
742
+ [
743
+ "during",
744
+ {
745
+ "left": [
746
+ "icd9",
747
+ "412"
748
+ ],
749
+ "right": [
750
+ "date_range",
751
+ {
752
+ "start": "2010-01-01",
753
+ "end": "2010-12-31"
754
+ }
755
+ ]
756
+ }
757
+ ]
758
+ ```
759
+
760
+ When comparing results in L against a set of results in R, the temporal operator compares results in stream L against results in stream R on a person-by-person basis.
761
+
762
+ - If a person has results in L or R stream, but not in both, none of their results continue downstream
763
+ - On a per person basis, the temporal operator joins all results in the L stream to all results in the R stream
764
+ - Any results in the L stream that meet the temporal comparison against any results in the R stream continue downstream
765
+
766
+ ```ConceptQL
767
+ # All MIs While Patients had Part A Medicare
768
+ [
769
+ "during",
770
+ {
771
+ "left": [
772
+ "icd9",
773
+ "412"
774
+ ],
775
+ "right": [
776
+ "payer",
777
+ "Part A"
778
+ ]
779
+ }
780
+ ]
781
+ ```
782
+
783
+ #### Edge behaviors
784
+
785
+ For 11 of the 13 temporal operators, comparison of results is straight-forward. However, the before/after operators have a slight twist.
786
+
787
+ Imagine events 1-1-2-1-2-1. In my mind, three 1's come before a 2 and two 1's come after a 2. Accordingly:
788
+
789
+ - When comparing L **before** R, the temporal operator compares L against the **LAST** occurrence of R per person
790
+ - When comparing L **after** R, the temporal operator compares L against the **FIRST** occurrence of R per person
791
+
792
+ If we're looking for events in L that occur before events in R, then any event in L that occurs before the last event in R technically meet the comparison of "before". The reverse is true for after: all events in L that occur after the first event in R technically occur after R.
793
+
794
+ ```ConceptQL
795
+ # All MIs that occurred before a patient's __last__ case of irritability (799.22)
796
+ [
797
+ "before",
798
+ {
799
+ "left": [
800
+ "icd9",
801
+ "412"
802
+ ],
803
+ "right": [
804
+ "icd9",
805
+ "799.22"
806
+ ]
807
+ }
808
+ ]
809
+ ```
810
+
811
+ If this is not the behavior you desire, use one of the sequence operators to select which event in R should be the one used to do comparison
812
+
813
+ ```ConceptQL
814
+ # All MIs that occurred before a patient's __first__ case of irritability (799.22)
815
+ [
816
+ "before",
817
+ {
818
+ "left": [
819
+ "icd9",
820
+ "412"
821
+ ],
822
+ "right": [
823
+ "first",
824
+ [
825
+ "icd9",
826
+ "799.22"
827
+ ]
828
+ ]
829
+ }
830
+ ]
831
+ ```
832
+
833
+ ### Time Windows
834
+
835
+ There are situations when the date columns associated with a result should have their values shifted forward or backward in time to make a comparison with another set of dates.
836
+
837
+ #### time_window
838
+
839
+ - Takes 2 arguments
840
+ - First argument is the stream on which to operate
841
+ - Second argument is a hash with two keys: \[:start, :end\] each with a value in the following format: "(-?\d+\[dmy\])+"
842
+ - Both start and end must be defined, even if you are only adjusting one of the dates
843
+ - Some examples
844
+ - 30d => 30 days
845
+ - 20 => 20 days
846
+ - d => 1 day
847
+ - 1y => 1 year
848
+ - -1m => -1 month
849
+ - 10d3m => 3 months and 10 days
850
+ - -2y10m-3d => -2 years, +10 months, -3 days
851
+ - The start or end value can also be '', '0', or nil
852
+ - This will leave the date unaffected
853
+ - The start or end value can also be the string 'start' or 'end'
854
+ - 'start' represents the start_date for each result
855
+ - 'end' represents the end_date for each result
856
+ - See the example below
857
+
858
+ ```ConceptQL
859
+ # All Diagnoses of Irritability (ICD-9 799.22) within 30 days of an MI
860
+ [
861
+ "during",
862
+ {
863
+ "left": [
864
+ "icd9",
865
+ "799.22"
866
+ ],
867
+ "right": [
868
+ "time_window",
869
+ [
870
+ "icd9",
871
+ "412"
872
+ ],
873
+ {
874
+ "start": "-30d",
875
+ "end": "30d"
876
+ }
877
+ ]
878
+ }
879
+ ]
880
+ ```
881
+
882
+ ```ConceptQL
883
+ # Shift the window for all MIs back by 2 years
884
+ [
885
+ "time_window",
886
+ [
887
+ "icd9",
888
+ "412"
889
+ ],
890
+ {
891
+ "start": "-2y",
892
+ "end": "-2y"
893
+ }
894
+ ]
895
+ ```
896
+
897
+ ```ConceptQL
898
+ # Expand the dates for all MIs to a window ranging from 2 months and 2 days prior to 1 year and 3 days after the MI
899
+ [
900
+ "time_window",
901
+ [
902
+ "icd9",
903
+ "412"
904
+ ],
905
+ {
906
+ "start": "-2m-2d",
907
+ "end": "3d1y"
908
+ }
909
+ ]
910
+ ```
911
+
912
+ ```ConceptQL
913
+ # Collapse all hospital visits' date ranges down to just the date of admission by leaving start_date unaffected and setting end_date to start_date
914
+ [
915
+ "time_window",
916
+ [
917
+ "place_of_service_code",
918
+ "21"
919
+ ],
920
+ {
921
+ "start": "",
922
+ "end": "start"
923
+ }
924
+ ]
925
+ ```
926
+
927
+ ```ConceptQL
928
+ # Nonsensical, but allowed: swap the start_date and end_date for a range
929
+ [
930
+ "time_window",
931
+ [
932
+ "icd9",
933
+ "412"
934
+ ],
935
+ {
936
+ "start": "end",
937
+ "end": "start"
938
+ }
939
+ ]
940
+ ```
941
+
942
+ #### Temporal Operators and Person Streams
943
+
944
+ Person streams carry a patient's date of birth in their date columns. This makes them almost useless when they are part of the L stream of a temporal operator. But person streams are useful as the R stream. By ```time_window```ing the patient's date of birth, we can filter based on the patient's age like so:
945
+
946
+ ```ConceptQL
947
+ # All MIs that occurred after a male patient's 50th birthday
948
+ [
949
+ "after",
950
+ {
951
+ "left": [
952
+ "icd9",
953
+ "412"
954
+ ],
955
+ "right": [
956
+ "time_window",
957
+ [
958
+ "gender",
959
+ "Male"
960
+ ],
961
+ {
962
+ "start": "50y",
963
+ "end": "50y"
964
+ }
965
+ ]
966
+ }
967
+ ]
968
+ ```
969
+
970
+ ## Type Conversion
971
+
972
+ There are situations where it is appropriate to convert the type of a stream of results into a different type. In programmer parlance, we say "typecasting" or "casting", which is the terminology we'll use here. A good analogy and mnemonic for casting is to think of taking a piece of metal, say a candle holder, melting it down, and recasting it into, say, a lamp. We'll do something similar with streams. We'll take, for example, a visit_occurrence stream and recast it into a stream of person.
973
+
974
+ ### Casting to person
975
+
976
+ - Useful if we're just checking for the presence of a condition for a person
977
+ - E.g. We want to know *if* a person has an old MI, not when an MI or how many MIs occurred
978
+
979
+ ```ConceptQL
980
+ # All People Who Had an MI
981
+ [
982
+ "person",
983
+ [
984
+ "icd9",
985
+ "412"
986
+ ]
987
+ ]
988
+ ```
989
+
990
+ ### Casting to a visit_occurrence
991
+
992
+ - It is common to look for a set of conditions that coincide with a set of procedures
993
+ - Gathering conditions yields a condition stream, gathering procedures yields a procedure stream
994
+ - It is not possible to compare those two streams directly using AND
995
+ - It is possible to compare the streams temporally, but CDM provides a visit_occurrence table to explicitly tie a set of conditions to a set of procedures
996
+ - Casting both streams to visit_occurrence streams allows us to gather all visit_occurrences for which a set of conditions/procedures occurred in the same visit
997
+
998
+ ```ConceptQL
999
+ # All Visits Where a Patient Had an MI During and Office Visit
1000
+ [
1001
+ "intersect",
1002
+ [
1003
+ "visit_occurrence",
1004
+ [
1005
+ "icd9",
1006
+ "412"
1007
+ ]
1008
+ ],
1009
+ [
1010
+ "visit_occurrence",
1011
+ [
1012
+ "cpt",
1013
+ "99214"
1014
+ ]
1015
+ ]
1016
+ ]
1017
+ ```
1018
+
1019
+ Many tables have a foreign key (FK) reference to the visit_occurrence table. If we cast a result to a visit_occurrence, and its table of origin has a visit_occurrence_id FK column, the result becomes a visit_occurrence result corresponding to the row pointed to by visit_occurrence_id. If the row's visit_occurrence_id is NULL, the result is discarded from the stream.
1020
+
1021
+ If the result's table of origin has no visit_occurrence_id column, we will instead replace the result with ALL visit_occurrences for the person assigned to the result. This allows us to convert between a person stream and visit_occurrence stream and back. E.g. we can get all male patients, then ask for their visit_occurrences later downstream.
1022
+
1023
+ ```ConceptQL
1024
+ # All Visits for All Male Patients
1025
+ [
1026
+ "visit_occurrence",
1027
+ [
1028
+ "gender",
1029
+ "Male"
1030
+ ]
1031
+ ]
1032
+ ```
1033
+
1034
+ ### Casting Loses All Original Information
1035
+
1036
+ After a result undergoes casting, it loses its original information. E.g. casting a visit_occurrence to a person loses the visit_occurrence information and resets the start_date and end_date columns to the person's date of birth. As a side note, this is actually handy if a stream’s dates have been altered by a time_window operator and you want the original dates later on. Just cast the stream to its same type and it will regain its original dates.
1037
+
1038
+ ### Cast all the Things!
1039
+
1040
+ Although casting to visit_occurrence and person are the most common types of casting, we can cast to and from any of the types in the ConceptQL system.
1041
+
1042
+ The general rule will be that if the source type has a defined relationship with the target type, we'll cast using that relationship, e.g. casting visit_occurrences to procedures will turn all visit_occurrence results into the set of procedure results that point at those original visit_occurrences. But if there is no direct relationship, we'll do a generous casting, e.g. casting observations to procedures will return all procedures for all persons in the observation stream.
1043
+
1044
+ INSERT HANDY TABLE SHOWING CONVERSION MATRIX HERE
1045
+
1046
+ ```ConceptQL
1047
+ # Cost of 70012 while Hospitalized for MI
1048
+ [
1049
+ "procedure_cost",
1050
+ [
1051
+ "intersect",
1052
+ [
1053
+ "cpt",
1054
+ "70012"
1055
+ ],
1056
+ [
1057
+ "procedure",
1058
+ [
1059
+ "intersect",
1060
+ [
1061
+ "place_of_service_code",
1062
+ "21"
1063
+ ],
1064
+ [
1065
+ "visit_occurrence",
1066
+ [
1067
+ "icd9",
1068
+ "412"
1069
+ ]
1070
+ ]
1071
+ ]
1072
+ ]
1073
+ ]
1074
+ ]
1075
+ ```
1076
+
1077
+ ### Casting as a way to fetch all rows
1078
+
1079
+ The casting operator doubles as a way to fetch all rows for a single type. Provide the casting operator with an argument of ```true``` (instead of an upstream operator) to get all rows as results:
1080
+
1081
+ ```ConceptQL
1082
+ # All death results in the database
1083
+ [
1084
+ "death",
1085
+ true
1086
+ ]
1087
+ ```
1088
+
1089
+ This comes in handy for situations like these:
1090
+
1091
+ ```ConceptQL
1092
+ # All Male patients who died
1093
+ [
1094
+ "person_filter",
1095
+ {
1096
+ "left": [
1097
+ "gender",
1098
+ "Male"
1099
+ ],
1100
+ "right": [
1101
+ "death",
1102
+ true
1103
+ ]
1104
+ }
1105
+ ]
1106
+ ```
1107
+
1108
+ ## Filtering by People
1109
+
1110
+ Often we want to filter out a set of results by people. For instance, say we wanted to find all MIs for all males. We'd use the person_filter operator for that. Like the Except operator, it takes a left-hand stream and a right-hand stream.
1111
+
1112
+ Unlike the ```except``` operator, the person_filter operator will use all types of all streams in the right-hand side to filter out results in all types of all streams on the left hand side.
1113
+
1114
+ ```ConceptQL
1115
+ # All MI Conditions for people who are male
1116
+ [
1117
+ "person_filter",
1118
+ {
1119
+ "left": [
1120
+ "icd9",
1121
+ "412"
1122
+ ],
1123
+ "right": [
1124
+ "gender",
1125
+ "Male"
1126
+ ]
1127
+ }
1128
+ ]
1129
+ ```
1130
+
1131
+ But we can get crazier. The right-hand side doesn't have to be a person stream. If a non-person stream is used in the right-hand side, the person_filter will cast all right-hand streams to person first and use the union of those streams:
1132
+
1133
+ ```ConceptQL
1134
+ # All MI Conditions for people who had an office visit at some point in the data
1135
+ [
1136
+ "person_filter",
1137
+ {
1138
+ "left": [
1139
+ "icd9",
1140
+ "412"
1141
+ ],
1142
+ "right": [
1143
+ "cpt",
1144
+ "99214"
1145
+ ]
1146
+ }
1147
+ ]
1148
+ ```
1149
+
1150
+ ```ConceptQL
1151
+ # All MI Conditions for people who had an office visit at some point in the data (an explicit representation of what's happening in the diagram above)
1152
+ [
1153
+ "person_filter",
1154
+ {
1155
+ "left": [
1156
+ "icd9",
1157
+ "412"
1158
+ ],
1159
+ "right": [
1160
+ "person",
1161
+ [
1162
+ "cpt",
1163
+ "99214"
1164
+ ]
1165
+ ]
1166
+ }
1167
+ ]
1168
+ ```
1169
+
1170
+ ```ConceptQL
1171
+ # All MI Conditions for people who are Male OR had an office visit at some point in the data
1172
+ [
1173
+ "person_filter",
1174
+ {
1175
+ "left": [
1176
+ "icd9",
1177
+ "412"
1178
+ ],
1179
+ "right": [
1180
+ "union",
1181
+ [
1182
+ "cpt",
1183
+ "99214"
1184
+ ],
1185
+ [
1186
+ "gender",
1187
+ "Male"
1188
+ ]
1189
+ ]
1190
+ }
1191
+ ]
1192
+ ```
1193
+
1194
+ And don't forget the left-hand side can have multiple types of streams:
1195
+
1196
+ ```ConceptQL
1197
+ # Yields two streams: a stream of all MI Conditions for people who are Male and a stream of all office visit Procedures for people who are Male
1198
+ [
1199
+ "person_filter",
1200
+ {
1201
+ "left": [
1202
+ "union",
1203
+ [
1204
+ "icd9",
1205
+ "412"
1206
+ ],
1207
+ [
1208
+ "cpt",
1209
+ "99214"
1210
+ ]
1211
+ ],
1212
+ "right": [
1213
+ "gender",
1214
+ "Male"
1215
+ ]
1216
+ }
1217
+ ]
1218
+ ```
1219
+
1220
+ ## Sub-algorithms within a Larger Algorithm
1221
+
1222
+ If a algorithm is particularly complex, or has a stream of results that are used more than once, it can be helpful to break the algorithm into a set of sub-algorithms. This can be done using the `label` options and the `recall` operator.
1223
+
1224
+ ### `label` option
1225
+
1226
+ Any ConceptQL operator can be assigned a label. The label simply provides a way to apply a brief description to an operator, generally, what kind of results the operator is producing. Any operator that has a label can be accessed via the `recall` operator.
1227
+
1228
+ ### `recall` operator
1229
+
1230
+ - Takes 1 argument
1231
+ - The "label" of an operator from which you'd like to pull the exact same set of results
1232
+
1233
+ A stream must be `define`d before `recall` can use it.
1234
+
1235
+ ```ConceptQL
1236
+ # Save away a stream of results to build the 1 inpatient, 2 outpatient pattern used in claims data algorithms
1237
+ [
1238
+ "first",
1239
+ [
1240
+ "union",
1241
+ [
1242
+ "intersect",
1243
+ [
1244
+ "visit_occurrence",
1245
+ [
1246
+ "icd9",
1247
+ "412"
1248
+ ],
1249
+ {
1250
+ "label": "Heart Attack Visit"
1251
+ }
1252
+ ],
1253
+ [
1254
+ "place_of_service_code",
1255
+ "21"
1256
+ ]
1257
+ ],
1258
+ [
1259
+ "before",
1260
+ {
1261
+ "left": [
1262
+ "intersect",
1263
+ [
1264
+ "recall",
1265
+ "Heart Attack Visit"
1266
+ ],
1267
+ [
1268
+ "complement",
1269
+ [
1270
+ "place_of_service_code",
1271
+ 21
1272
+ ]
1273
+ ],
1274
+ {
1275
+ "label": "Outpatient Heart Attack"
1276
+ }
1277
+ ],
1278
+ "right": [
1279
+ "time_window",
1280
+ [
1281
+ "recall",
1282
+ "Outpatient Heart Attack"
1283
+ ],
1284
+ {
1285
+ "start": "-30d",
1286
+ "end": "0"
1287
+ }
1288
+ ],
1289
+ "label": "Earliest of Two Outpatient Heart Attacks"
1290
+ }
1291
+ ]
1292
+ ]
1293
+ ]
1294
+ ```
1295
+
1296
+ ## Algorithms within Algorithms
1297
+
1298
+ One of the main motivations behind keeping ConceptQL so flexible is to allow users to build ConceptQL statements from other ConceptQL statements. This section loosely describes how this feature will work. Its actual execution and implementation will differ from what is presented here.
1299
+
1300
+ Say a ConceptQL statement gathers all visit_occurrences where a patient had an MI and a Hospital encounter (CPT 99231):
1301
+
1302
+ ```ConceptQL
1303
+ # All Visits where a Patient had both an MI and a Hospital Encounter
1304
+ [
1305
+ "intersect",
1306
+ [
1307
+ "visit_occurrence",
1308
+ [
1309
+ "icd9",
1310
+ "412"
1311
+ ]
1312
+ ],
1313
+ [
1314
+ "visit_occurrence",
1315
+ [
1316
+ "cpt",
1317
+ "99231"
1318
+ ]
1319
+ ]
1320
+ ]
1321
+ ```
1322
+
1323
+ If we wanted to gather all costs for all procedures for those visits, we could use the "algorithm" operator to represent the algorithm defined above in a new concept:
1324
+
1325
+ ```ConceptQL
1326
+ # All Procedure Costs for All Visits as defined above
1327
+ [
1328
+ "procedure_cost",
1329
+ [
1330
+ "algorithm",
1331
+ "\nAll Visits\nwhere a Patient had\nboth an MI and\na Hospital Encounter"
1332
+ ]
1333
+ ]
1334
+ ```
1335
+
1336
+ The color and edge coming from the algorithm operator are black to denote that we don't know what types or streams are coming from the concept. In reality, any program that uses ConceptQL can ask the algorithm represented by the algorithm operator for the concept's types. The result of nesting one algorithm within another is exactly the same had we taken algorithm operator and replaced it with the ConceptQL statement for the algorithm it represents.
1337
+
1338
+ ```ConceptQL
1339
+ # Procedure Costs for All Visits where a Patient had both an MI and a Hospital Encounter (same as above)
1340
+ [
1341
+ "procedure_cost",
1342
+ [
1343
+ "intersect",
1344
+ [
1345
+ "visit_occurrence",
1346
+ [
1347
+ "icd9",
1348
+ "412"
1349
+ ]
1350
+ ],
1351
+ [
1352
+ "visit_occurrence",
1353
+ [
1354
+ "cpt",
1355
+ "99231"
1356
+ ]
1357
+ ]
1358
+ ]
1359
+ ]
1360
+ ```
1361
+
1362
+ In the actual implementation of the algorithm operator, each ConceptQL statement will have a unique identifier which the algorithm operator will use. So, assuming that the ID 2031 represents the algorithm we want to gather all procedure costs for, our example should really read:
1363
+
1364
+ ```ConceptQL
1365
+ [
1366
+ "procedure_cost",
1367
+ [
1368
+ "algorithm",
1369
+ 2031
1370
+ ]
1371
+ ]
1372
+ ```
1373
+
1374
+ ## Values
1375
+
1376
+ A result can carry forward three different types of values, modeled after the behavior of the observation table:
1377
+
1378
+ - value_as_numeric
1379
+ - For values like lab values, counts of occurrence of results, cost information
1380
+ - value_as_string
1381
+ - For value_as_string from observation table, or notes captured in EHR data
1382
+ - value_as_concept_id
1383
+ - For values that are like factors from the observation value_as_concept_id column
1384
+
1385
+ By default, all value fields are set to NULL, unless a selection operator is explicitly written to populate one or more of those fields.
1386
+
1387
+ There are many operations that can be performed on the value_as\_\* columns and as those operations are implemented, this section will grow.
1388
+
1389
+ For now we'll cover some of the general behavior of the value_as_numeric column and it's associated operators.
1390
+
1391
+ ### numeric
1392
+
1393
+ - Takes 2 arguments
1394
+ - A stream
1395
+ - And a numeric value or a symbol representing the name of a column in CDM
1396
+
1397
+ Passing streams through a `numeric` operator changes the number stored in the value column:
1398
+
1399
+ ```ConceptQL
1400
+ # All MIs, setting value_as_numeric to 2
1401
+ [
1402
+ "numeric",
1403
+ 2,
1404
+ [
1405
+ "icd9",
1406
+ "412"
1407
+ ]
1408
+ ]
1409
+ ```
1410
+
1411
+ `numeric` can also take a column name instead of a number. It will derive the results row's value from the value stored in the column specified.
1412
+
1413
+ ```ConceptQL
1414
+ # All copays for 99214s
1415
+ [
1416
+ "numeric",
1417
+ "paid_copay",
1418
+ [
1419
+ "procedure_cost",
1420
+ [
1421
+ "cpt",
1422
+ "99214"
1423
+ ]
1424
+ ]
1425
+ ]
1426
+ ```
1427
+
1428
+ If something nonsensical happens, like the column specified isn't present in the table pointed to by a result row, value_as_numeric in the result row will be unaffected:
1429
+
1430
+ ```ConceptQL
1431
+ # Still all MIs with value_as_numeric defaulted to NULL. condition_occurrence table doesn't have a "paid_copay" column
1432
+ [
1433
+ "value",
1434
+ "paid_copay",
1435
+ [
1436
+ "icd9",
1437
+ "412"
1438
+ ]
1439
+ ]
1440
+ ```
1441
+
1442
+ Or if the column specified exists, but refers to a non-numerical column, we'll set the value to 0
1443
+
1444
+ ```ConceptQL
1445
+ # All MIs, with value set to 0 since the column specified by value operator is a non-numerical column
1446
+ [
1447
+ "value",
1448
+ "stop_reason",
1449
+ [
1450
+ "icd9",
1451
+ "412"
1452
+ ]
1453
+ ]
1454
+ ```
1455
+
1456
+ With a `numeric` operator defined, we could introduce a sum operator that will sum by patient and type. This allows us to implement the Charlson comorbidity algorithm:
1457
+
1458
+ ```ConceptQL
1459
+ [
1460
+ "sum",
1461
+ [
1462
+ "union",
1463
+ [
1464
+ "numeric",
1465
+ 1,
1466
+ [
1467
+ "person",
1468
+ [
1469
+ "icd9",
1470
+ "412"
1471
+ ]
1472
+ ]
1473
+ ],
1474
+ [
1475
+ "numeric",
1476
+ 2,
1477
+ [
1478
+ "person",
1479
+ [
1480
+ "icd9",
1481
+ "278.02"
1482
+ ]
1483
+ ]
1484
+ ]
1485
+ ]
1486
+ ]
1487
+ ```
1488
+
1489
+ ### Counting
1490
+
1491
+ It might be helpful to count the number of occurrences of a result row in a stream. A simple "count" operator could group identical rows and store the number of occurrences in the value_as_numeric column.
1492
+
1493
+ I need examples of algorithms that could benefit from this operator. I'm concerned that we'll want to roll up occurrences by person most of the time and that would require us to first cast streams to person before passing the person stream to count.
1494
+
1495
+ ```ConceptQL
1496
+ # Count the number of times each person was irritable
1497
+ [
1498
+ "count",
1499
+ [
1500
+ "person",
1501
+ [
1502
+ "icd9",
1503
+ "799.22"
1504
+ ]
1505
+ ]
1506
+ ]
1507
+ ```
1508
+
1509
+ We could do dumb things like count the number of times a row shows up in a union:
1510
+
1511
+ ```ConceptQL
1512
+ # All rows with a value of 2 would be rows that were both MI and Primary
1513
+ [
1514
+ "count",
1515
+ [
1516
+ "union",
1517
+ [
1518
+ "icd9",
1519
+ "412"
1520
+ ],
1521
+ [
1522
+ "primary_diagnosis",
1523
+ true
1524
+ ]
1525
+ ]
1526
+ ]
1527
+ ```
1528
+
1529
+ #### Numeric Value Comparison
1530
+
1531
+ Acts like any other binary operator. L and R streams, joined by person. Any L that pass comparison go downstream. R is thrown out. Comparison based on result row's value column.
1532
+
1533
+ - Less than
1534
+ - Less than or equal
1535
+ - Equal
1536
+ - Greater than or equal
1537
+ - Greater than
1538
+ - Not equal
1539
+
1540
+ ### numeric as selection operator
1541
+
1542
+ Numeric doesn't have to take a stream. If it doesn't have a stream as an argument, it acts like a selection operator much like date_range
1543
+
1544
+ ```ConceptQL
1545
+ # People with more than 1 MI
1546
+ [
1547
+ "greater_than",
1548
+ {
1549
+ "left": [
1550
+ "count",
1551
+ [
1552
+ "person",
1553
+ [
1554
+ "icd9",
1555
+ "412"
1556
+ ]
1557
+ ]
1558
+ ],
1559
+ "right": [
1560
+ "numeric",
1561
+ 1
1562
+ ]
1563
+ }
1564
+ ]
1565
+ ```
1566
+
1567
+ #### sum
1568
+
1569
+ - Takes a stream of results and does some wild things
1570
+ - Groups all results by person and type
1571
+ - Sums the value_as_numeric column within that grouping
1572
+ - Sets start_date to the earliest start_date in the group
1573
+ - Sets the end_date to the most recent end_date in the group
1574
+ - Sets selection_id to 0 since there is no particular single row that the result refers to anymore
1575
+
1576
+ ## Appendix A - Selection Operators
1577
+
1578
+ | Operator Name | Stream Type | Arguments | Returns |
1579
+ | ---- | ---- | --------- | ------- |
1580
+ | cpt | procedure_occurrence | 1 or more CPT codes | All results whose source_value match any of the CPT codes |
1581
+ | icd9 | condition_occurrence | 1 or more ICD-9 codes | All results whose source_value match any of the ICD-9 codes |
1582
+ | icd9_procedure | procedure_occurrence | 1 or more ICD-9 procedure codes | All results whose source_value match any of the ICD-9 procedure codes |
1583
+ | icd10 | condition_occurrence | 1 or more ICD-10 | All results whose source_value match any of the ICD-10 codes |
1584
+ | hcpcs | procedure_occurrence | 1 or more HCPCS codes | All results whose source_value match any of the HCPCS codes |
1585
+ | gender | person | 1 or more gender concept_ids | All results whose gender_concept_id match any of the concept_ids|
1586
+ | loinc | observation | 1 or more LOINC codes | All results whose source_value match any of the LOINC codes |
1587
+ | place_of_service_code | visit_occurrence | 1 or more place of service codes | All results whose place of service matches any of the codes|
1588
+ | race | person | 1 or more race concept_ids | All results whose race_concept_id match any of the concept_ids|
1589
+ | rxnorm | drug_exposure | 1 or more RxNorm IDs | All results whose drug_concept_id match any of the RxNorm IDs|
1590
+ | snomed | condition_occurrence | 1 or more SNOMED codes | All results whose source_value match any of the SNOMED codes |
1591
+
1592
+ ## Appendix B - Algorithm Showcase
1593
+
1594
+ Here I take some algorithms from [OMOP's Health Outcomes of Interest](http://omop.org/HOI) and turn them into ConceptQL statements to give more examples. I truncated some of the sets of codes to help ensure the diagrams didn't get too large.
1595
+
1596
+ ### Acute Kidney Injury - Narrow Definition and diagnositc procedure
1597
+
1598
+ - ICD-9 of 584
1599
+ - AND
1600
+ - ICD-9 procedure codes of 39.95 or 54.98 within 60 days after diagnosis
1601
+ - AND NOT
1602
+ - A diagnostic code of chronic dialysis any time before initial diagnosis
1603
+ - V45.1, V56.0, V56.31, V56.32, V56.8
1604
+
1605
+ ```ConceptQL
1606
+ [
1607
+ "during",
1608
+ {
1609
+ "left": [
1610
+ "except",
1611
+ {
1612
+ "left": [
1613
+ "icd9",
1614
+ "584"
1615
+ ],
1616
+ "right": [
1617
+ "after",
1618
+ {
1619
+ "left": [
1620
+ "icd9",
1621
+ "584"
1622
+ ],
1623
+ "right": [
1624
+ "icd9",
1625
+ "V45.1",
1626
+ "V56.0",
1627
+ "V56.31",
1628
+ "V56.32",
1629
+ "V56.8"
1630
+ ]
1631
+ }
1632
+ ]
1633
+ }
1634
+ ],
1635
+ "right": [
1636
+ "time_window",
1637
+ [
1638
+ "icd9_procedure",
1639
+ "39.95",
1640
+ "54.98"
1641
+ ],
1642
+ {
1643
+ "start": "0",
1644
+ "end": "60d"
1645
+ }
1646
+ ]
1647
+ }
1648
+ ]
1649
+ ```
1650
+
1651
+ ### Mortality after Myocardial Infarction #3
1652
+
1653
+ - Person Died
1654
+ - And Occurrence of 410\* prior to death
1655
+ - And either
1656
+ - MI diagnosis within 30 days prior to 410
1657
+ - MI therapy within 60 days after 410
1658
+
1659
+ ```ConceptQL
1660
+ [
1661
+ "during",
1662
+ {
1663
+ "left": [
1664
+ "before",
1665
+ {
1666
+ "left": [
1667
+ "icd9",
1668
+ "410*"
1669
+ ],
1670
+ "right": [
1671
+ "death",
1672
+ true
1673
+ ]
1674
+ }
1675
+ ],
1676
+ "right": [
1677
+ "union",
1678
+ [
1679
+ "time_window",
1680
+ [
1681
+ "union",
1682
+ [
1683
+ "cpt",
1684
+ "0146T",
1685
+ "75898",
1686
+ "82554",
1687
+ "92980",
1688
+ "93010",
1689
+ "93233",
1690
+ "93508",
1691
+ "93540",
1692
+ "93545"
1693
+ ],
1694
+ [
1695
+ "icd9_procedure",
1696
+ "00.24",
1697
+ "36.02",
1698
+ "89.53",
1699
+ "89.57",
1700
+ "89.69"
1701
+ ],
1702
+ [
1703
+ "loinc",
1704
+ "10839-9",
1705
+ "13969-1",
1706
+ "18843-3",
1707
+ "2154-3",
1708
+ "33204-9",
1709
+ "48425-3",
1710
+ "49259-5",
1711
+ "6597-9",
1712
+ "8634-8"
1713
+ ]
1714
+ ],
1715
+ {
1716
+ "start": "-30d",
1717
+ "end": "0"
1718
+ }
1719
+ ],
1720
+ [
1721
+ "time_window",
1722
+ [
1723
+ "union",
1724
+ [
1725
+ "cpt",
1726
+ "0146T",
1727
+ "75898",
1728
+ "82554",
1729
+ "92980",
1730
+ "93010",
1731
+ "93233"
1732
+ ],
1733
+ [
1734
+ "icd9_procedure",
1735
+ "00.24",
1736
+ "36.02",
1737
+ "89.53",
1738
+ "89.57",
1739
+ "89.69"
1740
+ ]
1741
+ ],
1742
+ {
1743
+ "start": "",
1744
+ "end": "60d"
1745
+ }
1746
+ ]
1747
+ ]
1748
+ }
1749
+ ]
1750
+ ```
1751
+
1752
+ ### GI Ulcer Hospitalization 2 (5000001002)
1753
+
1754
+ - Occurrence of GI Ulcer diagnostic code
1755
+ - Hospitalization at time of diagnostic code
1756
+ - At least one diagnostic procedure during same hospitalization
1757
+
1758
+ ```ConceptQL
1759
+ # We use the fact that conditions, observations, and procedures all can be tied to a visit_occurrence to find situations where the appropriate conditions, diagnostic procedures, and place of service all occur in the same visit_occurrence
1760
+ [
1761
+ "union",
1762
+ [
1763
+ "place_of_service_code",
1764
+ "21"
1765
+ ],
1766
+ [
1767
+ "visit_occurrence",
1768
+ [
1769
+ "icd9",
1770
+ "410"
1771
+ ]
1772
+ ],
1773
+ [
1774
+ "visit_occurrence",
1775
+ [
1776
+ "union",
1777
+ [
1778
+ "cpt",
1779
+ "0008T",
1780
+ "3142F",
1781
+ "43205",
1782
+ "43236",
1783
+ "76975",
1784
+ "91110",
1785
+ "91111"
1786
+ ],
1787
+ [
1788
+ "hcpcs",
1789
+ "B4081",
1790
+ "B4082"
1791
+ ],
1792
+ [
1793
+ "icd9_procedure",
1794
+ "42.22",
1795
+ "42.23",
1796
+ "44.13",
1797
+ "45.13",
1798
+ "52.21",
1799
+ "97.01"
1800
+ ],
1801
+ [
1802
+ "loinc",
1803
+ "16125-7",
1804
+ "17780-8",
1805
+ "40820-3",
1806
+ "50320-1",
1807
+ "5177-1",
1808
+ "7901-2"
1809
+ ]
1810
+ ]
1811
+ ]
1812
+ ]
1813
+ ```
1814
+
1815
+ ## Appendix C - Under Development
1816
+
1817
+ ConceptQL is not yet fully specified. These are modifications/enhancements that are under consideration. These ideas are most likely not completely refined and might actually represent changes that would fundamentally break ConceptQL.
1818
+
1819
+ ### Todo List
1820
+
1821
+ 1. Handle costs
1822
+ - How do we aggregate?
1823
+ 1. How do we count?
1824
+ 1. How do we handle missing values in streams?
1825
+ - For instance, missing DoB on patient?
1826
+ 1. What does it mean to pass a date range as an L stream?
1827
+ - I'm thinking we pass through no results
1828
+ - Turns out that, as implemented, a date_range is really a person_stream where the start and end dates represent the range (instead of the date of birth) so we're probably OK
1829
+ 1. How do we want to look up standard vocab concepts?
1830
+ - I think Marc’s approach is a bit heavy-handed
1831
+
1832
+ Some statements maybe very useful and it would be handy to reuse the bulk of the statement, but perhaps vary just a few things about it. ConceptQL supports the idea of using variables to represent sub-expressions. The variable operator is used as a place holder to say "some criteria set belongs here". That variable can be defined in another part of the criteria set and will be used in all places the variable operator appears.
1833
+
1834
+ ### Future Work for Define and Recall
1835
+
1836
+ I'd like to make it so if a variable operator is used, but not defined, the algorithm is still valid, but will fail to run until a definition for all missing variables is provided.
1837
+
1838
+ But I don't have a good feel for:
1839
+
1840
+ - Whether we should have users name the variables, or auto-assign a name?
1841
+ - We risk name collisions if a algorithm includes a sub-algorithm with the same variable name
1842
+ - Probably need to name space all variables
1843
+ - How to prompt users to enter values for variables in a concept
1844
+ - If we have name-spaced variables and sub-algorithms needing values, how do we show this in a coherent manner to a user?
1845
+ - We'll need to do a pass through a algorithm to find all variables and prompt a user, then do another pass through the algorithm before attempting to execute it to ensure all variables have values
1846
+ - Do we throw an exception if not?
1847
+ - Do we require calling programs to invoke a check on the algorithm before generating the query?
1848
+ - Perhaps slot is a different operator from "define"
1849
+
1850
+ ### Considerations for Values
1851
+
1852
+ I'm considering defaulting each value_as\_\* column to some value.
1853
+
1854
+ - numeric => 1
1855
+ - concept_id => 0
1856
+ - Or maybe the concept_id of the main concept_id value from the row?
1857
+ - This would be confusing when pulling from the observation table
1858
+ - What's the "main" concept_id of a person?
1859
+ - Hm. This feels a bit less like a good idea now
1860
+ - string
1861
+ - source_value?
1862
+ - Boy, this one is even harder to default
1863
+
1864
+ ```ConceptQL
1865
+ # All MIs, defaulting value_as_numeric to 1, concept_id to concept id for 412, string to condition_source_value
1866
+ [
1867
+ "icd9",
1868
+ "412"
1869
+ ]
1870
+ ```
1871
+
1872
+ ### Filter Operator
1873
+
1874
+ Inspired by person_filter, why not just have a "filter" operator that filters L by R. Takes L, R, and an "as" option. As option temporarily casts the L and R streams to the type specified by :as and then does person by person comparison, only keeping rows that occur on both sides. Handy for keeping procedures that coincide with conditions without fully casting the streams:
1875
+
1876
+ ```ConceptQL
1877
+ # All 99214's where person was irritable during a visit
1878
+ [
1879
+ "filter",
1880
+ {
1881
+ "left": [
1882
+ "cpt",
1883
+ "99214"
1884
+ ],
1885
+ "right": [
1886
+ "icd9",
1887
+ "799.22"
1888
+ ],
1889
+ "as": "visit_occurrence"
1890
+ }
1891
+ ]
1892
+ ```
1893
+
1894
+ person_filter then becomes a special case of general filter:
1895
+
1896
+ ```ConceptQL
1897
+ # All 99214's where person was irritable at some point in the data
1898
+ [
1899
+ "filter",
1900
+ {
1901
+ "left": [
1902
+ "cpt",
1903
+ "99214"
1904
+ ],
1905
+ "right": [
1906
+ "icd9",
1907
+ "799.22"
1908
+ ],
1909
+ "as": "person"
1910
+ }
1911
+ ]
1912
+ ```
1913
+
1914
+ Filter operator is the opposite of Except. It only includes L if R matches.
1915
+
1916
+ ### AS option for Except
1917
+
1918
+ Just like Filter has an :as option, add one to Except operator. This would simplify some of the algorithms I've developed.
1919
+
1920
+ ### How to Handle fact_relationship Table from CDMv5
1921
+
1922
+ Each relationship type could be a binary operator box read as L <relationship\> R. E.g. L 'downstream of' R would take a L stream and only pass on downstreams of rows in R stream.
1923
+
1924
+ We could implement a single operator that takes a relationship as an argument (on top of the L and R arguments) or we could create a operator class for each relationship. I think it would be better to have a single relationship operator class and take the relationship as the argument.
1925
+
1926
+ The next question is: how do we actually join the two streams? I suppose we could translate each "type" into a "domain" and then join where l.domain = domain_concept_id_1 and l.entity_id = fact_id_1 and R.domain = domain_concept_id_2 and R.entity_id = fact_id_2 where the relationship chosen = relationship_concept_id.
1927
+
1928
+ Yup, that should work. Phew!
1929
+
1930
+ [^AIA]: J. Allen. Maintaining knowledge about temporal intervals. Communications of the ACM (1983) vol. 26 (11) pp. 832-843