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/converter.rb ADDED
@@ -0,0 +1,33 @@
1
+ require_relative '../lib/conceptql'
2
+ require 'pp'
3
+ require 'json'
4
+
5
+ $converter = ConceptQL::Converter.new
6
+ def my_pp(obj)
7
+ #PP.pp(obj, ''.dup, 10)
8
+ JSON.pretty_generate(obj)
9
+ end
10
+
11
+ def convert(cql)
12
+ header = []
13
+ header << cql.shift while cql.first =~ /^[`#]/
14
+ footer = [cql.pop]
15
+ if cql.first =~ /^\[/
16
+ cql = my_pp(eval(cql.join))
17
+ else
18
+ cql = my_pp($converter.convert(eval(cql.join)))
19
+ end
20
+ [header, cql, "\n", footer].flatten
21
+ end
22
+
23
+ lines = File.readlines('doc/spec.md')
24
+ chunks = lines.slice_before { |l| l =~ /```ConceptQL/ }.to_a
25
+ outputs = []
26
+ outputs << chunks.shift unless chunks.first =~ /```ConceptQL/
27
+ puts chunks.count
28
+ outputs += chunks.map do |chunk|
29
+ cql, *remainder = chunk.slice_after { |l| l =~ /^```\n$/ }.to_a
30
+ cql = convert(cql)
31
+ [cql, remainder].flatten#.tap { |arr| pp arr; gets }
32
+ end.flatten
33
+ File.write('/tmp/test.md', outputs.join)
data/doc/metadata.md ADDED
@@ -0,0 +1,89 @@
1
+ # A Bit About Metadata
2
+
3
+ `ConceptQL.metadata` produces a hash containing all relevant metadata about ConceptQL, specifically which categories and operators are available in ConceptQL.
4
+
5
+ The hash contains two keys: "categories" and "operators".
6
+
7
+ ## Metadata about Categories
8
+
9
+ The value of the "categories" hash is an array of hashes representing each available category in ConceptQL. Each hash has two key/value pairs:
10
+
11
+ - name
12
+ - The category's name
13
+ - priority
14
+ - The position the category should have if you were to list the categories in order
15
+
16
+ ## Metadata about Operators
17
+
18
+ Each operator in ConceptQL is listed in the metadata.json file under the "operators" key.
19
+
20
+ The operator metadata is a hash where the key is the name of an operator and the hash is the metadata specific to that operator.
21
+
22
+ The metadata for each operator should be complete enough that a UI can understand all of the parameters and constraints specific to that operator and render it accordingly. Essentially, the metadata should be complete enough that entirely new operators can appear in the metadata and the UI should be able to render that operator and its parameters without needing to change anything in the code for the UI.
23
+
24
+ ### Operator Metadata Outline
25
+
26
+ - min_upstreams
27
+ - 0 or 1
28
+ - 0 means this operator does not need inputs from an upstream operator
29
+ - 1 means this operator needs input from at least one upstream operator
30
+ - max_upstreams
31
+ - 0, 1, or 99
32
+ - 0 means this operator does not take input from an upstream operator
33
+ - 1 means this operator takes input from up to one upstream operator
34
+ - 99 means this operator takes input from unlimited upstream operators
35
+ - preferred_name
36
+ - If this option is present, this is the name of the operator to display in the UI
37
+ - If this option is missing, run the name of the operator through the equivalent of ActiveSupport#humanize
38
+ - operation
39
+ - The name of the operation
40
+ - This is the name to use when translating the structure in the UI into a ConceptQL statement
41
+ - options
42
+ - A hash of the parameters that an operation expects
43
+ - Key is the name of the parameters (run through ActiveSupport#humanize to get the name to display in the UI)
44
+ - Value is a hash described in Option Metadata Outline below
45
+ - categories
46
+ - An array of arrays representing the categories this operator is assigned to
47
+ - Each sub-array represents a path of categories and sub-categories that the operator is assigned to
48
+ - At the moment, all sub-arrays are single element arrays and no sub-categories are used
49
+ - So, it's safe to flatten the array of arrays and assign an operator to each of the categories in the flattened array
50
+ - **If an operator has no categories assigned, it should NOT appear in the UI**
51
+ - arguments
52
+ - Similar to options
53
+ - When the UI generates the corresponding ConceptQL, values assigned to arguments should be listed as elements 1 thru XX in the array that represents the current operator
54
+ - desc
55
+ - Description of the operator, to be displayed when the user is interacting with that operator
56
+ - predominant_domains
57
+ - A list of one or more domains that the operator is known to represent
58
+ - This should be used as a means to declare what domain color(s) to use to represent the operator and how many lines the operator should generate
59
+ - This option should only appear in selection operators and casting operators
60
+ - basic_type
61
+ - I don't know what this does but it seemed like information needed for Envy's JAM
62
+
63
+ ### Option Metadata Outline
64
+
65
+ - type
66
+ - Dictates what type of input the operator expects for this parameter
67
+ - Can be one of the following types:
68
+ - string
69
+ - A string of text
70
+ - integer
71
+ - A whole number, positive or negative
72
+ - boolean
73
+ - Either true or false
74
+ - Can be respresented by a checkbox or similar, toggleable UI item
75
+ - codelist
76
+ - Eventually the UI should provide a sophisticated means of selecting codes from a specific terminology (specified by the vocab option)
77
+ - For now, expect a comma delimited list of codes in a textarea
78
+ - upstream
79
+ - Indicates that we need input from an upstream operator
80
+ - vocab
81
+ - Specifies which terminology to use when presenting a list of codes to select from
82
+ - Should only be used when type is codelist
83
+ - options
84
+ - An array representing an enumeration of all possible values that can be used for this option/argument
85
+ - The UI should present only these options for a user to choose and disallow any other input from the user
86
+ - default
87
+ - The default value for this parameter
88
+ - required
89
+ - True if this parameter must have a value
data/doc/spec.md CHANGED
@@ -3,12 +3,13 @@
3
3
  ConceptQL (pronounced concept-Q-L) is a high-level language that allows researchers to unambiguously define their research algorithms.
4
4
 
5
5
  ## Motivation for ConceptQL
6
+
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:
7
8
 
8
9
  1. Methods sections of research papers commonly use natural language to specify the criteria used to build cohorts from a claims database.
9
10
  - Algorithms defined in natural language are often imprecise, open to multiple interpretations, and generally difficult to reproduce.
10
11
  - Researchers could benefit from a language that removes the ambiguity of natural language while increasing the reproducibility of their research algorithms.
11
- 2. Querying against claims databases is often difficult.
12
+ 1. Querying against claims databases is often difficult.
12
13
  - Hand-coding algorithms to extract cohorts from datasets is time-consuming, error-prone, and opaque.
13
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.
14
15
 
@@ -17,16 +18,38 @@ 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.
18
19
 
19
20
  For instance, using ConceptQL we can take a statement that looks like this:
21
+
20
22
  ```YAML
21
23
  :icd9: '412'
22
24
  ```
23
25
 
24
26
  And generate a diagram that looks like this:
25
- ```ConceptQL
26
- { icd9: '412' }
27
+
28
+
29
+ ```YAML
30
+ ---
31
+ - icd9
32
+ - '412'
33
+
27
34
  ```
28
35
 
36
+ ![](spec/f6b4fc31703cfb6327bbbd4614af8bb72da6d39fa3d53ada63a70157f2fad80e.png)
37
+
38
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
39
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
40
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
41
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
42
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
43
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
44
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
45
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
46
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
47
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
48
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
49
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
50
+
29
51
  And generate SQL that looks like this:
52
+
30
53
  ```SQL
31
54
  SELECT *
32
55
  FROM cdm_data.condition_occurrence AS co
@@ -36,10 +59,10 @@ AND scm.source_vocabulary_id = 2
36
59
  AND scm.source_code = co.condition_source_value
37
60
  ```
38
61
 
39
- As stated above, one of the goals of ConcegtQL 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.
40
-
62
+ 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.
41
63
 
42
64
  ## ConceptQL Overview
65
+
43
66
  ### What ConceptQL Looks Like
44
67
 
45
68
  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.
@@ -47,43 +70,77 @@ I find seeing examples to be the quickest way to get a sense of a language. Her
47
70
  ```YAML
48
71
  # Example 1: A simple example in YAML
49
72
  # This is just a simple hash with a key of :icd9 and a value of 412
50
- # This example will search the condition_occurrence table for all conditions that match the ICD-9 concept of 412.
73
+ # This example will search the condition_occurrence table for all conditions that match the ICD-9 code 412.
51
74
  ---
52
75
  :icd9: '412'
53
76
  ```
54
77
 
55
78
  ### ConceptQL Diagrams
79
+
56
80
  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:
57
- ```ConceptQL
58
- # All Conditions Matching MI
59
- { icd9: '412' }
81
+
82
+
83
+ ```YAML
84
+ ---
85
+ - icd9
86
+ - '412'
87
+
60
88
  ```
61
89
 
90
+ ![](spec/f6b4fc31703cfb6327bbbd4614af8bb72da6d39fa3d53ada63a70157f2fad80e.png)
91
+
92
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
93
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
94
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
95
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
96
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
97
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
98
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
99
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
100
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
101
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
102
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
103
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
104
+
105
+ 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:
106
+
107
+
108
+ ```YAML
109
+ ---
110
+ - first
111
+ - - cpt
112
+ - '99214'
62
113
 
63
- Each oval depicts a "node", or rather, a ConceptQL expression. An arrow between a pair of nodes indicates that the results from the node on the tail of the arrow pass on to the node at the head of the arrow. A simple example should help here:
64
- ```ConceptQL
65
- # First Office Visit Per Patient
66
- {
67
- first: {
68
- cpt: '99214'
69
- }
70
- }
71
114
  ```
72
115
 
116
+ ![](spec/39d6a8eb71cae51b1d6937c97134e51f04fd47c54535ff0915fe6a8b4f197fb2.png)
73
117
 
74
- 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 node operates. Fortunately, this document will (hopefully) impart that knowledge to you.
118
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
119
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
120
+ | 2 | 48 | procedure_occurrence | 2009-07-03 | 2009-07-03 | 99214 |
121
+ | 5 | 118 | procedure_occurrence | 2008-12-14 | 2008-12-14 | 99214 |
122
+ | 6 | 167 | procedure_occurrence | 2009-09-12 | 2009-09-12 | 99214 |
123
+ | 7 | 376 | procedure_occurrence | 2008-08-13 | 2008-08-13 | 99214 |
124
+ | 8 | 609 | procedure_occurrence | 2008-02-27 | 2008-02-27 | 99214 |
125
+ | 9 | 652 | procedure_occurrence | 2009-09-11 | 2009-09-11 | 99214 |
126
+ | 10 | 681 | procedure_occurrence | 2009-05-09 | 2009-05-09 | 99214 |
127
+ | 11 | 758 | procedure_occurrence | 2008-06-17 | 2008-06-17 | 99214 |
128
+ | 12 | 847 | procedure_occurrence | 2008-02-11 | 2008-02-11 | 99214 |
129
+ | 13 | 1102 | procedure_occurrence | 2008-01-24 | 2008-01-24 | 99214 |
75
130
 
76
- Please note that all of my diagrams end with an arrow pointing at nothing. You'll see why soon.
131
+ 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.
77
132
 
133
+ Please note that all of my diagrams end with an arrow pointing at nothing. You'll see why soon.
78
134
 
79
135
  ### Think of Results as a Stream
80
- I draw my ConceptQL diagrams with leaf nodes at the top and the "trunk" nodes at the bottom. I like to think of the results of a ConceptQL statement as a flowing stream of data. The leaf nodes, or nodes 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 node to the next.
81
136
 
82
- The trailing arrow in the diagrams serves as a reminder that ConceptQL yields a stream of results.
137
+ 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.
83
138
 
139
+ The trailing arrow in the diagrams serves as a reminder that ConceptQL yields a stream of results.
84
140
 
85
141
  ### Streams have Types
86
- You might have noticed that the nodes and edges in the diagrams often have a color. That color represents what "type" of stream the node 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):
142
+
143
+ 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):
87
144
 
88
145
  - condition_occurrence
89
146
  - red
@@ -106,28 +163,66 @@ You might have noticed that the nodes and edges in the diagrams often have a col
106
163
  - visit_occurrence
107
164
  - orange
108
165
 
109
- 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 node. When certain nodes, particularly set and temporal operation nodes, 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.
166
+ 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.
110
167
 
111
168
  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.
112
169
 
113
-
114
170
  ### What *are* Streams Really?
171
+
115
172
  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.
116
173
 
117
174
  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.
118
175
 
119
176
  So when we execute this ConceptQL statement, the resulting "stream" is all the person IDs for all male patients in the database:
120
- ```ConceptQL
121
- # All Male Patients
122
- { gender: 'Male' }
177
+
178
+
179
+ ```YAML
180
+ ---
181
+ - gender
182
+ - Male
183
+
123
184
  ```
124
185
 
186
+ ![](spec/c82077b9455d0f9abc2c45ee1a298e38b99c9ce9cd685f65d87b376d7718d7ad.png)
187
+
188
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
189
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
190
+ | 1 | 1 | person | 1923-05-01 | 1923-05-01 | 00013D2EFD8E45D1 |
191
+ | 2 | 2 | person | 1943-01-01 | 1943-01-01 | 00016F745862898F |
192
+ | 4 | 4 | person | 1941-06-01 | 1941-06-01 | 00021CA6FF03E670 |
193
+ | 5 | 5 | person | 1936-08-01 | 1936-08-01 | 00024B3D2352D2D0 |
194
+ | 6 | 6 | person | 1943-10-01 | 1943-10-01 | 0002DAE1C81CC70D |
195
+ | 7 | 7 | person | 1922-07-01 | 1922-07-01 | 0002F28CE057345B |
196
+ | 8 | 8 | person | 1935-09-01 | 1935-09-01 | 000308435E3E5B76 |
197
+ | 12 | 12 | person | 1929-06-01 | 1929-06-01 | 00048EF1F4791C68 |
198
+ | 14 | 14 | person | 1934-05-01 | 1934-05-01 | 00052705243EA128 |
199
+ | 16 | 16 | person | 1934-01-01 | 1934-01-01 | 0007E57CC13CE880 |
200
+
125
201
  When we execute this ConceptQL statement, the resulting "stream" is all condition_occurrence IDs that match ICD-9 799.22:
126
- ```ConceptQL
127
- # All Condition Occurrences that match ICD-9 799.22
128
- { icd9: '799.22' }
202
+
203
+
204
+ ```YAML
205
+ ---
206
+ - icd9
207
+ - '799.22'
208
+
129
209
  ```
130
210
 
211
+ ![](spec/05f9b844571ffceeed2def3025fb60c68552817b8b73d3c8a76939dbc08b7c65.png)
212
+
213
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
214
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
215
+ | 273 | 33363 | condition_occurrence | 2010-06-17 | 2010-06-17 | 799.22 |
216
+ | 440 | 51450 | condition_occurrence | 2009-01-12 | 2009-01-12 | 799.22 |
217
+ | 1783 | 206904 | condition_occurrence | 2008-03-08 | 2008-03-08 | 799.22 |
218
+ | 1830 | 211909 | condition_occurrence | 2010-06-24 | 2010-06-24 | 799.22 |
219
+ | 2086 | 238625 | condition_occurrence | 2008-05-24 | 2008-05-24 | 799.22 |
220
+ | 2272 | 260093 | condition_occurrence | 2009-09-19 | 2009-09-19 | 799.22 |
221
+ | 2525 | 288414 | condition_occurrence | 2009-04-17 | 2009-04-17 | 799.22 |
222
+ | 2772 | 317847 | condition_occurrence | 2009-09-08 | 2009-09-08 | 799.22 |
223
+ | 2924 | 334949 | condition_occurrence | 2009-01-24 | 2009-01-24 | 799.22 |
224
+ | 4072 | 473603 | condition_occurrence | 2008-05-15 | 2008-05-15 | 799.22 |
225
+
131
226
  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.
132
227
 
133
228
  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:
@@ -139,274 +234,499 @@ When a ConceptQL statement is executed, it yields a final set of streams that ar
139
234
 
140
235
  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.
141
236
 
142
- ## Criterion Nodes
237
+ ## Selection Operators
143
238
 
144
- Criterion nodes 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 criterion. Criterion nodes are always leaf nodes.
239
+ 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.
145
240
 
146
- There are _many_ criterion nodes. A list of currently implemented nodes is available in Appendix A.
241
+ There are _many_ selection operators. A list of currently implemented operators is available in Appendix A.
147
242
 
148
- ## All Other Nodes
243
+ ## All Other Operators i.e. Mutation Operators
149
244
 
150
- Virtually all other nodes add, remove, filter, or otherwise alter streams of results. They are discussed in this section.
245
+ Virtually all other operators add, remove, filter, or otherwise alter streams of results. They are discussed in this section.
151
246
 
152
- ## Set Operation Nodes
153
- Because streams represent sets of results, its makes sense to include a nodes that operate on sets
247
+ ## Set Operators
248
+
249
+ Because streams represent sets of results, its makes sense to include a operators that operate on sets
154
250
 
155
251
  ### Union
156
- - Takes any number of upstream nodes and aggregates their streams
252
+
253
+ - Takes any number of upstream operators and aggregates their streams
157
254
  - Unions together streams with identical types
158
255
  - Think of streams with the same type flowing together into a single stream
159
256
  - We're really just gathering the union of all IDs for identically-typed streams
160
257
  - Streams with the different types flow along together concurrently without interacting
161
258
  - 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
162
- ```ConceptQL
163
- # Two streams of the same type (condition_occurrence) joined into a single stream
164
- {
165
- union: [
166
- { icd9: '412' },
167
- { icd9: '799.22' }
168
- ]
169
- }
170
- ```
171
- ```ConceptQL
172
- # Two streams of the same type (condition_occurrence) joined into a single stream, then a different stream (visit_occurrence) flows concurrently
173
- {
174
- union: [
175
- {union: [
176
- { icd9: '412' },
177
- { icd9: '799.22' }
178
- ]},
179
- { place_of_service: 'Inpatient' }
180
- ]
181
- }
182
- ```
183
- ```ConceptQL
184
- # 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)
185
- {
186
- union: [
187
- { icd9: '412' },
188
- { icd9: '799.22' },
189
- { place_of_service: 'Inpatient' }
190
- ]
191
- }
259
+
260
+
261
+ ```YAML
262
+ ---
263
+ - union
264
+ - - icd9
265
+ - '412'
266
+ - - icd9
267
+ - '799.22'
268
+
192
269
  ```
193
270
 
271
+ ![](spec/ea935ac31f3b57ff373646780a1fba34a38c9e086dc771eb7fc16c65a7e20cfc.png)
272
+
273
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
274
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
275
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
276
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
277
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
278
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
279
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
280
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
281
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
282
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
283
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
284
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
285
+
286
+
287
+ ```YAML
288
+ ---
289
+ - union
290
+ - - union
291
+ - - icd9
292
+ - '412'
293
+ - - icd9
294
+ - '799.22'
295
+ - - place_of_service_code
296
+ - '21'
297
+
298
+ ```
299
+
300
+ ![](spec/f766f2e3aa13420e3ba0f823ac7956b311ed7c6c20be26b72324fadd87f36712.png)
301
+
302
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
303
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
304
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
305
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
306
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
307
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
308
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
309
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
310
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
311
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
312
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
313
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
314
+
315
+
316
+ ```YAML
317
+ ---
318
+ - union
319
+ - - icd9
320
+ - '412'
321
+ - - icd9
322
+ - '799.22'
323
+ - - place_of_service_code
324
+ - '21'
325
+
326
+ ```
327
+
328
+ ![](spec/a79274742cf6fac6f6c9f4a0eb651aeb452f9c43b537c8e6ccaefecd05b7105c.png)
329
+
330
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
331
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
332
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
333
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
334
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
335
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
336
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
337
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
338
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
339
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
340
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
341
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
342
+
194
343
  ### Intersect
344
+
195
345
  1. Group incoming streams by type
196
- 2. For each group of same-type streams
197
- 1. Intersect all streams, yielding a single stream that contains only those IDs common to those streams
198
- 3. A single stream for each incoming type is sent downstream
199
- 1. If only a single stream of a type is upstream, that stream is essentially unaltered as it is passed downstream
200
- ```ConceptQL
201
- # Yields a single stream of all Conditions where MI was Primary Diagnosis. This involves two Condition streams and so results are intersected
202
- {
203
- intersect: [
204
- { icd9: '412' },
205
- { primary_diagnosis: true }
206
- ]
207
- }
208
- ```
209
- ```ConceptQL
210
- # 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
211
- {
212
- intersect: [
213
- { icd9: '412' },
214
- { gender: 'Male' }
215
- ]
216
- }
217
- ```
218
- ```ConceptQL
219
- # Yields two streams: a stream of all Conditions where MI was Primary Diagnosis and a stream of all White, Male patients.
220
- {
221
- intersect: [
222
- { icd9: '412' },
223
- { primary_diagnosis: true },
224
- { gender: 'Male' },
225
- { race: 'White' }
226
- ]
227
- }
346
+ 1. For each group of same-type streams
347
+ a. Intersect all streams, yielding a single stream that contains only those IDs common to those streams
348
+ 1. A single stream for each incoming type is sent downstream
349
+ a. If only a single stream of a type is upstream, that stream is essentially unaltered as it is passed downstream
350
+
351
+
352
+ ```YAML
353
+ ---
354
+ - intersect
355
+ - - icd9
356
+ - '412'
357
+ - - primary_diagnosis
358
+ - true
359
+
228
360
  ```
229
361
 
362
+ ![](spec/af5ae3787e80bf0771f18f1a04fe4c5d9291e1e0f963ac408a7bc198d2f1ee28.png)
363
+
364
+ ```No Results. Statement is experimental.```
365
+
366
+
367
+ ```YAML
368
+ ---
369
+ - intersect
370
+ - - icd9
371
+ - '412'
372
+ - - gender
373
+ - Male
374
+
375
+ ```
376
+
377
+ ![](spec/514f263e976d07c0d9e0a86c79bcbdcddc7d444d7b72135294ad78758effd28f.png)
378
+
379
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
380
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
381
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
382
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
383
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
384
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
385
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
386
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
387
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
388
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
389
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
390
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
391
+
392
+
393
+ ```YAML
394
+ ---
395
+ - intersect
396
+ - - icd9
397
+ - '412'
398
+ - - primary_diagnosis
399
+ - true
400
+ - - gender
401
+ - Male
402
+ - - race
403
+ - White
404
+
405
+ ```
406
+
407
+ ![](spec/11f57941951bad5a75f9a16f38a31a3c6bf3046a475aac6e398e780892fab4ad.png)
408
+
409
+ ```No Results. Statement is experimental.```
410
+
230
411
  ### Complement
231
- This node will take the complement of each set of IDs in the incoming streams.
232
- ```ConceptQL
233
- # All non-MI Conditions
234
- {
235
- complement: { icd9: '412' }
236
- }
412
+
413
+ This operator will take the complement of each set of IDs in the incoming streams.
414
+
415
+
416
+ ```YAML
417
+ ---
418
+ - complement
419
+ - - icd9
420
+ - '412'
421
+
237
422
  ```
238
423
 
424
+ ![](spec/c2157d8a6b73abe4f22ba5042159f32502c74bf6d762be28d2df6831586822c7.png)
425
+
426
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
427
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
428
+ | 1 | 1 | condition_occurrence | 2010-03-12 | 2010-03-13 | 780.2 |
429
+ | 1 | 2 | condition_occurrence | 2010-03-12 | 2010-03-13 | 788.20 |
430
+ | 1 | 3 | condition_occurrence | 2010-03-12 | 2010-03-13 | V45.01 |
431
+ | 1 | 4 | condition_occurrence | 2010-03-12 | 2010-03-13 | 428.0 |
432
+ | 1 | 5 | condition_occurrence | 2010-03-12 | 2010-03-13 | 272.0 |
433
+ | 1 | 6 | condition_occurrence | 2010-03-12 | 2010-03-13 | 401.9 |
434
+ | 1 | 7 | condition_occurrence | 2010-03-12 | 2010-03-13 | V45.02 |
435
+ | 1 | 8 | condition_occurrence | 2010-03-12 | 2010-03-13 | 733.00 |
436
+ | 1 | 9 | condition_occurrence | 2010-03-12 | 2010-03-13 | E933.0 |
437
+ | 1 | 10 | condition_occurrence | 2008-09-04 | 2008-09-04 | V58.41 |
438
+
239
439
  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:
240
- ```ConceptQL
241
- # All Conditions where the Condition isn't an MI as the Primary Diagnosis
242
- {
243
- complement: {
244
- union: [
245
- { icd9: '412' },
246
- { primary_diagnosis: true }
247
- ]
248
- }
249
- }
250
- ```
251
- ```ConceptQL
252
- # All Conditions where the Condition isn't an MI as the Primary Diagnosis (same as above)
253
- {
254
- intersect: [
255
- { complement: { icd9: '412' } },
256
- { complement: { primary_diagnosis: true } }
257
- ]
258
- }
440
+
441
+
442
+ ```YAML
443
+ ---
444
+ - complement
445
+ - - union
446
+ - - icd9
447
+ - '412'
448
+ - - primary_diagnosis
449
+ - true
450
+
259
451
  ```
260
452
 
453
+ ![](spec/02f44ad35d266ddd0a4df1691d26bf4a297b30604fc3f44b0391d6d852d23a9f.png)
454
+
455
+ ```No Results. Statement is experimental.```
456
+
457
+
458
+ ```YAML
459
+ ---
460
+ - intersect
461
+ - - complement
462
+ - - icd9
463
+ - '412'
464
+ - - complement
465
+ - - primary_diagnosis
466
+ - true
467
+
468
+ ```
469
+
470
+ ![](spec/a4450e8c0fe0e2fde92fe9bd61952f907b1976c1aa3ba963b809bed079d42b09.png)
471
+
472
+ ```No Results. Statement is experimental.```
473
+
261
474
  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:
262
- ```ConceptQL
263
- # 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
264
- {
265
- complement: {
266
- union: [
267
- { icd9: '412' },
268
- { primary_diagnosis: true },
269
- { cpt: '99214' }
270
- ]
271
- }
272
- }
273
- ```
274
- ```ConceptQL
275
- # 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)
276
- {
277
- intersect: [
278
- { complement: { icd9: '412' } },
279
- { complement: { primary_diagnosis: true } },
280
- { complement: { cpt: '99214' } }
281
- ]
282
- }
283
- ```
284
- ```ConceptQL
285
- # 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)
286
- {
287
- union: [
288
- {
289
- intersect: [
290
- { complement: { icd9: '412' } },
291
- { complement: { primary_diagnosis: true } }
292
- ]
293
- },
294
- { complement: { cpt: '99214' } }
295
- ]
296
- }
475
+
476
+
477
+ ```YAML
478
+ ---
479
+ - complement
480
+ - - union
481
+ - - icd9
482
+ - '412'
483
+ - - primary_diagnosis
484
+ - true
485
+ - - cpt
486
+ - '99214'
487
+
488
+ ```
489
+
490
+ ![](spec/dbc66b3ae6bd7123d77dd04b64f8a24498d048725a55c5340b15f5ae0a1ff307.png)
491
+
492
+ ```No Results. Statement is experimental.```
493
+
494
+
495
+ ```YAML
496
+ ---
497
+ - intersect
498
+ - - complement
499
+ - - icd9
500
+ - '412'
501
+ - - complement
502
+ - - primary_diagnosis
503
+ - true
504
+ - - complement
505
+ - - cpt
506
+ - '99214'
507
+
508
+ ```
509
+
510
+ ![](spec/a9b4528726adec2a90f3f00139d8d0492f13c51f03c2f9ed6a5134b1b26b44a9.png)
511
+
512
+ ```No Results. Statement is experimental.```
513
+
514
+
515
+ ```YAML
516
+ ---
517
+ - union
518
+ - - intersect
519
+ - - complement
520
+ - - icd9
521
+ - '412'
522
+ - - complement
523
+ - - primary_diagnosis
524
+ - true
525
+ - - complement
526
+ - - cpt
527
+ - '99214'
528
+
297
529
  ```
298
530
 
531
+ ![](spec/a4bc7382a1154ea9856544fd48418f3dd9ce474ca94b8859fc323749c6cc1f55.png)
532
+
533
+ ```No Results. Statement is experimental.```
299
534
 
300
535
  ### Except
301
- This node takes two sets of incoming streams, a left-hand stream and a right-hand stream. The node matches like-type streams between the left-hand and right-hand streams. The node removes any results in the left-hand stream if they appear in the right-hand stream. The node passes only results for the left-hand stream downstream. The node discards all results in the right-hand stream. For example:
302
- ```ConceptQL
303
- # All Conditions that are MI unless they are primary diagnoses
304
- {
305
- except: {
306
- left: { icd9: '412' },
307
- right: { primary_diagnosis: true }
308
- }
309
- }
310
- ```
311
- ```ConceptQL
312
- # All Conditions that are MI unless they are primary diagnoses (same as above)
313
- {
314
- intersect: [
315
- { icd9: '412' },
316
- { complement: { primary_diagnosis: true } }
317
- ]
318
- }
536
+
537
+ 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:
538
+
539
+
540
+ ```YAML
541
+ ---
542
+ - except
543
+ - :left:
544
+ - icd9
545
+ - '412'
546
+ :right:
547
+ - primary_diagnosis
548
+ - true
549
+
319
550
  ```
320
551
 
321
- If the left-hand stream has no types that match the right-hand stream, the left-hand stream passes through unaffected:
322
- ```ConceptQL
323
- # All Conditions that are MI
324
- {
325
- except: {
326
- left: { icd9: '412' },
327
- right: { cpt: '99214' }
328
- }
329
- }
552
+ ![](spec/462153be527b28dc2cb5259c0aec62e1f529e8b60dc6e9c23fd1e06e8be933c9.png)
553
+
554
+ ```No Results. Statement is experimental.```
555
+
556
+
557
+ ```YAML
558
+ ---
559
+ - intersect
560
+ - - icd9
561
+ - '412'
562
+ - - complement
563
+ - - primary_diagnosis
564
+ - true
565
+
330
566
  ```
331
567
 
568
+ ![](spec/da450cdd0c94a1301bd98560339a45caa8041e09974352a56ecfb144e9a5e4d4.png)
569
+
570
+ ```No Results. Statement is experimental.```
571
+
572
+ If the left-hand stream has no types that match the right-hand stream, the left-hand stream passes through unaffected:
573
+
574
+
575
+ ```YAML
576
+ ---
577
+ - except
578
+ - :left:
579
+ - icd9
580
+ - '412'
581
+ :right:
582
+ - cpt
583
+ - '99214'
584
+
585
+ ```
586
+
587
+ ![](spec/253845fe6162621af407ebd110296ff4f6d8a3f23ec75dfb4ea8cda30be71262.png)
588
+
589
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
590
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
591
+ | 6354 | 730080 | condition_occurrence | 2009-05-22 | 2009-05-22 | 412 |
592
+ | 405 | 47310 | condition_occurrence | 2010-04-21 | 2010-04-21 | 412 |
593
+ | 37067 | 4195911 | condition_occurrence | 2009-02-26 | 2009-02-26 | 412 |
594
+ | 31965 | 3622631 | condition_occurrence | 2008-05-09 | 2008-05-09 | 412 |
595
+ | 62025 | 6984372 | condition_occurrence | 2009-08-24 | 2009-08-24 | 412 |
596
+ | 7548 | 861875 | condition_occurrence | 2010-08-19 | 2010-09-08 | 412 |
597
+ | 72056 | 8102530 | condition_occurrence | 2008-02-14 | 2008-02-17 | 412 |
598
+ | 29548 | 3346625 | condition_occurrence | 2008-02-12 | 2008-02-19 | 412 |
599
+ | 51224 | 5768620 | condition_occurrence | 2010-04-21 | 2010-04-21 | 412 |
600
+ | 62051 | 6987562 | condition_occurrence | 2009-06-16 | 2009-06-16 | 412 |
601
+
332
602
  And just to show how multiple streams behave:
333
- ```ConceptQL
334
- # 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)
335
- {
336
- except: {
337
- left: {
338
- union: [
339
- { icd9: '412' },
340
- { gender: 'Male' },
341
- { cpt: '99214' }
342
- ]
343
- },
344
- right: {
345
- union: [
346
- { primary_diagnosis: true },
347
- { race: 'White' },
348
- ]
349
- }
350
- }
351
- }
352
- ```
353
- ### Discussion about Set Operation Nodes
354
- #### Union Nodes
355
- *Q. Why should we allow two different types of streams to continue downstream concurrently?*
603
+
604
+
605
+ ```YAML
606
+ ---
607
+ - except
608
+ - :left:
609
+ - union
610
+ - - icd9
611
+ - '412'
612
+ - - gender
613
+ - Male
614
+ - - cpt
615
+ - '99214'
616
+ :right:
617
+ - union
618
+ - - primary_diagnosis
619
+ - true
620
+ - - race
621
+ - White
622
+
623
+ ```
624
+
625
+ ![](spec/f0c734b099841a754ae0366afb00e992ad4814479b65e4a7de23c6e3dd85c09a.png)
626
+
627
+ ```No Results. Statement is experimental.```
628
+
629
+ ### Discussion about Set Operators
630
+
631
+ #### Union Operators
632
+
633
+ ##### Q. Why should we allow two different types of streams to continue downstream concurrently?
356
634
 
357
635
  - This feature lets us do interesting things, like find the first occurrence of either an MI or Death as in the example below
358
636
  - Throw in a few more criteria and you could find the first occurrence of all censor events for each patient
359
637
 
360
- ```ConceptQL
361
- # First occurrence of either MI or Death for each patient
362
- {
363
- first: {
364
- union: [
365
- { icd9: '412' },
366
- { death: true }
367
- ]
368
- }
369
- }
638
+
639
+ ```YAML
640
+ ---
641
+ - first
642
+ - - union
643
+ - - icd9
644
+ - '412'
645
+ - - death
646
+ - true
647
+
370
648
  ```
371
649
 
650
+ ![](spec/1102fa717b1c2df67af5220bf3ae219afafd79be7bba0c117e301983385ada52.png)
372
651
 
373
- Q. Why aren't all streams passed forward unaltered? Why union like-typed streams?
652
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
653
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
654
+ | 16 | 16 | death | 2010-12-01 | 2010-12-01 | |
655
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
656
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
657
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
658
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
659
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
660
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
661
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
662
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
663
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
664
+
665
+ ##### Q. Why aren't all streams passed forward unaltered? Why union like-typed streams?
374
666
 
375
667
  - 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
376
668
  - Essentially, these two diagrams would be identical:
377
669
 
378
- ```ConceptQL
379
- # Two streams: a stream of all Conditions matching either 412 or 799.22 and a stream of Procedures matching 99214
380
- {
381
- intersect: [
382
- {
383
- union: [
384
- { icd9: '412' },
385
- { icd9: '799.22' },
386
- ]
387
- },
388
- { cpt: '99214' }
389
- ]
390
- }
391
- ```
392
-
393
-
394
- ```ConceptQL
395
- # 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
396
- {
397
- intersect: [
398
- {
399
- intersect: [
400
- { icd9: '412' },
401
- { icd9: '799.22' },
402
- ]
403
- },
404
- { cpt: '99214' }
405
- ]
406
- }
407
- ```
408
-
409
- ## Time-oriented Nodes
670
+
671
+ ```YAML
672
+ ---
673
+ - intersect
674
+ - - union
675
+ - - icd9
676
+ - '412'
677
+ - - icd9
678
+ - '799.22'
679
+ - - cpt
680
+ - '99214'
681
+
682
+ ```
683
+
684
+ ![](spec/d64993258ffbef9406d9ab9136de7af530626b3a69e9eeb75835e11f11dabf62.png)
685
+
686
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
687
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
688
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
689
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
690
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
691
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
692
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
693
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
694
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
695
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
696
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
697
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
698
+
699
+
700
+ ```YAML
701
+ ---
702
+ - intersect
703
+ - - intersect
704
+ - - icd9
705
+ - '412'
706
+ - - icd9
707
+ - '799.22'
708
+ - - cpt
709
+ - '99214'
710
+
711
+ ```
712
+
713
+ ![](spec/defbd0b853d895802663f507761ad297d82e167f516c6082686a2a19b76012c5.png)
714
+
715
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
716
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
717
+ | 2 | 48 | procedure_occurrence | 2009-07-03 | 2009-07-03 | 99214 |
718
+ | 2 | 95 | procedure_occurrence | 2009-12-02 | 2009-12-02 | 99214 |
719
+ | 5 | 118 | procedure_occurrence | 2008-12-14 | 2008-12-14 | 99214 |
720
+ | 5 | 134 | procedure_occurrence | 2009-12-21 | 2009-12-21 | 99214 |
721
+ | 5 | 144 | procedure_occurrence | 2009-07-04 | 2009-07-04 | 99214 |
722
+ | 6 | 167 | procedure_occurrence | 2009-09-12 | 2009-09-12 | 99214 |
723
+ | 6 | 176 | procedure_occurrence | 2010-02-23 | 2010-02-23 | 99214 |
724
+ | 7 | 291 | procedure_occurrence | 2009-09-27 | 2009-09-27 | 99214 |
725
+ | 7 | 350 | procedure_occurrence | 2010-05-23 | 2010-05-23 | 99214 |
726
+ | 7 | 357 | procedure_occurrence | 2008-09-21 | 2008-09-21 | 99214 |
727
+
728
+ ## Time-oriented Operators
729
+
410
730
  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.
411
731
 
412
732
  For instance, a visit_occurrence result derives its start_date from visit_start_date and its end_date from visit_end_date.
@@ -415,11 +735,12 @@ If a result comes from a table that only has a single date value, the result der
415
735
 
416
736
  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.
417
737
 
738
+ ### Relative Temporal Operators
418
739
 
419
- ### Relative Temporal Nodes
420
- 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 nodes provide this type of filtering. Relative temporal nodes use a result's start_date to do chronological ordering.
740
+ 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.
421
741
 
422
742
  #### occurrence
743
+
423
744
  - Takes a two arguments: the stream to select from and an integer argument
424
745
  - For the integer argument
425
746
  - Positive numbers mean 1st, 2nd, 3rd occurrence in chronological order
@@ -428,57 +749,107 @@ When looking at a set of results for a person, perhaps we want to select just th
428
749
  - Negative numbers mean 1st, 2nd, 3rd occurrence in reverse chronological order
429
750
  - e.g. -1 => last
430
751
  - e.g. -4 => fourth from last
431
- - 0 is undefined?
752
+ - 0 is undefined?
753
+
754
+
755
+ ```YAML
756
+ ---
757
+ - occurrence
758
+ - 3
759
+ - - icd9
760
+ - '412'
432
761
 
433
- ```ConceptQL
434
- # For each patient, select the Condition that represents the third occurrence of an MI
435
- {
436
- occurrence: [
437
- { icd9: '412' },
438
- 3
439
- ]
440
- }
441
762
  ```
442
763
 
764
+ ![](spec/328467a6a419c7c05e299b8097e5e000686068ded8dc6d5f2e2de6f51976c315.png)
765
+
766
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
767
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
768
+ | 487 | 56319 | condition_occurrence | 2009-01-15 | 2009-01-19 | 412 |
769
+ | 506 | 59000 | condition_occurrence | 2010-07-19 | 2010-07-19 | 412 |
770
+ | 629 | 73033 | condition_occurrence | 2010-09-20 | 2010-09-20 | 412 |
771
+ | 985 | 114982 | condition_occurrence | 2009-09-29 | 2009-09-29 | 412 |
772
+ | 1336 | 156290 | condition_occurrence | 2009-10-03 | 2009-10-03 | 412 |
773
+ | 1779 | 206548 | condition_occurrence | 2010-02-09 | 2010-02-09 | 412 |
774
+ | 2475 | 282601 | condition_occurrence | 2009-02-28 | 2009-02-28 | 412 |
775
+ | 2529 | 289044 | condition_occurrence | 2010-07-18 | 2010-07-19 | 412 |
776
+ | 2942 | 337181 | condition_occurrence | 2010-01-22 | 2010-01-22 | 412 |
777
+ | 3206 | 365939 | condition_occurrence | 2009-03-25 | 2009-03-25 | 412 |
443
778
 
444
779
  #### first
445
- - Node that is shorthand for writing "occurrence: 1"
446
780
 
447
- ```ConceptQL
448
- # For each patient, select the Condition that represents the first occurrence of an MI
449
- {
450
- first: { icd9: '412' }
451
- }
781
+ - Operator that is shorthand for writing "occurrence: 1"
782
+
783
+
784
+ ```YAML
785
+ ---
786
+ - first
787
+ - - icd9
788
+ - '412'
789
+
452
790
  ```
453
791
 
792
+ ![](spec/04491942fcbd741982514f9eb12aeecf3d54b5b69a2b50c8331f7700169d5521.png)
793
+
794
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
795
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
796
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
797
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
798
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
799
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
800
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
801
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
802
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
803
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
804
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
805
+ | 88 | 10443 | condition_occurrence | 2010-05-26 | 2010-05-26 | 412 |
454
806
 
455
807
  #### last
456
- - Node that is just shorthand for writing "occurrence: -1"
457
808
 
458
- ```ConceptQL
459
- # For each patient, select the Condition that represents the last occurrence of an MI
460
- {
461
- last: { icd9: '412' }
462
- }
809
+ - Operator that is just shorthand for writing "occurrence: -1"
810
+
811
+
812
+ ```YAML
813
+ ---
814
+ - last
815
+ - - icd9
816
+ - '412'
817
+
463
818
  ```
464
819
 
820
+ ![](spec/ebacbd092e3d1a3c7b745a381e51e8ff9d63a21db23a16940193e18e57bc866f.png)
821
+
822
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
823
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
824
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
825
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
826
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
827
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
828
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
829
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
830
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
831
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
832
+ | 86 | 10196 | condition_occurrence | 2009-05-30 | 2009-05-30 | 412 |
833
+ | 88 | 10443 | condition_occurrence | 2010-05-26 | 2010-05-26 | 412 |
465
834
 
466
835
  ### Date Literals
467
- For situations where we need to represent pre-defined date ranges, we can use "date literal" nodes.
836
+
837
+ For situations where we need to represent pre-defined date ranges, we can use "date literal" operators.
468
838
 
469
839
  #### date_range
840
+
470
841
  - Takes a hash with two elements: { start: \<date-format\>, end: \<date-format\> }
471
842
  - Creates an inclusive, continuous range of dates defined by a start and end date
472
843
 
473
-
474
844
  #### day
845
+
475
846
  - Takes a single argument: \<date-format\>
476
847
  - Represents a single day
477
848
  - Shorthand for creating a date range that starts and ends on the same date
478
849
  - *Not yet implemented*
479
850
 
480
-
481
851
  #### What is <date-format\>?
852
+
482
853
  Dates follow these formats:
483
854
 
484
855
  - "YYYY-MM-DD"
@@ -488,13 +859,13 @@ Dates follow these formats:
488
859
  - "END"
489
860
  - Represents the last date of information available from the data source.
490
861
 
862
+ ### Temporal Comparison Operators
491
863
 
492
- ### Temporal Comparison Nodes
493
- 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 nodes.
864
+ 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.
494
865
 
495
- Temporal nodes 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 node has a comparison operator which defines how it compares dates between L and R. A temporal node passes results only from L downstream. A temporal node discards all results in the R stream after it makes all comparisons.
866
+ 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.
496
867
 
497
- The available set of temporal nodes 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)
868
+ 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)
498
869
 
499
870
  Our implementation of this algebra is originally going to be as strict as listed here, meaning that:
500
871
 
@@ -519,79 +890,138 @@ Ryan's Sidebar on These Definitions:
519
890
  > 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
520
891
 
521
892
  When comparing results in L against a date range, results in L continue downstream only if they pass the comparison.
522
- ```ConceptQL
523
- # All MIs for the year 2010
524
- {
525
- during: {
526
- left: { icd9: '412' },
527
- right: {
528
- date_range: {
529
- start: '2010-01-01',
530
- end: '2010-12-31'
531
- }
532
- }
533
- }
534
- }
535
- ```
536
-
537
- When comparing results in L against a set of results in R, the temporal node compares results in stream L against results in stream R on a person-by-person basis.
893
+
894
+
895
+ ```YAML
896
+ ---
897
+ - during
898
+ - :left:
899
+ - icd9
900
+ - '412'
901
+ :right:
902
+ - date_range
903
+ - :start: '2010-01-01'
904
+ :end: '2010-12-31'
905
+
906
+ ```
907
+
908
+ ![](spec/ba90ef705f7be91c53c5eb4a81a439fa0f7c48532214bd3db3cc5c069160543e.png)
909
+
910
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
911
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
912
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
913
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
914
+ | 88 | 10443 | condition_occurrence | 2010-05-26 | 2010-05-26 | 412 |
915
+ | 108 | 13741 | condition_occurrence | 2010-06-27 | 2010-06-27 | 412 |
916
+ | 149 | 17774 | condition_occurrence | 2010-11-22 | 2010-11-22 | 412 |
917
+ | 183 | 21619 | condition_occurrence | 2010-12-26 | 2010-12-26 | 412 |
918
+ | 206 | 24437 | condition_occurrence | 2010-02-07 | 2010-02-07 | 412 |
919
+ | 209 | 24989 | condition_occurrence | 2010-06-22 | 2010-06-23 | 412 |
920
+ | 231 | 28188 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
921
+ | 255 | 31542 | condition_occurrence | 2010-11-21 | 2010-11-21 | 412 |
922
+
923
+ 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.
538
924
 
539
925
  - If a person has results in L or R stream, but not in both, none of their results continue downstream
540
- - On a per person basis, the temporal node joins all results in the L stream to all results in the R stream
926
+ - On a per person basis, the temporal operator joins all results in the L stream to all results in the R stream
541
927
  - Any results in the L stream that meet the temporal comparison against any results in the R stream continue downstream
542
- ```ConceptQL
543
- # All MIs While Patients had Part A Medicare
544
- {
545
- during: {
546
- left: { icd9: '412' },
547
- right: { payer: 'Part A' }
548
- }
549
- }
928
+
929
+
930
+ ```YAML
931
+ ---
932
+ - during
933
+ - :left:
934
+ - icd9
935
+ - '412'
936
+ :right:
937
+ - payer
938
+ - Part A
939
+
550
940
  ```
551
941
 
942
+ ![](spec/ed039f82867241393b1a6a7153d3690461103934c72c1f3eaa3d99a12bb40885.png)
943
+
944
+ ```No Results. Statement is experimental.```
945
+
552
946
  #### Edge behaviors
553
- For 11 of the 13 temporal nodes, comparison of results is straight-forward. However, the before/after nodes have a slight twist.
947
+
948
+ For 11 of the 13 temporal operators, comparison of results is straight-forward. However, the before/after operators have a slight twist.
554
949
 
555
950
  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:
556
951
 
557
- - When comparing L **before** R, the temporal node compares L against the **LAST** occurrence of R per person
558
- - When comparing L **after** R, the temporal node compares L against the **FIRST** occurrence of R per person
952
+ - When comparing L **before** R, the temporal operator compares L against the **LAST** occurrence of R per person
953
+ - When comparing L **after** R, the temporal operator compares L against the **FIRST** occurrence of R per person
559
954
 
560
955
  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.
561
956
 
562
957
 
563
- ```ConceptQL
564
- # All MIs that occurred before a patient's __last__ case of irritability (799.22)
565
- {
566
- before: {
567
- left: { icd9: '412' },
568
- right: { icd9: '799.22' }
569
- }
570
- }
571
- ```
958
+ ```YAML
959
+ ---
960
+ - before
961
+ - :left:
962
+ - icd9
963
+ - '412'
964
+ :right:
965
+ - icd9
966
+ - '799.22'
572
967
 
573
- If this is not the behavior you desire, use one of the sequence nodes to select which event in R should be the one used to do comparison
574
- ```ConceptQL
575
- # All MIs that occurred before a patient's __first__ case of irritability (799.22)
576
- {
577
- before: {
578
- left: { icd9: '412' },
579
- right: {
580
- first: {
581
- icd9: '799.22'
582
- }
583
- }
584
- }
585
- }
586
968
  ```
587
969
 
970
+ ![](spec/ee283d6a4b69cf10da2df703be3a16830be9cd8cd4f68c5f7afdf558ea28fa76.png)
971
+
972
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
973
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
974
+ | 53785 | 6053034 | condition_occurrence | 2008-07-18 | 2008-07-18 | 412 |
975
+ | 4289 | 496274 | condition_occurrence | 2008-07-19 | 2008-07-19 | 412 |
976
+ | 103062 | 11580605 | condition_occurrence | 2008-08-28 | 2008-08-28 | 412 |
977
+ | 12524 | 1422629 | condition_occurrence | 2009-08-25 | 2009-08-25 | 412 |
978
+ | 20306 | 2302248 | condition_occurrence | 2010-01-04 | 2010-01-04 | 412 |
979
+ | 81188 | 9131971 | condition_occurrence | 2010-02-15 | 2010-02-15 | 412 |
980
+ | 81188 | 9132070 | condition_occurrence | 2009-11-07 | 2009-11-07 | 412 |
981
+ | 97169 | 10930462 | condition_occurrence | 2008-02-05 | 2008-02-05 | 412 |
982
+ | 98040 | 11029333 | condition_occurrence | 2008-10-02 | 2008-10-02 | 412 |
983
+ | 98040 | 11029388 | condition_occurrence | 2008-08-09 | 2008-08-09 | 412 |
984
+
985
+ 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
986
+
987
+
988
+ ```YAML
989
+ ---
990
+ - before
991
+ - :left:
992
+ - icd9
993
+ - '412'
994
+ :right:
995
+ - first
996
+ - - icd9
997
+ - '799.22'
998
+
999
+ ```
1000
+
1001
+ ![](spec/de589af36fa854e006a1563c93e644e2210f2a5616babb779f7f38aadb6c1ed7.png)
1002
+
1003
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1004
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1005
+ | 53785 | 6053034 | condition_occurrence | 2008-07-18 | 2008-07-18 | 412 |
1006
+ | 4289 | 496274 | condition_occurrence | 2008-07-19 | 2008-07-19 | 412 |
1007
+ | 103062 | 11580605 | condition_occurrence | 2008-08-28 | 2008-08-28 | 412 |
1008
+ | 12524 | 1422629 | condition_occurrence | 2009-08-25 | 2009-08-25 | 412 |
1009
+ | 20306 | 2302248 | condition_occurrence | 2010-01-04 | 2010-01-04 | 412 |
1010
+ | 81188 | 9131971 | condition_occurrence | 2010-02-15 | 2010-02-15 | 412 |
1011
+ | 81188 | 9132070 | condition_occurrence | 2009-11-07 | 2009-11-07 | 412 |
1012
+ | 97169 | 10930462 | condition_occurrence | 2008-02-05 | 2008-02-05 | 412 |
1013
+ | 98040 | 11029333 | condition_occurrence | 2008-10-02 | 2008-10-02 | 412 |
1014
+ | 98040 | 11029388 | condition_occurrence | 2008-08-09 | 2008-08-09 | 412 |
1015
+
588
1016
  ### Time Windows
1017
+
589
1018
  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.
590
1019
 
591
1020
  #### time_window
1021
+
592
1022
  - Takes 2 arguments
593
1023
  - First argument is the stream on which to operate
594
- - Second argument is a hash with two keys: [:start, :end] each with a value in the following format: "(-?\d+[dmy])+"
1024
+ - Second argument is a hash with two keys: \[:start, :end\] each with a value in the following format: "(-?\d+\[dmy\])+"
595
1025
  - Both start and end must be defined, even if you are only adjusting one of the dates
596
1026
  - Some examples
597
1027
  - 30d => 30 days
@@ -608,378 +1038,669 @@ There are situations when the date columns associated with a result should have
608
1038
  - 'end' represents the end_date for each result
609
1039
  - See the example below
610
1040
 
611
- ```ConceptQL
612
- # All Diagnoses of Irritability (ICD-9 799.22) within 30 days of an MI
613
- {
614
- during: {
615
- left: { icd9: '799.22' },
616
- right: {
617
- time_window: [
618
- { icd9: '412' },
619
- { start: '-30d', end: '30d' }
620
- ]
621
- }
622
- }
623
- }
624
- ```
625
-
626
- ```ConceptQL
627
- # Shift the window for all MIs back by 2 years
628
- {
629
- time_window: [
630
- { icd9: '412' },
631
- { start: '-2y', end: '-2y' }
632
- ]
633
- }
634
- ```
635
-
636
- ```ConceptQL
637
- # 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
638
- {
639
- time_window: [
640
- { icd9: '412' },
641
- { start: '-2m-2d', end: '3d1y' }
642
- ]
643
- }
644
- ```
645
-
646
- ```ConceptQL
647
- # 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
648
- {
649
- time_window: [
650
- { place_of_service: 'inpatient' },
651
- { start: '', end: 'start' }
652
- ]
653
- }
654
- ```
655
-
656
- ```ConceptQL
657
- # Nonsensical, but allowed: swap the start_date and end_date for a range
658
- {
659
- time_window: [
660
- { icd9: '412' },
661
- { start: 'end', end: 'start' }
662
- ]
663
- }
664
- ```
665
-
666
- #### Temporal Nodes and Person Streams
667
- 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 node. 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:
668
- ```ConceptQL
669
- # All MIs that occurred after a male patient's 50th birthday
670
- {
671
- after: {
672
- left: { icd9: '412' },
673
- right: {
674
- time_window: [
675
- { gender: 'Male' },
676
- {
677
- start: '50y',
678
- end: '50y'
679
- }
680
- ]
681
- }
682
- }
683
- }
1041
+
1042
+ ```YAML
1043
+ ---
1044
+ - during
1045
+ - :left:
1046
+ - icd9
1047
+ - '799.22'
1048
+ :right:
1049
+ - time_window
1050
+ - - icd9
1051
+ - '412'
1052
+ - :start: "-30d"
1053
+ :end: 30d
1054
+
684
1055
  ```
685
1056
 
1057
+ ![](spec/8101d9b89d9ba8070d585432707b43a8acdb4c2a3e9d37c3f7114b5e3ea9e800.png)
1058
+
1059
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1060
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1061
+ | 2086 | 238625 | condition_occurrence | 2008-05-24 | 2008-05-24 | 799.22 |
1062
+ | 5121 | 590274 | condition_occurrence | 2009-03-26 | 2009-04-04 | 799.22 |
1063
+ | 11427 | 1298251 | condition_occurrence | 2008-09-06 | 2008-09-06 | 799.22 |
1064
+ | 16432 | 1870381 | condition_occurrence | 2009-02-16 | 2009-02-16 | 799.22 |
1065
+ | 37733 | 4272148 | condition_occurrence | 2010-03-09 | 2010-03-09 | 799.22 |
1066
+ | 54141 | 6093274 | condition_occurrence | 2010-06-13 | 2010-06-13 | 799.22 |
1067
+ | 110498 | 12420479 | condition_occurrence | 2009-04-30 | 2009-04-30 | 799.22 |
1068
+
1069
+
1070
+ ```YAML
1071
+ ---
1072
+ - time_window
1073
+ - - icd9
1074
+ - '412'
1075
+ - :start: "-2y"
1076
+ :end: "-2y"
1077
+
1078
+ ```
1079
+
1080
+ ![](spec/15268bc45993d3f57ccf915877f91e48bdee684f24faa614249915833cac4af9.png)
1081
+
1082
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1083
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1084
+ | 17 | 1712 | condition_occurrence | 2006-08-25 | 2006-08-25 | 412 |
1085
+ | 17 | 1829 | condition_occurrence | 2007-04-30 | 2007-04-30 | 412 |
1086
+ | 37 | 4359 | condition_occurrence | 2008-02-12 | 2008-02-12 | 412 |
1087
+ | 53 | 5751 | condition_occurrence | 2006-06-05 | 2006-06-05 | 412 |
1088
+ | 59 | 6083 | condition_occurrence | 2007-07-19 | 2007-07-22 | 412 |
1089
+ | 64 | 6902 | condition_occurrence | 2007-07-25 | 2007-07-25 | 412 |
1090
+ | 71 | 7865 | condition_occurrence | 2006-11-16 | 2006-11-16 | 412 |
1091
+ | 75 | 8397 | condition_occurrence | 2008-10-06 | 2008-10-06 | 412 |
1092
+ | 79 | 8618 | condition_occurrence | 2007-01-28 | 2007-01-30 | 412 |
1093
+ | 86 | 9882 | condition_occurrence | 2007-01-03 | 2007-01-09 | 412 |
1094
+
1095
+
1096
+ ```YAML
1097
+ ---
1098
+ - time_window
1099
+ - - icd9
1100
+ - '412'
1101
+ - :start: "-2m-2d"
1102
+ :end: 3d1y
1103
+
1104
+ ```
1105
+
1106
+ ![](spec/cc960a268d51ccf2ebde657d36848f780213834844900018bce3d111843f7b0f.png)
1107
+
1108
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1109
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1110
+ | 17 | 1712 | condition_occurrence | 2008-06-23 | 2009-08-28 | 412 |
1111
+ | 17 | 1829 | condition_occurrence | 2009-02-26 | 2010-05-03 | 412 |
1112
+ | 37 | 4359 | condition_occurrence | 2009-12-10 | 2011-02-15 | 412 |
1113
+ | 53 | 5751 | condition_occurrence | 2008-04-03 | 2009-06-08 | 412 |
1114
+ | 59 | 6083 | condition_occurrence | 2009-05-17 | 2010-07-25 | 412 |
1115
+ | 64 | 6902 | condition_occurrence | 2009-05-23 | 2010-07-28 | 412 |
1116
+ | 71 | 7865 | condition_occurrence | 2008-09-14 | 2009-11-19 | 412 |
1117
+ | 75 | 8397 | condition_occurrence | 2010-08-04 | 2011-10-09 | 412 |
1118
+ | 79 | 8618 | condition_occurrence | 2008-11-26 | 2010-02-02 | 412 |
1119
+ | 86 | 9882 | condition_occurrence | 2008-11-01 | 2010-01-12 | 412 |
1120
+
1121
+
1122
+ ```YAML
1123
+ ---
1124
+ - time_window
1125
+ - - place_of_service_code
1126
+ - '21'
1127
+ - :start: ''
1128
+ :end: start
1129
+
1130
+ ```
1131
+
1132
+ ![](spec/886bf85249a704668a55c5161bceaac10be4a41a94b91606f49851dfa017526c.png)
1133
+
1134
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1135
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1136
+ | 1 | 1 | visit_occurrence | 2010-03-12 | 2010-03-12 | Inpatient |
1137
+ | 2 | 8 | visit_occurrence | 2009-09-17 | 2009-09-17 | Inpatient |
1138
+ | 2 | 9 | visit_occurrence | 2009-04-12 | 2009-04-12 | Inpatient |
1139
+ | 2 | 10 | visit_occurrence | 2010-06-26 | 2010-06-26 | Inpatient |
1140
+ | 2 | 11 | visit_occurrence | 2009-08-31 | 2009-08-31 | Inpatient |
1141
+ | 14 | 507 | visit_occurrence | 2008-09-12 | 2008-09-12 | Inpatient |
1142
+ | 17 | 729 | visit_occurrence | 2010-05-22 | 2010-05-22 | Inpatient |
1143
+ | 17 | 730 | visit_occurrence | 2008-09-19 | 2008-09-19 | Inpatient |
1144
+ | 17 | 731 | visit_occurrence | 2010-06-02 | 2010-06-02 | Inpatient |
1145
+ | 17 | 732 | visit_occurrence | 2010-06-16 | 2010-06-16 | Inpatient |
1146
+
1147
+
1148
+ ```YAML
1149
+ ---
1150
+ - time_window
1151
+ - - icd9
1152
+ - '412'
1153
+ - :start: end
1154
+ :end: start
1155
+
1156
+ ```
1157
+
1158
+ ![](spec/6705af65d728c0d5c50d6c4d46253017a91eb459dbb1f40f92449f05d5562f4a.png)
1159
+
1160
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1161
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1162
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
1163
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
1164
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
1165
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
1166
+ | 59 | 6083 | condition_occurrence | 2009-07-22 | 2009-07-19 | 412 |
1167
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
1168
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
1169
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
1170
+ | 79 | 8618 | condition_occurrence | 2009-01-30 | 2009-01-28 | 412 |
1171
+ | 86 | 9882 | condition_occurrence | 2009-01-09 | 2009-01-03 | 412 |
1172
+
1173
+ #### Temporal Operators and Person Streams
1174
+
1175
+ 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:
1176
+
1177
+
1178
+ ```YAML
1179
+ ---
1180
+ - after
1181
+ - :left:
1182
+ - icd9
1183
+ - '412'
1184
+ :right:
1185
+ - time_window
1186
+ - - gender
1187
+ - Male
1188
+ - :start: 50y
1189
+ :end: 50y
1190
+
1191
+ ```
1192
+
1193
+ ![](spec/68fac940a32c7e40caacf8e560c61da552d57633d015ba98f2e98ec040a00c5b.png)
1194
+
1195
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1196
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1197
+ | 92077 | 10363643 | condition_occurrence | 2010-03-08 | 2010-03-08 | 412 |
1198
+ | 66609 | 7497031 | condition_occurrence | 2009-05-25 | 2009-05-28 | 412 |
1199
+ | 13729 | 1563187 | condition_occurrence | 2008-06-13 | 2008-06-13 | 412 |
1200
+ | 10876 | 1237925 | condition_occurrence | 2008-09-13 | 2008-09-13 | 412 |
1201
+ | 10876 | 1237830 | condition_occurrence | 2008-02-02 | 2008-02-03 | 412 |
1202
+ | 54683 | 6153652 | condition_occurrence | 2008-10-24 | 2008-10-28 | 412 |
1203
+ | 16106 | 1833669 | condition_occurrence | 2009-07-06 | 2009-07-13 | 412 |
1204
+ | 68518 | 7706073 | condition_occurrence | 2009-02-22 | 2009-02-22 | 412 |
1205
+ | 52736 | 5937885 | condition_occurrence | 2008-05-07 | 2008-05-07 | 412 |
1206
+ | 62215 | 7004785 | condition_occurrence | 2008-06-10 | 2008-06-10 | 412 |
1207
+
686
1208
  ## Type Conversion
1209
+
687
1210
  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.
688
1211
 
689
1212
  ### Casting to person
1213
+
690
1214
  - Useful if we're just checking for the presence of a condition for a person
691
1215
  - E.g. We want to know *if* a person has an old MI, not when an MI or how many MIs occurred
692
- ```ConceptQL
693
- # All People Who Had an MI
694
- {
695
- person: {
696
- icd9: '412'
697
- }
698
- }
1216
+
1217
+
1218
+ ```YAML
1219
+ ---
1220
+ - person
1221
+ - - icd9
1222
+ - '412'
1223
+
699
1224
  ```
1225
+
1226
+ ![](spec/8ed478d8c81a58a202d0c51348fca246df206fc24a0567b163d4e0bdab56ca46.png)
1227
+
1228
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1229
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1230
+ | 251 | 251 | person | 1928-10-01 | 1928-10-01 | 008645209D3E025E |
1231
+ | 66532 | 66532 | person | 1943-04-01 | 1943-04-01 | 96AB8ADC5FA7AD8C |
1232
+ | 64221 | 64221 | person | 1934-04-01 | 1934-04-01 | 916F76F7FDF6B6CF |
1233
+ | 111839 | 111839 | person | 1938-12-01 | 1938-12-01 | FDE56ED4546D17F6 |
1234
+ | 25643 | 25643 | person | 1916-06-01 | 1916-06-01 | 39BA7D25EC6D1B14 |
1235
+ | 79317 | 79317 | person | 1943-02-01 | 1943-02-01 | B441BDCB76C7C267 |
1236
+ | 108128 | 108128 | person | 1935-02-01 | 1935-02-01 | F58409ED69652B4A |
1237
+ | 77900 | 77900 | person | 1934-05-01 | 1934-05-01 | B0E710725FE3FE97 |
1238
+ | 61145 | 61145 | person | 1942-07-01 | 1942-07-01 | 8A595528CF5E2859 |
1239
+ | 18149 | 18149 | person | 1946-09-01 | 1946-09-01 | 28AFD67E63039098 |
1240
+
700
1241
  ### Casting to a visit_occurrence
1242
+
701
1243
  - It is common to look for a set of conditions that coincide with a set of procedures
702
1244
  - Gathering conditions yields a condition stream, gathering procedures yields a procedure stream
703
1245
  - It is not possible to compare those two streams directly using AND
704
1246
  - 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
705
1247
  - 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
706
- ```ConceptQL
707
- # All Visits Where a Patient Had an MI During and Office Visit
708
- {
709
- intersect: [
710
- {
711
- visit_occurrence: {
712
- icd9: '412'
713
- }
714
- },
715
- {
716
- visit_occurrence: {
717
- cpt: '99214'
718
- }
719
- }
720
- ]
721
- }
722
- ```
1248
+
1249
+
1250
+ ```YAML
1251
+ ---
1252
+ - intersect
1253
+ - - visit_occurrence
1254
+ - - icd9
1255
+ - '412'
1256
+ - - visit_occurrence
1257
+ - - cpt
1258
+ - '99214'
1259
+
1260
+ ```
1261
+
1262
+ ![](spec/62323426e381ec21c967971a67e1f4a6d89dae92154bd937284e00b67f67fdd3.png)
1263
+
1264
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1265
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1266
+ | 59633 | 2958903 | visit_occurrence | 2010-07-08 | 2010-07-08 | Office |
1267
+ | 8462 | 423786 | visit_occurrence | 2008-08-24 | 2008-08-24 | Office |
1268
+ | 48614 | 2410554 | visit_occurrence | 2009-06-05 | 2009-06-05 | Office |
1269
+ | 92639 | 4587768 | visit_occurrence | 2009-04-25 | 2009-04-25 | Office |
1270
+ | 46156 | 2292353 | visit_occurrence | 2008-06-18 | 2008-06-18 | Office |
1271
+ | 105614 | 5223564 | visit_occurrence | 2008-02-03 | 2008-02-03 | Office |
1272
+ | 21343 | 1061266 | visit_occurrence | 2008-04-25 | 2008-04-25 | Office |
1273
+ | 62315 | 3086112 | visit_occurrence | 2008-05-27 | 2008-05-27 | Office |
1274
+ | 18286 | 914814 | visit_occurrence | 2010-02-10 | 2010-02-10 | Office |
1275
+ | 27340 | 1365178 | visit_occurrence | 2009-06-17 | 2009-06-17 | Office |
723
1276
 
724
1277
  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.
725
1278
 
726
1279
  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.
727
- ```ConceptQL
728
- # All Visits for All Male Patients
729
- {
730
- visit_occurrence: {
731
- gender: 'Male'
732
- }
733
- }
1280
+
1281
+
1282
+ ```YAML
1283
+ ---
1284
+ - visit_occurrence
1285
+ - - gender
1286
+ - Male
1287
+
734
1288
  ```
735
1289
 
1290
+ ![](spec/e8630103287f7c9d28eff40b3b1826e24846e776b877f7b8554257acbe621e1c.png)
1291
+
1292
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1293
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1294
+ | 10295 | 516092 | visit_occurrence | 2008-04-08 | 2008-04-08 | Outpatient |
1295
+ | 10295 | 516093 | visit_occurrence | 2008-07-28 | 2008-07-28 | Outpatient |
1296
+ | 10295 | 516094 | visit_occurrence | 2009-05-27 | 2009-05-27 | Outpatient |
1297
+ | 10295 | 516095 | visit_occurrence | 2008-09-03 | 2008-09-03 | Outpatient |
1298
+ | 10295 | 516096 | visit_occurrence | 2008-05-31 | 2008-05-31 | Outpatient |
1299
+ | 10295 | 516097 | visit_occurrence | 2008-09-13 | 2008-09-13 | Outpatient |
1300
+ | 10295 | 516098 | visit_occurrence | 2008-08-23 | 2008-08-23 | Outpatient |
1301
+ | 10295 | 516099 | visit_occurrence | 2008-04-28 | 2008-04-28 | Office |
1302
+ | 10295 | 516100 | visit_occurrence | 2009-03-26 | 2009-03-26 | Office |
1303
+ | 10295 | 516101 | visit_occurrence | 2009-09-22 | 2009-09-22 | Office |
1304
+
736
1305
  ### Casting Loses All Original Information
737
- 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 node and you want the original dates later on. Just cast the stream to its same type and it will regain its original dates.
738
1306
 
1307
+ 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.
739
1308
 
740
1309
  ### Cast all the Things!
1310
+
741
1311
  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.
742
1312
 
743
1313
  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.
744
1314
 
745
1315
  INSERT HANDY TABLE SHOWING CONVERSION MATRIX HERE
746
1316
 
747
- ```ConceptQL
748
- # Cost of 70012 while Hospitalized for MI
749
- {
750
- procedure_cost: {
751
- intersect: [
752
- { cpt: '70012' },
753
- procedure: {
754
- intersect: [
755
- { place_of_service: 'inpatient' },
756
- visit_occurrence: {
757
- icd9: '412'
758
- }
759
- ]
760
- }
761
- ]
762
- }
763
- }
1317
+
1318
+ ```YAML
1319
+ ---
1320
+ - procedure_cost
1321
+ - - intersect
1322
+ - - cpt
1323
+ - '70012'
1324
+ - - procedure
1325
+ - - intersect
1326
+ - - place_of_service_code
1327
+ - '21'
1328
+ - - visit_occurrence
1329
+ - - icd9
1330
+ - '412'
1331
+
764
1332
  ```
765
1333
 
1334
+ ![](spec/6a34c0ef589c9c976fe41f3e67e799e198499f5b9c3ebfd240fb91f73e893573.png)
1335
+
1336
+ ```No Results. Statement is experimental.```
1337
+
766
1338
  ### Casting as a way to fetch all rows
767
- The casting node doubles as a way to fetch all rows for a single type. Provide the casting node with an argument of ```true``` (instead of an upstream node) to get all rows as results:
768
- ```ConceptQL
769
- # All death results in the database
770
- { death: true }
1339
+
1340
+ 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:
1341
+
1342
+
1343
+ ```YAML
1344
+ ---
1345
+ - death
1346
+ - true
1347
+
771
1348
  ```
772
1349
 
1350
+ ![](spec/e9b384fa7dec5f1a06479c4b289e06b1e60e4f23f7630aff6d03c52595f500f8.png)
1351
+
1352
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1353
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1354
+ | 16 | 16 | death | 2010-12-01 | 2010-12-01 | |
1355
+ | 177 | 177 | death | 2010-07-01 | 2010-07-01 | |
1356
+ | 293 | 293 | death | 2010-01-01 | 2010-01-01 | |
1357
+ | 306 | 306 | death | 2010-05-01 | 2010-05-01 | |
1358
+ | 375 | 375 | death | 2010-03-01 | 2010-03-01 | |
1359
+ | 429 | 429 | death | 2010-03-01 | 2010-03-01 | |
1360
+ | 450 | 450 | death | 2010-11-01 | 2010-11-01 | |
1361
+ | 555 | 555 | death | 2010-11-01 | 2010-11-01 | |
1362
+ | 565 | 565 | death | 2010-06-01 | 2010-06-01 | |
1363
+ | 603 | 603 | death | 2010-06-01 | 2010-06-01 | |
1364
+
773
1365
  This comes in handy for situations like these:
774
- ```ConceptQL
775
- # All Male patients who died
776
- {
777
- person_filter: {
778
- left: { gender: 'Male' },
779
- right: { death: true },
780
- }
781
- }
782
- ```
783
1366
 
784
1367
 
1368
+ ```YAML
1369
+ ---
1370
+ - person_filter
1371
+ - :left:
1372
+ - gender
1373
+ - Male
1374
+ :right:
1375
+ - death
1376
+ - true
1377
+
1378
+ ```
1379
+
1380
+ ![](spec/58113a57a37431a402d2547369eba3a481bf1dbbfd82dc384406a5c91f6df01f.png)
1381
+
1382
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1383
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1384
+ | 55510 | 55510 | person | 1930-08-01 | 1930-08-01 | 7D34060FA1EF58C6 |
1385
+ | 74808 | 74808 | person | 1927-02-01 | 1927-02-01 | A9BE60D395FEE13D |
1386
+ | 32780 | 32780 | person | 1961-09-01 | 1961-09-01 | 49BF11D11CEF2328 |
1387
+ | 87909 | 87909 | person | 1934-04-01 | 1934-04-01 | C7727009E7DDF6B8 |
1388
+ | 43890 | 43890 | person | 1920-03-01 | 1920-03-01 | 6309F87AE1E03227 |
1389
+ | 46052 | 46052 | person | 1941-09-01 | 1941-09-01 | 67D8035124FE474E |
1390
+ | 88540 | 88540 | person | 1952-08-01 | 1952-08-01 | C8E882134C354ADF |
1391
+ | 10616 | 10616 | person | 1946-07-01 | 1946-07-01 | 179C0EDEB061D6E3 |
1392
+ | 74892 | 74892 | person | 1927-02-01 | 1927-02-01 | A9F0108311BE3424 |
1393
+ | 84318 | 84318 | person | 1938-06-01 | 1938-06-01 | BF7387DC991F39A9 |
1394
+
785
1395
  ## Filtering by People
786
- 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 node for that. Like the Except node, it takes a left-hand stream and a right-hand stream.
787
1396
 
788
- Unlike the ```except``` node, the person_filter node 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.
1397
+ 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.
789
1398
 
1399
+ 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.
790
1400
 
791
- ```ConceptQL
792
- # All MI Conditions for people who are male
793
- {
794
- person_filter: {
795
- left: { icd9: '412' },
796
- right: { gender: 'Male'}
797
- }
798
- }
799
- ```
1401
+
1402
+ ```YAML
1403
+ ---
1404
+ - person_filter
1405
+ - :left:
1406
+ - icd9
1407
+ - '412'
1408
+ :right:
1409
+ - gender
1410
+ - Male
1411
+
1412
+ ```
1413
+
1414
+ ![](spec/0360fc0c2b7a88fd82ffc4d13387b76766649d5d42aa8f9349bbf60a81ac6119.png)
1415
+
1416
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1417
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1418
+ | 92077 | 10363643 | condition_occurrence | 2010-03-08 | 2010-03-08 | 412 |
1419
+ | 66609 | 7497031 | condition_occurrence | 2009-05-25 | 2009-05-28 | 412 |
1420
+ | 13729 | 1563187 | condition_occurrence | 2008-06-13 | 2008-06-13 | 412 |
1421
+ | 10876 | 1237925 | condition_occurrence | 2008-09-13 | 2008-09-13 | 412 |
1422
+ | 10876 | 1237830 | condition_occurrence | 2008-02-02 | 2008-02-03 | 412 |
1423
+ | 54683 | 6153652 | condition_occurrence | 2008-10-24 | 2008-10-28 | 412 |
1424
+ | 16106 | 1833669 | condition_occurrence | 2009-07-06 | 2009-07-13 | 412 |
1425
+ | 33793 | 3829115 | condition_occurrence | 2008-01-17 | 2008-01-21 | 412 |
1426
+ | 68518 | 7706073 | condition_occurrence | 2009-02-22 | 2009-02-22 | 412 |
1427
+ | 52736 | 5937885 | condition_occurrence | 2008-05-07 | 2008-05-07 | 412 |
800
1428
 
801
1429
  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:
802
- ```ConceptQL
803
- # All MI Conditions for people who had an office visit at some point in the data
804
- {
805
- person_filter: {
806
- left: { icd9: '412' },
807
- right: { cpt: '99214' }
808
- }
809
- }
810
- ```
811
- ```ConceptQL
812
- # 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)
813
- {
814
- person_filter: {
815
- left: { icd9: '412' },
816
- right: { person: { cpt: '99214' } }
817
- }
818
- }
819
- ```
820
- ```ConceptQL
821
- # All MI Conditions for people who are Male OR had an office visit at some point in the data
822
- {
823
- person_filter: {
824
- left: { icd9: '412' },
825
- right: {
826
- union: [
827
- { cpt: '99214' },
828
- { gender: 'Male' }
829
- ]
830
- }
831
- }
832
- }
1430
+
1431
+
1432
+ ```YAML
1433
+ ---
1434
+ - person_filter
1435
+ - :left:
1436
+ - icd9
1437
+ - '412'
1438
+ :right:
1439
+ - cpt
1440
+ - '99214'
1441
+
833
1442
  ```
834
1443
 
1444
+ ![](spec/26fd52b5ac55438dd9f81b4a3f3913f1058c9f225c8a5e129007c1e9413d5881.png)
1445
+
1446
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1447
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1448
+ | 92077 | 10363643 | condition_occurrence | 2010-03-08 | 2010-03-08 | 412 |
1449
+ | 108031 | 12142323 | condition_occurrence | 2009-11-25 | 2009-11-25 | 412 |
1450
+ | 56414 | 6351863 | condition_occurrence | 2008-11-15 | 2008-11-15 | 412 |
1451
+ | 66609 | 7497031 | condition_occurrence | 2009-05-25 | 2009-05-28 | 412 |
1452
+ | 10876 | 1237830 | condition_occurrence | 2008-02-02 | 2008-02-03 | 412 |
1453
+ | 10876 | 1237925 | condition_occurrence | 2008-09-13 | 2008-09-13 | 412 |
1454
+ | 33463 | 3787772 | condition_occurrence | 2009-08-08 | 2009-08-08 | 412 |
1455
+ | 48678 | 5484541 | condition_occurrence | 2009-09-09 | 2009-09-09 | 412 |
1456
+ | 54683 | 6153652 | condition_occurrence | 2008-10-24 | 2008-10-28 | 412 |
1457
+ | 68518 | 7706073 | condition_occurrence | 2009-02-22 | 2009-02-22 | 412 |
1458
+
1459
+
1460
+ ```YAML
1461
+ ---
1462
+ - person_filter
1463
+ - :left:
1464
+ - icd9
1465
+ - '412'
1466
+ :right:
1467
+ - person
1468
+ - - cpt
1469
+ - '99214'
1470
+
1471
+ ```
1472
+
1473
+ ![](spec/e1cb0863b21e14256d61a54200316791f6547c78ba2f0156c110f4500f9bbd49.png)
1474
+
1475
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1476
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1477
+ | 92077 | 10363643 | condition_occurrence | 2010-03-08 | 2010-03-08 | 412 |
1478
+ | 108031 | 12142323 | condition_occurrence | 2009-11-25 | 2009-11-25 | 412 |
1479
+ | 56414 | 6351863 | condition_occurrence | 2008-11-15 | 2008-11-15 | 412 |
1480
+ | 66609 | 7497031 | condition_occurrence | 2009-05-25 | 2009-05-28 | 412 |
1481
+ | 10876 | 1237830 | condition_occurrence | 2008-02-02 | 2008-02-03 | 412 |
1482
+ | 10876 | 1237925 | condition_occurrence | 2008-09-13 | 2008-09-13 | 412 |
1483
+ | 33463 | 3787772 | condition_occurrence | 2009-08-08 | 2009-08-08 | 412 |
1484
+ | 48678 | 5484541 | condition_occurrence | 2009-09-09 | 2009-09-09 | 412 |
1485
+ | 54683 | 6153652 | condition_occurrence | 2008-10-24 | 2008-10-28 | 412 |
1486
+ | 68518 | 7706073 | condition_occurrence | 2009-02-22 | 2009-02-22 | 412 |
1487
+
1488
+
1489
+ ```YAML
1490
+ ---
1491
+ - person_filter
1492
+ - :left:
1493
+ - icd9
1494
+ - '412'
1495
+ :right:
1496
+ - union
1497
+ - - cpt
1498
+ - '99214'
1499
+ - - gender
1500
+ - Male
1501
+
1502
+ ```
1503
+
1504
+ ![](spec/5d331d74c460d75814b2d3138a9b7d90b5ddb2dcd85e1f5f260d183745fc3a1e.png)
1505
+
1506
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1507
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1508
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
1509
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
1510
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
1511
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
1512
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
1513
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
1514
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
1515
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
1516
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
1517
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
1518
+
835
1519
  And don't forget the left-hand side can have multiple types of streams:
836
- ```ConceptQL
837
- # 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
838
- {
839
- person_filter: {
840
- left: {
841
- union: [
842
- { icd9: '412' },
843
- { cpt: '99214' }
844
- ]
845
- },
846
- right: { gender: 'Male' }
847
- }
848
- }
849
- ```
850
-
851
-
852
- ## Sub-concepts within a Larger Concept
853
- If a concept is particularly complex, or has a stream of results that are used more than once, it can be helpful to break the concept into a set of sub-concepts. This can be done using two nodes: define and recall
854
-
855
- #### define
856
- - Takes 2 arguments
857
- - First argument is a string of arbitrary length that describe the stream to be save. This is the "name" assigned to the stream for later recall
858
- - Second argument is the stream to save under the name specified
859
1520
 
860
1521
 
861
- #### recall
862
- - Takes 1 argument
863
- - The "name" of the stream previously saved using the `define` node
1522
+ ```YAML
1523
+ ---
1524
+ - person_filter
1525
+ - :left:
1526
+ - union
1527
+ - - icd9
1528
+ - '412'
1529
+ - - cpt
1530
+ - '99214'
1531
+ :right:
1532
+ - gender
1533
+ - Male
1534
+
1535
+ ```
1536
+
1537
+ ![](spec/c93dd18894a245a5647f99e1867d3779e4cd34c9c8f8860600ff0c837a5ffa53.png)
1538
+
1539
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1540
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1541
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
1542
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
1543
+ | 91 | 10865 | condition_occurrence | 2009-11-08 | 2009-11-08 | 412 |
1544
+ | 108 | 13741 | condition_occurrence | 2010-06-27 | 2010-06-27 | 412 |
1545
+ | 128 | 15149 | condition_occurrence | 2008-03-22 | 2008-03-23 | 412 |
1546
+ | 146 | 17041 | condition_occurrence | 2008-04-07 | 2008-04-07 | 412 |
1547
+ | 149 | 17772 | condition_occurrence | 2008-08-16 | 2008-08-16 | 412 |
1548
+ | 149 | 17774 | condition_occurrence | 2010-11-22 | 2010-11-22 | 412 |
1549
+ | 158 | 18412 | condition_occurrence | 2009-10-25 | 2009-10-29 | 412 |
1550
+ | 183 | 21619 | condition_occurrence | 2010-12-26 | 2010-12-26 | 412 |
1551
+
1552
+ ## Sub-algorithms within a Larger Algorithm
1553
+
1554
+ 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.
1555
+
1556
+ ### `label` option
1557
+
1558
+ 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.
864
1559
 
1560
+ ### `recall` operator
1561
+
1562
+ - Takes 1 argument
1563
+ - The "label" of an operator from which you'd like to pull the exact same set of results
865
1564
 
866
1565
  A stream must be `define`d before `recall` can use it.
867
1566
 
868
- ```ConceptQL
869
- # Save away a stream of results to build the 1 inpatient, 2 outpatient pattern used in claims data algorithms
870
- [
871
- {
872
- define: [
873
- 'Heart Attack Visit',
874
- { visit_occurrence: { icd9: '412' } }
875
- ]
876
- },
877
-
878
- {
879
- define: [
880
- 'Inpatient Heart Attack',
881
- {
882
- intersect: [
883
- { recall: 'Heart Attack Visit'},
884
- { place_of_service_code: 21 }
885
- ]
886
- }
887
- ]
888
- },
889
-
890
- {
891
- define: [
892
- 'Outpatient Heart Attack',
893
- {
894
- intersect: [
895
- { recall: 'Heart Attack Visit'},
896
- {
897
- complement: {
898
- place_of_service_code: 21
899
- }
900
- }
901
- ]
902
- }
903
- ]
904
- },
905
-
906
- {
907
- define: [
908
- 'Earlier of Two Outpatient Heart Attacks',
909
- {
910
- before: {
911
- left: { recall: 'Outpatient Heart Attack' },
912
- right: {
913
- time_window: [
914
- { recall: 'Outpatient Heart Attack' },
915
- { start: '-30d', end: '0' }
916
- ]
917
- }
918
- }
919
- }
920
- ]
921
- },
922
-
923
- {
924
- first: {
925
- union: [
926
- { recall: 'Inpatient Heart Attack' },
927
- { recall: 'Earlier of Two Outpatient Heart Attacks'}
928
- ]
929
- }
930
- }
931
- ]
932
- ```
933
-
934
-
935
- ## Concepts within Concepts
1567
+
1568
+ ```YAML
1569
+ ---
1570
+ - first
1571
+ - - union
1572
+ - - intersect
1573
+ - - visit_occurrence
1574
+ - - icd9
1575
+ - '412'
1576
+ - :label: Heart Attack Visit
1577
+ - - place_of_service_code
1578
+ - '21'
1579
+ - - before
1580
+ - :left:
1581
+ - intersect
1582
+ - - recall
1583
+ - Heart Attack Visit
1584
+ - - complement
1585
+ - - place_of_service_code
1586
+ - 21
1587
+ - :label: Outpatient Heart Attack
1588
+ :right:
1589
+ - time_window
1590
+ - - recall
1591
+ - Outpatient Heart Attack
1592
+ - :start: "-30d"
1593
+ :end: '0'
1594
+ :label: Earliest of Two Outpatient Heart Attacks
1595
+
1596
+ ```
1597
+
1598
+ ![](spec/4a3b47ed1c54f96ebdae693d41c36c51884c4546ef799a4108085708fb7b964e.png)
1599
+
1600
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1601
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1602
+ | 59 | 2705 | visit_occurrence | 2009-07-19 | 2009-07-22 | Inpatient |
1603
+ | 79 | 3847 | visit_occurrence | 2009-01-28 | 2009-01-30 | Inpatient |
1604
+ | 86 | 4378 | visit_occurrence | 2009-01-03 | 2009-01-09 | Inpatient |
1605
+ | 128 | 6640 | visit_occurrence | 2008-03-22 | 2008-03-23 | Inpatient |
1606
+ | 158 | 8108 | visit_occurrence | 2009-10-25 | 2009-10-29 | Inpatient |
1607
+ | 173 | 8806 | visit_occurrence | 2009-06-13 | 2009-06-16 | Inpatient |
1608
+ | 222 | 11783 | visit_occurrence | 2008-03-14 | 2008-03-21 | Inpatient |
1609
+ | 260 | 13972 | visit_occurrence | 2010-05-29 | 2010-06-21 | Inpatient |
1610
+ | 352 | 18458 | visit_occurrence | 2008-07-02 | 2008-07-09 | Inpatient |
1611
+ | 407 | 20925 | visit_occurrence | 2008-08-25 | 2008-08-27 | Inpatient |
1612
+
1613
+ ## Algorithms within Algorithms
1614
+
936
1615
  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.
937
1616
 
938
1617
  Say a ConceptQL statement gathers all visit_occurrences where a patient had an MI and a Hospital encounter (CPT 99231):
939
1618
 
940
- ```ConceptQL
941
- # All Visits where a Patient had both an MI and a Hospital Encounter
942
- {
943
- intersect: [
944
- { visit_occurrence: { icd9: '412' } },
945
- { visit_occurrence: { cpt: '99231' } }
946
- ]
947
- }
1619
+
1620
+ ```YAML
1621
+ ---
1622
+ - intersect
1623
+ - - visit_occurrence
1624
+ - - icd9
1625
+ - '412'
1626
+ - - visit_occurrence
1627
+ - - cpt
1628
+ - '99231'
1629
+
948
1630
  ```
949
1631
 
950
- If we wanted to gather all costs for all procedures for those visits, we could use the "concept" node to represent the concept defined above in a new concept:
951
- ```ConceptQL
952
- # All Procedure Costs for All Visits as defined above
953
- {
954
- procedure_cost: {
955
- concept: "\nAll Visits\nwhere a Patient had\nboth an MI and\na Hospital Encounter"
956
- }
957
- }
1632
+ ![](spec/5d6ff62038b75d6f240d65f35d1520a131c221f47d3801554c8c2be5d528ebb0.png)
1633
+
1634
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1635
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1636
+ | 108335 | 5357904 | visit_occurrence | 2009-12-07 | 2009-12-07 | Office |
1637
+ | 23251 | 1158016 | visit_occurrence | 2009-07-24 | 2009-07-24 | Office |
1638
+ | 13270 | 662308 | visit_occurrence | 2010-07-23 | 2010-07-25 | Office |
1639
+ | 24119 | 1199980 | visit_occurrence | 2008-11-30 | 2008-12-05 | Office |
1640
+ | 91102 | 4511328 | visit_occurrence | 2008-09-01 | 2008-09-01 | Office |
1641
+ | 3646 | 184096 | visit_occurrence | 2009-01-09 | 2009-01-09 | Office |
1642
+ | 21338 | 1061186 | visit_occurrence | 2008-07-11 | 2008-07-11 | Office |
1643
+ | 86004 | 4256504 | visit_occurrence | 2008-04-18 | 2008-04-18 | Office |
1644
+ | 112447 | 5561049 | visit_occurrence | 2008-12-22 | 2008-12-25 | Office |
1645
+ | 20229 | 1009400 | visit_occurrence | 2008-09-06 | 2008-09-06 | Office |
1646
+
1647
+ 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:
1648
+
1649
+
1650
+ ```YAML
1651
+ ---
1652
+ - procedure_cost
1653
+ - - algorithm
1654
+ - |2-
1655
+
1656
+ All Visits
1657
+ where a Patient had
1658
+ both an MI and
1659
+ a Hospital Encounter
1660
+
958
1661
  ```
959
- The color and edge coming from the concept node 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 concept represented by the concept node for the concept's types. The result of nesting one concept within another is exactly the same had we taken concept node and replaced it with the ConceptQL statement for the concept it represents.
960
1662
 
961
- ```ConceptQL
962
- # Procedure Costs for All Visits where a Patient had both an MI and a Hospital Encounter (same as above)
963
- {
964
- procedure_cost: {
965
- intersect: [
966
- { visit_occurrence: { icd9: '412' } },
967
- { visit_occurrence: { cpt: '99231' } }
968
- ]
969
- }
970
- }
1663
+ ![](spec/eb8f5511f7d88bd0f8ba73420fc10f7c78405db7f4373d778a827058707f888e.png)
1664
+
1665
+ ```No Results. Statement is experimental.```
1666
+
1667
+ 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.
1668
+
1669
+
1670
+ ```YAML
1671
+ ---
1672
+ - procedure_cost
1673
+ - - intersect
1674
+ - - visit_occurrence
1675
+ - - icd9
1676
+ - '412'
1677
+ - - visit_occurrence
1678
+ - - cpt
1679
+ - '99231'
1680
+
971
1681
  ```
972
1682
 
973
- In the actual implementation of the concept node, each ConceptQL statement will have a unique identifier which the concept node will use. So, assuming that the ID 2031 represents the concept we want to gather all procedure costs for, our example should really read:
1683
+ ![](spec/6b48534236697d1ccfa1f5403764782f9d228f9eb706789cfa80203882b7b13a.png)
1684
+
1685
+ ```No Results. Statement is experimental.```
1686
+
1687
+ 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:
1688
+
1689
+
1690
+ ```YAML
1691
+ ---
1692
+ - procedure_cost
1693
+ - - algorithm
1694
+ - 2031
974
1695
 
975
- ```ConceptQL
976
- {
977
- procedure_cost: { concept: 2031 }
978
- }
979
1696
  ```
980
1697
 
1698
+ ![](spec/067241a3579767a802d4f8e20fd35b60adbe377c9a6512ef135f164a5accfb27.png)
1699
+
1700
+ ```No Results. Statement is experimental.```
981
1701
 
982
1702
  ## Values
1703
+
983
1704
  A result can carry forward three different types of values, modeled after the behavior of the observation table:
984
1705
 
985
1706
  - value_as_numeric
@@ -989,113 +1710,181 @@ A result can carry forward three different types of values, modeled after the be
989
1710
  - value_as_concept_id
990
1711
  - For values that are like factors from the observation value_as_concept_id column
991
1712
 
992
-
993
- By default, all value fields are set to NULL, unless a criterion node is explicitly written to populate one or more of those fields.
1713
+ By default, all value fields are set to NULL, unless a selection operator is explicitly written to populate one or more of those fields.
994
1714
 
995
1715
  There are many operations that can be performed on the value_as\_\* columns and as those operations are implemented, this section will grow.
996
1716
 
997
- For now we'll cover some of the general behavior of the value_as_numeric column and it's associated nodes.
1717
+ For now we'll cover some of the general behavior of the value_as_numeric column and it's associated operators.
1718
+
1719
+ ### numeric
998
1720
 
999
- #### numeric
1000
1721
  - Takes 2 arguments
1001
1722
  - A stream
1002
1723
  - And a numeric value or a symbol representing the name of a column in CDM
1003
1724
 
1004
- Passing streams through a `numeric` node changes the number stored in the value column:
1725
+ Passing streams through a `numeric` operator changes the number stored in the value column:
1726
+
1727
+
1728
+ ```YAML
1729
+ ---
1730
+ - numeric
1731
+ - 2
1732
+ - - icd9
1733
+ - '412'
1005
1734
 
1006
- ```ConceptQL
1007
- # All MIs, setting value_as_numeric to 2
1008
- {
1009
- numeric: [
1010
- { icd9: '412' },
1011
- 2
1012
- ]
1013
- }
1014
1735
  ```
1015
1736
 
1737
+ ![](spec/d39452b58257c95a7cba07afed4877417b0c227f3690e2bff22c9eca89eac845.png)
1738
+
1739
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1740
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1741
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
1742
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
1743
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
1744
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
1745
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
1746
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
1747
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
1748
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
1749
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
1750
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
1751
+
1016
1752
  `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.
1017
- ```ConceptQL
1018
- # All copays for 99214s
1019
- {
1020
- numeric: [
1021
- { procedure_cost: { cpt: '99214' } },
1022
- :paid_copay
1023
- ]
1024
- }
1753
+
1754
+
1755
+ ```YAML
1756
+ ---
1757
+ - numeric
1758
+ - paid_copay
1759
+ - - procedure_cost
1760
+ - - cpt
1761
+ - '99214'
1762
+
1025
1763
  ```
1026
1764
 
1765
+ ![](spec/3f46dee4d775d1a29d52b68af6552f8ea3abd8303094e749714fc77bd7958155.png)
1766
+
1767
+ ```No Results. Statement is experimental.```
1768
+
1027
1769
  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:
1028
- ```ConceptQL
1029
- # Still all MIs with value_as_numeric defaulted to NULL. condition_occurrence table doesn't have a "paid_copay" column
1030
- {
1031
- value: [
1032
- { icd9: '412' },
1033
- :paid_copay
1034
- ]
1035
- }
1770
+
1771
+
1772
+ ```YAML
1773
+ ---
1774
+ - value
1775
+ - paid_copay
1776
+ - - icd9
1777
+ - '412'
1778
+
1036
1779
  ```
1037
1780
 
1781
+ ![](spec/2b57886a9cba66bb696e4b399c51ad0dc95cd64b952709fafc819a79d573f09e.png)
1782
+
1783
+ ```No Results. Statement is experimental.```
1784
+
1038
1785
  Or if the column specified exists, but refers to a non-numerical column, we'll set the value to 0
1039
- ```ConceptQL
1040
- # All MIs, with value set to 0 since the column specified by value node is a non-numerical column
1041
- {
1042
- value: [
1043
- { icd9: '412' },
1044
- :stop_reason
1045
- ]
1046
- }
1047
- ```
1048
-
1049
- With a `numeric` node defined, we could introduce a sum node that will sum by patient and type. This allows us to implement the Charlson comorbidity algorithm:
1050
- ```ConceptQL
1051
- {
1052
- sum: [
1053
- {
1054
- union: [
1055
- {
1056
- numeric: [
1057
- { person: { icd9: '412' } },
1058
- 1
1059
- ]
1060
- },
1061
- {
1062
- numeric: [
1063
- { person: { icd9: '278.02' } },
1064
- 2
1065
- ]
1066
- }
1067
- ]
1068
- }
1069
- ]
1070
- }
1786
+
1787
+
1788
+ ```YAML
1789
+ ---
1790
+ - value
1791
+ - stop_reason
1792
+ - - icd9
1793
+ - '412'
1794
+
1071
1795
  ```
1072
1796
 
1797
+ ![](spec/7b9db2986ab9ada45cfb9451ef87ff1a2d99c908083334b7ccdceb8a92387fa9.png)
1798
+
1799
+ ```No Results. Statement is experimental.```
1800
+
1801
+ 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:
1802
+
1803
+
1804
+ ```YAML
1805
+ ---
1806
+ - sum
1807
+ - - union
1808
+ - - numeric
1809
+ - 1
1810
+ - - person
1811
+ - - icd9
1812
+ - '412'
1813
+ - - numeric
1814
+ - 2
1815
+ - - person
1816
+ - - icd9
1817
+ - '278.02'
1818
+
1819
+ ```
1820
+
1821
+ ![](spec/ba572c4f4dbade65be55f141df16cf7b3e7d09e0aec4e4e5debc4f2075277371.png)
1822
+
1823
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1824
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1825
+ | 20485 | 0 | person | 1939-04-01 | 1939-04-01 | 2DDD007275DD21E0 |
1826
+ | 79028 | 0 | person | 1959-02-01 | 1959-02-01 | B392FC430DF921CD |
1827
+ | 100859 | 0 | person | 1956-05-01 | 1956-05-01 | E52898242C537BA0 |
1828
+ | 14065 | 0 | person | 1946-11-01 | 1946-11-01 | 1F60AFE3D4FBB0F8 |
1829
+ | 19728 | 0 | person | 1929-03-01 | 1929-03-01 | 2C18DC0853458E88 |
1830
+ | 6249 | 0 | person | 1941-03-01 | 1941-03-01 | 0DD88DF606E34410 |
1831
+ | 81868 | 0 | person | 1942-09-01 | 1942-09-01 | BA17E53F3EB2C999 |
1832
+ | 111550 | 0 | person | 1943-06-01 | 1943-06-01 | FD35C56E74BFB4AB |
1833
+ | 93771 | 0 | person | 1941-01-01 | 1941-01-01 | D4BF3A123E98674C |
1834
+ | 92853 | 0 | person | 1932-06-01 | 1932-06-01 | D2945588C9CE4481 |
1835
+
1073
1836
  ### Counting
1074
- It might be helpful to count the number of occurrences of a result row in a stream. A simple "count" node could group identical rows and store the number of occurrences in the value_as_numeric column.
1075
1837
 
1076
- I need examples of algorithms that could benefit from this node. 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.
1077
- ```ConceptQL
1078
- # Count the number of times each person was irritable
1079
- {
1080
- count: { person: { icd9: '799.22' } }
1081
- }
1838
+ 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.
1839
+
1840
+ 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.
1841
+
1842
+
1843
+ ```YAML
1844
+ ---
1845
+ - count
1846
+ - - person
1847
+ - - icd9
1848
+ - '799.22'
1849
+
1082
1850
  ```
1083
1851
 
1852
+ ![](spec/ff7d5b5573d09bd7c4cdd3aeda124d18bf82ec46673a62881b399a75d69f3f53.png)
1853
+
1854
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
1855
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
1856
+ | 84506 | 84506 | person | 1946-11-01 | 1946-11-01 | BFD9934105A902C5 |
1857
+ | 8511 | 8511 | person | 1934-02-01 | 1934-02-01 | 12F9E8CFD305414D |
1858
+ | 58597 | 58597 | person | 1922-11-01 | 1922-11-01 | 84841824E5D1516F |
1859
+ | 17481 | 17481 | person | 1952-04-01 | 1952-04-01 | 272C688CA4CFC78F |
1860
+ | 79930 | 79930 | person | 1940-04-01 | 1940-04-01 | B5AA192186CEFC33 |
1861
+ | 83321 | 83321 | person | 1928-06-01 | 1928-06-01 | BD49BED9C6228FA1 |
1862
+ | 111134 | 111134 | person | 1960-05-01 | 1960-05-01 | FC4C2599EA86941A |
1863
+ | 112745 | 112745 | person | 1959-07-01 | 1959-07-01 | FFFA950301FCA748 |
1864
+ | 11368 | 11368 | person | 1955-08-01 | 1955-08-01 | 19546CD71F65766E |
1865
+ | 24243 | 24243 | person | 1930-01-01 | 1930-01-01 | 3695943370154829 |
1866
+
1084
1867
  We could do dumb things like count the number of times a row shows up in a union:
1085
- ```ConceptQL
1086
- # All rows with a value of 2 would be rows that were both MI and Primary
1087
- {
1088
- count: {
1089
- union: [
1090
- { icd9: '412' },
1091
- { primary_diagnosis: true}
1092
- ]
1093
- }
1094
- }
1868
+
1869
+
1870
+ ```YAML
1871
+ ---
1872
+ - count
1873
+ - - union
1874
+ - - icd9
1875
+ - '412'
1876
+ - - primary_diagnosis
1877
+ - true
1878
+
1095
1879
  ```
1096
1880
 
1881
+ ![](spec/7aa76b4d29874719466c2cbafc9936e9f12e504bf31e1a09d26ca3fffa8ba1a6.png)
1882
+
1883
+ ```No Results. Statement is experimental.```
1884
+
1097
1885
  #### Numeric Value Comparison
1098
- Acts like any other binary node. 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.
1886
+
1887
+ 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.
1099
1888
 
1100
1889
  - Less than
1101
1890
  - Less than or equal
@@ -1104,32 +1893,41 @@ Acts like any other binary node. L and R streams, joined by person. Any L that
1104
1893
  - Greater than
1105
1894
  - Not equal
1106
1895
 
1896
+ ### numeric as selection operator
1897
+
1898
+ 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
1107
1899
 
1108
- ### numeric as criterion node
1109
- Numeric doesn't have to take a stream. If it doesn't have a stream as an argument, it acts like a criterion node much like date_range
1110
- ```ConceptQL
1111
- # People with more than 1 MI
1112
- {
1113
1900
 
1114
- greater_than: {
1115
- left: { count: { person: { icd9: '412' }}},
1116
- right: { numeric: 1 }
1117
- }
1118
- }
1901
+ ```YAML
1902
+ ---
1903
+ - greater_than
1904
+ - :left:
1905
+ - count
1906
+ - - person
1907
+ - - icd9
1908
+ - '412'
1909
+ :right:
1910
+ - numeric
1911
+ - 1
1912
+
1119
1913
  ```
1120
1914
 
1915
+ ![](spec/c1d0402862221d85aceedc7d76b3f82149b612cbd972f14d0ca9011e1e2c455c.png)
1916
+
1917
+ ```No Results. Statement is experimental.```
1918
+
1121
1919
  #### sum
1920
+
1122
1921
  - Takes a stream of results and does some wild things
1123
1922
  - Groups all results by person and type
1124
1923
  - Sums the value_as_numeric column within that grouping
1125
1924
  - Sets start_date to the earliest start_date in the group
1126
1925
  - Sets the end_date to the most recent end_date in the group
1127
- - Sets criterion_id to 0 since there is no particular single row that the result refers to anymore
1926
+ - Sets selection_id to 0 since there is no particular single row that the result refers to anymore
1128
1927
 
1928
+ ## Appendix A - Selection Operators
1129
1929
 
1130
- # Appendix A - Criterion Nodes
1131
-
1132
- | Node Name | Stream Type | Arguments | Returns |
1930
+ | Operator Name | Stream Type | Arguments | Returns |
1133
1931
  | ---- | ---- | --------- | ------- |
1134
1932
  | cpt | procedure_occurrence | 1 or more CPT codes | All results whose source_value match any of the CPT codes |
1135
1933
  | icd9 | condition_occurrence | 1 or more ICD-9 codes | All results whose source_value match any of the ICD-9 codes |
@@ -1143,148 +1941,229 @@ Numeric doesn't have to take a stream. If it doesn't have a stream as an argume
1143
1941
  | rxnorm | drug_exposure | 1 or more RxNorm IDs | All results whose drug_concept_id match any of the RxNorm IDs|
1144
1942
  | snomed | condition_occurrence | 1 or more SNOMED codes | All results whose source_value match any of the SNOMED codes |
1145
1943
 
1944
+ ## Appendix B - Algorithm Showcase
1146
1945
 
1147
- # Appendix B - Concept Showcase
1148
- Here I take some concepts 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.
1946
+ 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.
1149
1947
 
1150
1948
  ### Acute Kidney Injury - Narrow Definition and diagnositc procedure
1151
1949
 
1152
1950
  - ICD-9 of 584
1153
1951
  - AND
1154
- - ICD-9 procedure codes of 39.95 or 54.98 within 60 days after diagnosis
1952
+ - ICD-9 procedure codes of 39.95 or 54.98 within 60 days after diagnosis
1155
1953
  - AND NOT
1156
- - A diagnostic code of chronic dialysis any time before initial diagnosis
1157
- - V45.1, V56.0, V56.31, V56.32, V56.8
1158
- ```ConceptQL
1159
- {
1160
- during: {
1161
- left: {
1162
- except: {
1163
- left: { icd9: '584' },
1164
- right: {
1165
- after: {
1166
- left: { icd9: '584' },
1167
- right: { icd9: [ 'V45.1', 'V56.0', 'V56.31', 'V56.32', 'V56.8' ] }
1168
- }
1169
- }
1170
- }
1171
- },
1172
- right: {
1173
- time_window: [
1174
- { icd9_procedure: [ '39.95', '54.98' ] },
1175
- { start: '0', end: '60d' }
1176
- ]
1177
- }
1178
- }
1179
- }
1180
- ```
1954
+ - A diagnostic code of chronic dialysis any time before initial diagnosis
1955
+ - V45.1, V56.0, V56.31, V56.32, V56.8
1956
+
1957
+
1958
+ ```YAML
1959
+ ---
1960
+ - during
1961
+ - :left:
1962
+ - except
1963
+ - :left:
1964
+ - icd9
1965
+ - '584'
1966
+ :right:
1967
+ - after
1968
+ - :left:
1969
+ - icd9
1970
+ - '584'
1971
+ :right:
1972
+ - icd9
1973
+ - V45.1
1974
+ - V56.0
1975
+ - V56.31
1976
+ - V56.32
1977
+ - V56.8
1978
+ :right:
1979
+ - time_window
1980
+ - - icd9_procedure
1981
+ - '39.95'
1982
+ - '54.98'
1983
+ - :start: '0'
1984
+ :end: 60d
1985
+
1986
+ ```
1987
+
1988
+ ![](spec/44ec6743d5d77d15b8a487c2058bf3e455d34adc91c46ea05767f6e0e471a75e.png)
1989
+
1990
+ ```No Results found.```
1181
1991
 
1182
1992
  ### Mortality after Myocardial Infarction #3
1993
+
1183
1994
  - Person Died
1184
1995
  - And Occurrence of 410\* prior to death
1185
1996
  - And either
1186
- - MI diagnosis within 30 days prior to 410
1187
- - MI therapy within 60 days after 410
1188
- ```ConceptQL
1189
- {
1190
- during: {
1191
- left: {
1192
- before: {
1193
- left: { icd9: '410*' },
1194
- right: { death: true }
1195
- }
1196
- },
1197
- right: {
1198
- union: [
1199
- {
1200
- time_window: [
1201
- {
1202
- union: [
1203
- { cpt: [ '0146T', '75898', '82554', '92980', '93010', '93233', '93508', '93540', '93545' ] },
1204
- { icd9_procedure: [ '00.24', '36.02', '89.53', '89.57', '89.69' ] },
1205
- { loinc: [ '10839-9', '13969-1', '18843-3', '2154-3', '33204-9', '48425-3', '49259-5', '6597-9', '8634-8' ] }
1206
- ]
1207
- },
1208
- { start: '-30d', end: '0' }
1209
- ]
1210
- },
1211
- {
1212
- time_window: [
1213
- {
1214
- union: [
1215
- { cpt: [ '0146T', '75898', '82554', '92980', '93010', '93233'] },
1216
- { icd9_procedure: [ '00.24', '36.02', '89.53', '89.57', '89.69' ] }
1217
- ]
1218
- },
1219
- { start: '', end: '60d' }
1220
- ]
1221
- }
1222
- ]
1223
- }
1224
- }
1225
- }
1226
- ```
1997
+ - MI diagnosis within 30 days prior to 410
1998
+ - MI therapy within 60 days after 410
1999
+
2000
+
2001
+ ```YAML
2002
+ ---
2003
+ - during
2004
+ - :left:
2005
+ - before
2006
+ - :left:
2007
+ - icd9
2008
+ - 410*
2009
+ :right:
2010
+ - death
2011
+ - true
2012
+ :right:
2013
+ - union
2014
+ - - time_window
2015
+ - - union
2016
+ - - cpt
2017
+ - 0146T
2018
+ - '75898'
2019
+ - '82554'
2020
+ - '92980'
2021
+ - '93010'
2022
+ - '93233'
2023
+ - '93508'
2024
+ - '93540'
2025
+ - '93545'
2026
+ - - icd9_procedure
2027
+ - '00.24'
2028
+ - '36.02'
2029
+ - '89.53'
2030
+ - '89.57'
2031
+ - '89.69'
2032
+ - - loinc
2033
+ - 10839-9
2034
+ - 13969-1
2035
+ - 18843-3
2036
+ - 2154-3
2037
+ - 33204-9
2038
+ - 48425-3
2039
+ - 49259-5
2040
+ - 6597-9
2041
+ - 8634-8
2042
+ - :start: "-30d"
2043
+ :end: '0'
2044
+ - - time_window
2045
+ - - union
2046
+ - - cpt
2047
+ - 0146T
2048
+ - '75898'
2049
+ - '82554'
2050
+ - '92980'
2051
+ - '93010'
2052
+ - '93233'
2053
+ - - icd9_procedure
2054
+ - '00.24'
2055
+ - '36.02'
2056
+ - '89.53'
2057
+ - '89.57'
2058
+ - '89.69'
2059
+ - :start: ''
2060
+ :end: 60d
2061
+
2062
+ ```
2063
+
2064
+ ![](spec/307a8b5a7edd6e42f8be16523a4c939faf1a0533385c861d7004b6af8addd7d1.png)
2065
+
2066
+ ```No Results found.```
1227
2067
 
1228
2068
  ### GI Ulcer Hospitalization 2 (5000001002)
2069
+
1229
2070
  - Occurrence of GI Ulcer diagnostic code
1230
2071
  - Hospitalization at time of diagnostic code
1231
2072
  - At least one diagnostic procedure during same hospitalization
1232
- ```ConceptQL
1233
- # 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
1234
- {
1235
- union: [
1236
- { place_of_service: [ 'Inpatient' ]},
1237
- { visit_occurrence: { icd9: '410' } },
1238
- {
1239
- visit_occurrence: {
1240
- union: [
1241
- { cpt: [ '0008T', '3142F', '43205', '43236', '76975', '91110', '91111' ] },
1242
- { hcpcs: [ 'B4081', 'B4082' ] },
1243
- { icd9_procedure: [ '42.22', '42.23', '44.13', '45.13', '52.21', '97.01' ] },
1244
- { loinc: [ '16125-7', '17780-8', '40820-3', '50320-1', '5177-1', '7901-2' ] }
1245
- ]
1246
- }
1247
- }
1248
- ]
1249
- }
1250
- ```
1251
-
1252
- # Appendix C - Under Development
2073
+
2074
+
2075
+ ```YAML
2076
+ ---
2077
+ - union
2078
+ - - place_of_service_code
2079
+ - '21'
2080
+ - - visit_occurrence
2081
+ - - icd9
2082
+ - '410'
2083
+ - - visit_occurrence
2084
+ - - union
2085
+ - - cpt
2086
+ - 0008T
2087
+ - 3142F
2088
+ - '43205'
2089
+ - '43236'
2090
+ - '76975'
2091
+ - '91110'
2092
+ - '91111'
2093
+ - - hcpcs
2094
+ - B4081
2095
+ - B4082
2096
+ - - icd9_procedure
2097
+ - '42.22'
2098
+ - '42.23'
2099
+ - '44.13'
2100
+ - '45.13'
2101
+ - '52.21'
2102
+ - '97.01'
2103
+ - - loinc
2104
+ - 16125-7
2105
+ - 17780-8
2106
+ - 40820-3
2107
+ - 50320-1
2108
+ - 5177-1
2109
+ - 7901-2
2110
+
2111
+ ```
2112
+
2113
+ ![](spec/99392f56dfb0e5be3f45a12a7f1ba846d094e430f526dfeaa30b606837cd34c0.png)
2114
+
2115
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
2116
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
2117
+ | 1 | 1 | visit_occurrence | 2010-03-12 | 2010-03-13 | Inpatient |
2118
+ | 2 | 8 | visit_occurrence | 2009-09-17 | 2009-09-20 | Inpatient |
2119
+ | 2 | 9 | visit_occurrence | 2009-04-12 | 2009-04-18 | Inpatient |
2120
+ | 2 | 10 | visit_occurrence | 2010-06-26 | 2010-07-01 | Inpatient |
2121
+ | 2 | 11 | visit_occurrence | 2009-08-31 | 2009-09-02 | Inpatient |
2122
+ | 14 | 507 | visit_occurrence | 2008-09-12 | 2008-09-12 | Inpatient |
2123
+ | 17 | 729 | visit_occurrence | 2010-05-22 | 2010-06-12 | Inpatient |
2124
+ | 17 | 730 | visit_occurrence | 2008-09-19 | 2008-09-22 | Inpatient |
2125
+ | 17 | 731 | visit_occurrence | 2010-06-02 | 2010-06-06 | Inpatient |
2126
+ | 17 | 732 | visit_occurrence | 2010-06-16 | 2010-06-19 | Inpatient |
2127
+
2128
+ ## Appendix C - Under Development
2129
+
1253
2130
  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.
1254
2131
 
1255
2132
  ### Todo List
2133
+
1256
2134
  1. Handle costs
1257
2135
  - How do we aggregate?
1258
- 2. How do we count?
1259
- 3. How do we handle missing values in streams?
2136
+ 1. How do we count?
2137
+ 1. How do we handle missing values in streams?
1260
2138
  - For instance, missing DoB on patient?
1261
- 4. What does it mean to pass a date range as an L stream?
2139
+ 1. What does it mean to pass a date range as an L stream?
1262
2140
  - I'm thinking we pass through no results
1263
2141
  - 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
1264
- 5. How do we want to look up standard vocab concepts?
1265
- - I think Marc’s approach is a bit heavy-handed
1266
-
1267
- 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 node 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 node appears.
2142
+ 1. How do we want to look up standard vocab concepts?
2143
+ - I think Marc’s approach is a bit heavy-handed
1268
2144
 
2145
+ 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.
1269
2146
 
1270
2147
  ### Future Work for Define and Recall
1271
- I'd like to make it so if a variable node is used, but not defined, the concept is still valid, but will fail to run until a definition for all missing variables is provided.
2148
+
2149
+ 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.
1272
2150
 
1273
2151
  But I don't have a good feel for:
1274
2152
 
1275
2153
  - Whether we should have users name the variables, or auto-assign a name?
1276
- - We risk name collisions if a concept includes a sub-concept with the same variable name
2154
+ - We risk name collisions if a algorithm includes a sub-algorithm with the same variable name
1277
2155
  - Probably need to name space all variables
1278
2156
  - How to prompt users to enter values for variables in a concept
1279
- - If we have name-spaced variables and sub-concepts needing values, how do we show this in a coherent manner to a user?
1280
- - We'll need to do a pass through a concept to find all variables and prompt a user, then do another pass through the concept before attempting to execute it to ensure all variables have values
2157
+ - If we have name-spaced variables and sub-algorithms needing values, how do we show this in a coherent manner to a user?
2158
+ - 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
1281
2159
  - Do we throw an exception if not?
1282
- - Do we require calling programs to invoke a check on the concept before generating the query?
1283
- - Perhaps slot is a different node from "define"
1284
-
2160
+ - Do we require calling programs to invoke a check on the algorithm before generating the query?
2161
+ - Perhaps slot is a different operator from "define"
1285
2162
 
1286
2163
  ### Considerations for Values
2164
+
1287
2165
  I'm considering defaulting each value_as\_\* column to some value.
2166
+
1288
2167
  - numeric => 1
1289
2168
  - concept_id => 0
1290
2169
  - Or maybe the concept_id of the main concept_id value from the row?
@@ -1295,47 +2174,82 @@ I'm considering defaulting each value_as\_\* column to some value.
1295
2174
  - source_value?
1296
2175
  - Boy, this one is even harder to default
1297
2176
 
1298
- ```ConceptQL
1299
- # All MIs, defaulting value_as_numeric to 1, concept_id to concept id for 412, string to condition_source_value
1300
- { icd9: '412' }
2177
+
2178
+ ```YAML
2179
+ ---
2180
+ - icd9
2181
+ - '412'
2182
+
1301
2183
  ```
1302
2184
 
2185
+ ![](spec/f6b4fc31703cfb6327bbbd4614af8bb72da6d39fa3d53ada63a70157f2fad80e.png)
2186
+
2187
+ | person_id | criterion_id | criterion_type | start_date | end_date | source_value |
2188
+ | --------- | ------------ | -------------- | ---------- | -------- | ------------ |
2189
+ | 17 | 1712 | condition_occurrence | 2008-08-25 | 2008-08-25 | 412 |
2190
+ | 17 | 1829 | condition_occurrence | 2009-04-30 | 2009-04-30 | 412 |
2191
+ | 37 | 4359 | condition_occurrence | 2010-02-12 | 2010-02-12 | 412 |
2192
+ | 53 | 5751 | condition_occurrence | 2008-06-05 | 2008-06-05 | 412 |
2193
+ | 59 | 6083 | condition_occurrence | 2009-07-19 | 2009-07-22 | 412 |
2194
+ | 64 | 6902 | condition_occurrence | 2009-07-25 | 2009-07-25 | 412 |
2195
+ | 71 | 7865 | condition_occurrence | 2008-11-16 | 2008-11-16 | 412 |
2196
+ | 75 | 8397 | condition_occurrence | 2010-10-06 | 2010-10-06 | 412 |
2197
+ | 79 | 8618 | condition_occurrence | 2009-01-28 | 2009-01-30 | 412 |
2198
+ | 86 | 9882 | condition_occurrence | 2009-01-03 | 2009-01-09 | 412 |
2199
+
2200
+ ### Filter Operator
2201
+
2202
+ 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:
2203
+
2204
+
2205
+ ```YAML
2206
+ ---
2207
+ - filter
2208
+ - :left:
2209
+ - cpt
2210
+ - '99214'
2211
+ :right:
2212
+ - icd9
2213
+ - '799.22'
2214
+ :as: visit_occurrence
1303
2215
 
1304
- ### Filter Node
1305
- Inspired by person_filter, why not just have a "filter" node 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:
1306
- ```ConceptQL
1307
- # All 99214's where person was irritable during a visit
1308
- {
1309
- filter: {
1310
- left: { cpt: '99214' },
1311
- right: { icd9: '799.22' },
1312
- as: 'visit_occurrence'
1313
- }
1314
- }
1315
2216
  ```
1316
2217
 
2218
+ ![](spec/c5329a7f4937096a57b2e01efb9d542f84a4e2329a1e9381d08c630583ccad37.png)
2219
+
2220
+ ```No Results found.```
2221
+
1317
2222
  person_filter then becomes a special case of general filter:
1318
- ```ConceptQL
1319
- # All 99214's where person was irritable at some point in the data
1320
- {
1321
- filter: {
1322
- left: { cpt: '99214' },
1323
- right: { icd9: '799.22' },
1324
- as: 'person'
1325
- }
1326
- }
2223
+
2224
+
2225
+ ```YAML
2226
+ ---
2227
+ - filter
2228
+ - :left:
2229
+ - cpt
2230
+ - '99214'
2231
+ :right:
2232
+ - icd9
2233
+ - '799.22'
2234
+ :as: person
2235
+
1327
2236
  ```
1328
2237
 
1329
- Filter node is the opposite of Except. It only includes L if R matches.
2238
+ ![](spec/9139440329dcb815df89bc70182c3827868402a74ff64d0253706dcaff723dca.png)
2239
+
2240
+ ```No Results found.```
2241
+
2242
+ Filter operator is the opposite of Except. It only includes L if R matches.
1330
2243
 
1331
2244
  ### AS option for Except
1332
- Just like Filter has an :as option, add one to Except node. This would simplify some of the algorithms I've developed.
1333
2245
 
2246
+ Just like Filter has an :as option, add one to Except operator. This would simplify some of the algorithms I've developed.
1334
2247
 
1335
2248
  ### How to Handle fact_relationship Table from CDMv5
1336
- Each relationship type could be a binary node 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.
1337
2249
 
1338
- We could implement a single node that takes a relationship as an argument (on top of the L and R arguments) or we could create a node class for each relationship. I think it would be better to have a single relationship node class and take the relationship as the argument.
2250
+ 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.
2251
+
2252
+ 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.
1339
2253
 
1340
2254
  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.
1341
2255