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