diff --git a/flows/Load_DICOM_Vocab.json b/flows/Load_DICOM_Vocab.json
index ba9ab77..1bb60b8 100644
--- a/flows/Load_DICOM_Vocab.json
+++ b/flows/Load_DICOM_Vocab.json
@@ -196,7 +196,7 @@
"id": "13660611-484f-48ab-80fb-ba90dc8b68aa",
"data": {
"name": "TransformConceptRelationshipDf",
- "description": "Describe the task of node python_node_1",
+ "description": "Transform concept relationship vocabulary data into the OMOP-compatible column structure.",
"python_code": "import pickle\nimport numpy as np\n\nfrom pathlib import Path\nfrom typing import Any, Dict\n\ndef exec(myinput: Dict[str, Any]) -> pd.DataFrame:\n \"\"\"\n Combine multiple DICOM concept relationship dataframes into a single staging dataframe.\n \n This function processes three sources of DICOM data:\n 1. Cs_values_maps_to_value (Code String values mapped to values)\n 2. Cs_values_maps_to (Code String values mappings)\n 3. Part3_to_part16_relationship_via_CID (from pickle file in storage)\n \n The function downloads a pickle file containing concept relationships, converts\n date columns to datetime format, assigns default date ranges to the other datasets,\n and combines all three into a single dataframe.\n \n Args:\n myinput: Dictionary containing workflow data with the following expected keys:\n - \"UploadAttributes-CodeStringValues\": Result containing cs_values_maps_to_value DataFrame\n - \"UploadCs_values_maps_to\": Result containing cs_values_maps_to DataFrame\n - \"UploadAttributes-CID-ValueSets\": Result containing node_id and filename for pickle file\n \n Returns:\n pd.DataFrame: Combined dataframe with all concept relationships, including properly\n formatted valid_start_date and valid_end_date columns.\n \"\"\"\n cs_values_maps_to_value_df: pd.DataFrame = myinput.get(\"UploadAttributes-CodeStringValues\").result\n cs_values_maps_to_df: pd.DataFrame = myinput.get(\"UploadCs_values_maps_to\").result\n \n node_id: str = myinput.get(\"UploadAttributes-CID-ValueSets\").result.get(\"node_id\")\n filename: str = myinput.get(\"UploadAttributes-CID-ValueSets\").result.get(\"filename\")\n \n # Download the pickle file from remote storage\n download_file_from_storage(node_id, filename)\n\n filepath: Path = Path(DOWNLOADS_DIR) / filename\n\n concept_relationship_staging: pd.DataFrame = pd.read_pickle(filepath)\n\n # Convert date columns from integer (YYYYMMDD) to datetime using vectorized operations\n concept_relationship_staging['valid_start_date'] = pd.to_datetime(\n concept_relationship_staging['valid_start_date'], \n format='%Y%m%d', \n errors='coerce'\n )\n\n concept_relationship_staging['valid_end_date'] = pd.to_datetime(\n concept_relationship_staging['valid_end_date'], \n format='%Y%m%d', \n errors='coerce'\n )\n\n # Assign constant dates to all rows (vectorized - no loops needed)\n cs_values_maps_to_value_df['valid_start_date'] = pd.to_datetime('1993-01-01')\n cs_values_maps_to_value_df['valid_end_date'] = pd.to_datetime('2099-12-31')\n\n cs_values_maps_to_df['valid_start_date'] = pd.to_datetime('1993-01-01')\n cs_values_maps_to_df['valid_end_date'] = pd.to_datetime('2099-12-31')\n\n # Combine the three dataframes into one\n combined_df: pd.DataFrame = pd.concat([concept_relationship_staging, cs_values_maps_to_value_df, cs_values_maps_to_df], ignore_index=True)\n\n return combined_df\n\n\ndef download_file_from_storage(node_id: str, filename: str) -> Path:\n \"\"\"\n Download a file from Supabase storage to the downloads directory.\n \n Args:\n node_id: The storage node identifier where the file is located.\n filename: The name of the file to download.\n \n Returns:\n Path: The path to the downloaded file.\n \"\"\"\n storage_api = SupabaseStorageAPI()\n return storage_api.download_file_to_path(node_id, filename, Path(DOWNLOADS_DIR))"
},
"type": "python_node",
diff --git a/flows/artemis.json b/flows/artemis.json
index da2b846..5c610d2 100644
--- a/flows/artemis.json
+++ b/flows/artemis.json
@@ -25,7 +25,7 @@
"positionAbsolute": { "x": -420, "y": 80 },
"data": {
"name": "README",
- "description": "Describe the ARTEMIS flow and supported conditions.",
+ "description": "Explain the ARTEMIS flow, its configurable inputs, and supported conditions.",
"python_code": "def exec(myinput):\n \"\"\"\n ARTEMIS provides an interface for utilizing a modified Temporal Smith-Waterman (TSW) algorithm \n that is capable of analysing conditions in the following list\n [1] \"ER Breast cancer\" \n [2] \"Prostate cancer\" \n [3] \"undefined\" \n [4] \"Mantle cell lymphoma\" \n [5] \"Acute myeloid leukemia\" \n [6] \"KRAS Colorectal cancer\" \n [7] \"Non-small cell lung cancer\" \n [8] \"Non-small cell lung cancer squamous\" \n [9] \"Kaposi sarcoma\" \n [10] \"Acute promyelocytic leukemia\" \n [11] \"Immune thrombocytopenia\" \n [12] \"Acute myeloid leukemia pediatric\" \n [13] \"Castleman disease\" \n [14] \"Endometrial cancer\" \n [15] \"Myelodysplastic syndrome\" \n [16] \"Hepatocellular carcinoma\" \n [17] \"Thyroid cancer differentiated\" \n [18] \"Chronic myeloid leukemia\" \n [19] \"T-cell acute lymphoblastic leukemia pediatric\" \n [20] \"Extranodal NK- and T-cell lymphoma nasal type\" \n [21] \"Antiphospholipid antibody syndrome\" \n [22] \"Venous thromboembolism\" \n [23] \"Systemic mastocytosis\" \n [24] \"Clear cell renal cell carcinoma\" \n [25] \"Thyroid cancer medullary\" \n [26] \"IDH Acute myeloid leukemia\" \n [27] \"Graft versus host disease\" \n [28] \"VHL Renal cell carcinoma\" \n [29] \"Chronic lymphocytic leukemia\" \n [30] \"Transformed lymphoma\" \n [31] \"Renal cell carcinoma\" \n [32] \"Ovarian cancer\" \n [33] \"Cutaneous T-cell lymphoma\" \n [34] \"NRAS Melanoma\" \n [35] \"Testicular cancer\" \n [36] \"HIV-associated lymphoma\" \n [37] \"BCR::ABL1 B-cell acute lymphoblastic leukemia\" \n [38] \"Multiple myeloma\" \n [39] \"Waldenstroem macroglobulinemia\" \n [40] \"Chronic myeloid leukemia pediatric\" \n [41] \"Gastric cancer\" \n [42] \"Colorectal cancer\" \n [43] \"Pancreatic cancer\" \n [44] \"ERBB2 Breast cancer\" \n [45] \"Rectal cancer\" \n [46] \"TNBC Breast cancer\" \n [47] \"Small cell lung cancer\" \n [48] \"Glioblastoma\" \n [49] \"Peripheral T-cell lymphoma\" \n [50] \"CNS lymphoma\" \n [51] \"Head and neck cancer\" \n [52] \"ROS1 Non-small cell lung cancer\" \n [53] \"Diffuse large B-cell lymphoma\" \n [54] \"Breast cancer\" \n [55] \"Classical Hodgkin lymphoma\" \n [56] \"Osteosarcoma\" \n [57] \"Cutaneous squamous cell carcinoma\" \n [58] \"Adrenocortical carcinoma\" \n [59] \"B-cell acute lymphoblastic leukemia pediatric\" \n [60] \"Melanoma\" \n [61] \"Light-chain (AL) amyloidosis\" \n [62] \"B-cell acute lymphoblastic leukemia\" \n [63] \"Rhabdomyosarcoma\" \n [64] \"BCR::ABL1 B-cell acute lymphoblastic leukemia pediatric\" \n [65] \"Non-Hodgkin lymphoma pediatric\" \n [66] \"FLT3 Acute myeloid leukemia\" \n [67] \"NPM1 Acute myeloid leukemia\" \n [68] \"Thyroid cancer\" \n [69] \"Indolent lymphoma\" \n [70] \"Neuroblastoma\" \n [71] \"Papillary renal cell carcinoma\" \n [72] \"Pancreatic NET\" \n [73] \"Myelofibrosis\" \n [74] \"Penile cancer\" \n [75] \"Cholangiocarcinoma\" \n [76] \"Non-small cell lung cancer nonsquamous\" \n [77] \"Sickle cell anemia\" \n [78] \"Marginal zone lymphoma\" \n [79] \"T-cell prolymphocytic leukemia\" \n [80] \"Uveal melanoma\" \n [81] \"Neuroendocrine tumor\" \n [82] \"ER|ERBB2 Breast cancer\" \n [83] \"Malignant solid neoplasm NTRK-mutated\" \n [84] \"Low-grade serous ovarian cancer\" \n [85] \"Gastrointestinal stromal tumor\" \n [86] \"WHIM syndrome\" \n [87] \"Plasma cell leukemia\" \n [88] \"Gestational trophoblastic neoplasia\" \n [89] \"Langerhans cell histiocytosis\" \n [90] \"Malignant solid neoplasm ERBB3-mutated\" \n [91] \"Desmoid tumor\" \n [92] \"Thymoma\" \n [93] \"MALT lymphoma\" \n [94] \"Warm autoimmune hemolytic anemia\" \n [95] \"Burkitt lymphoma\" \n [96] \"Soft tissue sarcoma\" \n [97] \"Polycythemia vera\" \n [98] \"Cutaneous basal cell carcinoma\" \n [99] \"Follicular lymphoma\" \n [100] \"Smoldering multiple myeloma\" \n [101] \"Adult T-cell leukemia-lymphoma\" \n [102] \"Malignant solid neoplasm SMO-mutated or PTCH-1-mutated (Hedgehog)\"\n [103] \"Low-grade glioma\" \n [104] \"Post-transplant lymphoproliferative disorder\" \n [105] \"Primary mediastinal B-cell lymphoma\" \n [106] \"Ewing sarcoma\" \n [107] \"RAS Colorectal cancer\" \n [108] \"Urothelial carcinoma\" \n [109] \"NK- and T-cell lymphoma\" \n [110] \"Hairy cell leukemia\" \n [111] \"Gallbladder cancer\" \n [112] \"Hodgkin lymphoma nodular lymphocyte-predominant\" \n [113] \"Classical Hodgkin lymphoma pediatric\" \n [114] \"Nasopharyngeal carcinoma\" \n [115] \"Esophageal squamous cell carcinoma\" \n [116] \"Wilms tumor\" \n [117] \"Esophageal cancer\" \n [118] \"Sarcomatoid renal cell carcinoma\" \n [119] \"Anaplastic large cell lymphoma pediatric\" \n [120] \"Carcinoma of unknown primary\" \n [121] \"Hepatoblastoma\" \n [122] \"Bladder cancer\" \n [123] \"Vulvar cancer\" \n [124] \"Paroxysmal nocturnal hemoglobinuria\" \n [125] \"Mismatch repair deficient malignancy\" \n [126] \"PEComa\" \n [127] \"High-grade B-cell lymphoma\" \n [128] \"Blastic plasmacytoid dendritic cell neoplasm\" \n [129] \"Cervical cancer\" \n [130] \"Medulloblastoma\" \n [131] \"Osteosarcoma pediatric\" \n [132] \"Pheochromocytoma\" \n [133] \"RET Non-small cell lung cancer\" \n [134] \"Low-grade glioma pediatric\" \n [135] \"Malignant pleural mesothelioma\" \n [136] \"Leiomyosarcoma\" \n [137] \"Colon cancer\" \n [138] \"Hypereosinophilic syndrome\" \n [139] \"Malignant solid neoplasm ERBB2-mutated\" \n [140] \"KMT2A Acute lymphoblastic leukemia infant\" \n [141] \"PIK3CA Breast cancer\" \n [142] \"Essential thrombocythemia\" \n [143] \"Merkel cell carcinoma\" \n [144] \"T-cell acute lymphoblastic leukemia\" \n [145] \"Rosai-Dorfman-Destombes disease\" \n \"\"\" \n\n"
}
},
diff --git a/flows/clinicaltrialsomop.json b/flows/clinicaltrialsomop.json
index 9f2c99e..eccba5f 100644
--- a/flows/clinicaltrialsomop.json
+++ b/flows/clinicaltrialsomop.json
@@ -181,7 +181,7 @@
"id": "8e707161-6558-4df6-8249-8fdaa6eeae85",
"data": {
"name": "GetFiles",
- "description": "Describe the task of node python_node_0",
+ "description": "Discover clinical trial source files in the configured input folder.",
"python_code": "from pathlib import Path\n\ndef exec(myinput):\n csv_folder = Path(source_csv_folder)\n\n # Get only CSV files in the folder\n csv_files = list(csv_folder.glob(\"*.csv\"))\n \n absolute_paths = [csv_file.absolute() for csv_file in sorted(csv_files)]\n\n return absolute_paths"
},
"type": "python_node",
@@ -199,7 +199,7 @@
"id": "326f88c3-e78c-4d7b-81f7-baba15068f73",
"data": {
"name": "Staging_SDTM",
- "description": "Describe the task of node python_node_1",
+ "description": "Load and stage the source clinical trial files as SDTM data frames.",
"python_code": "def exec(myinput):\n file_list = myinput[\"GetFiles\"].result\n\n processed = {}\n\n for file in file_list:\n domain = file.stem.lower()\n\n # Process based on domain\n if domain in [\"dm\", \"ds\", \"sv\", \"cm\"]:\n\n source_df = pd.read_csv(file)\n\n # Convert columns to lowercase for consistent handling\n\n source_df.columns = [col.lower() for col in source_df.columns]\n\n # Special case handling\n match domain:\n case \"cm\": # Concomitant Medications\n convert_col_to_integer('visitnum', source_df)\n convert_col_to_integer('cmstdy', source_df)\n convert_col_to_integer('cmendy', source_df)\n\n source_df['cm_concat'] = source_df['cmtrt'].astype(str) + '|' + source_df['cmdose'].astype(str) + '|' + source_df['cmdosu'].astype(str) + '|' + source_df['cmroute'].astype(str)\n \n case \"ds\": # Disposition\n convert_col_to_integer('visitnum', source_df)\n convert_col_to_integer('dsstdy', source_df)\n # Todo: Uncomment\n # convert_col_to_integer('livedy', source_df)\n # convert_col_to_integer('totcldur', source_df)\n\n\n case \"sv\":\n convert_col_to_integer('svstdy', source_df)\n convert_col_to_integer('svendy', source_df)\n\n processed[domain] = source_df\n\n return processed\n\ndef convert_col_to_integer(col, df):\n df[col] = df[col].apply(lambda x: None if pd.isna(x) else int(x))\n\n\n\n "
},
"type": "python_node",
@@ -217,7 +217,7 @@
"id": "ccc9781e-66c7-4fb3-b210-94db69b2a5d9",
"data": {
"name": "DownloadSTCMSeedCSVs",
- "description": "Describe the task of node python_node_2",
+ "description": "Download the source-to-concept mapping seed files used by the clinical trial transformations.",
"python_code": "def exec(myinput):\n\n base_url = \"https://raw.githubusercontent.com/OHDSI/ClinicalTrialsWG-TB/refs/heads/main/seeds/stcm/\"\n\n seed_data = {}\n for name in [\"drug_route\", \"source_to_concept_map\"]:\n csv_url = base_url + name + \".csv\"\n df = pd.read_csv(csv_url)\n df.columns = [col.lower() for col in df.columns]\n seed_data[name] = df\n\n return seed_data"
},
"type": "python_node",
@@ -273,7 +273,7 @@
"data": {
"sql": "WITH sites AS (\n SELECT DISTINCT\n siteid\n , country\n FROM DemographicsData\n)\n\nSELECT\n ROW_NUMBER() OVER (ORDER BY sites.siteid) AS care_site_id\n , loc.location_id\n , sites.siteid AS care_site_source_value\nFROM sites\nLEFT JOIN CreateLocationRecords AS loc\n ON sites.country = loc.location_source_value\n",
"name": "CreateCareSiteRecords",
- "description": "Describe the task of node sql_node_1"
+ "description": "Transform staged study site data into OMOP care_site records."
},
"type": "sql_node",
"width": 350,
@@ -291,7 +291,7 @@
"data": {
"sql": "SELECT\n ROW_NUMBER() OVER (ORDER BY dm.usubjid) AS person_id\n , CASE\n WHEN dm.sex = 'M' THEN 8507\n WHEN dm.sex = 'F' THEN 8532\n ELSE 0\n END AS gender_concept_id\n , 2014 - dm.age::int AS year_of_birth\n , CASE\n WHEN dm.race = 'BLACK OR AFRICAN AMERICAN' THEN 8516\n WHEN dm.race = 'WHITE' THEN 8527\n WHEN dm.race = 'NATIVE HAWAIIAN OR OTHER PACIFIC ISLANDER' THEN 8557\n ELSE 0\n END AS race_concept_id\n , CASE\n WHEN dm.ethnic = 'NOT HISPANIC OR LATINO' THEN 38003564\n ELSE 0\n END AS ethnicity_concept_id\n , loc.location_id\n , cs.care_site_id\n , dm.usubjid AS person_source_value\n , dm.sex AS gender_source_value\n , dm.race AS race_source_value\n , dm.ethnic AS ethnicity_source_value\nFROM DemographicsData AS dm\nLEFT JOIN CreateLocationRecords AS loc\n ON dm.country = loc.location_source_value\nLEFT JOIN CreateCareSiteRecords AS cs\n ON dm.siteid = cs.care_site_source_value\nWHERE\n dm.usubjid IS NOT NULL\n AND dm.age IS NOT NULL",
"name": "CreatePersonRecords",
- "description": "Describe the task of node sql_node_2"
+ "description": "Transform staged subject demographics into OMOP person records."
},
"type": "sql_node",
"width": 350,
@@ -309,7 +309,7 @@
"data": {
"sql": "SELECT\n ROW_NUMBER() OVER (ORDER BY per.person_id, sv.visitnum) AS visit_occurrence_id\n , per.person_id\n , 581477 AS visit_concept_id -- 'Office visit'\n , DATE '2014-10-23' + sv.svstdy * INTERVAL 1 DAY AS visit_start_date\n , DATE '2014-10-23' + sv.svendy * INTERVAL 1 DAY AS visit_end_date\n , 32809 AS visit_type_concept_id -- 'Case Report Form'\n , sv.visitnum AS visit_source_value\nFROM SubjectVisitsData AS sv\nLEFT JOIN CreatePersonRecords AS per\n ON sv.usubjid = per.person_source_value\nWHERE\n sv.svstdy IS NOT NULL\n AND sv.svendy IS NOT NULL\n",
"name": "CreateVisitOccurrenceRecords",
- "description": "Describe the task of node sql_node_3"
+ "description": "Transform staged subject visits into OMOP visit_occurrence records."
},
"type": "sql_node",
"width": 350,
@@ -328,7 +328,7 @@
"map": {},
"name": "SubjectVisitsData",
"uiMap": { "path": "$.sv", "source": "Staging_SDTM" },
- "description": "Describe the task of node py2table_node_1"
+ "description": "Convert staged subject visit data into a table for OMOP transformation."
},
"type": "py2table_node",
"width": 350,
@@ -347,7 +347,7 @@
"map": {},
"name": "ConcomitantMedicationsData",
"uiMap": { "path": "$.cm", "source": "Staging_SDTM" },
- "description": "Describe the task of node py2table_node_2"
+ "description": "Convert staged concomitant medication data into a table for OMOP transformation."
},
"type": "py2table_node",
"width": 350,
@@ -365,7 +365,7 @@
"data": {
"sql": "SELECT\n ROW_NUMBER() OVER (ORDER BY per.person_id, cm.cmstdy) AS drug_exposure_id\n , per.person_id\n , DATE '2014-10-23' + cm.cmstdy * INTERVAL 1 DAY AS drug_exposure_start_date\n , CASE\n WHEN cm.cmendy IS NOT NULL THEN DATE '2014-10-23' + cm.cmendy * INTERVAL 1 DAY\n -- TODO add proper THEMIS imputation rules\n ELSE DATE '2014-10-23' + cm.cmstdy * INTERVAL 1 DAY\n END AS drug_exposure_end_date\n , cm.cm_concat AS drug_source_value\n , stcm.target_concept_id AS drug_concept_id\n , 32809 AS drug_type_concept_id -- 'Case Report Form'\n , cm.cmendy - cm.cmstdy + 1 AS days_supply\n , dr.concept_id AS route_concept_id\n , cm.cmroute AS route_source_value\n , vo.visit_occurrence_id\nFROM ConcomitantMedicationsData AS cm\nLEFT JOIN CreatePersonRecords AS per\n ON cm.usubjid = per.person_source_value\nLEFT JOIN CreateVisitOccurrenceRecords AS vo\n ON\n cm.visitnum = vo.visit_source_value\n AND per.person_id = vo.person_id\nLEFT JOIN SourceToConceptMapData AS stcm\n ON\n cm.cm_concat = stcm.source_code\n AND stcm.source_vocabulary_id = 'TB1015_CM'\nLEFT JOIN DrugRouteData AS dr\n ON UPPER(TRIM(cm.cmroute)) = dr.route",
"name": "CreateDrugExposureRecords",
- "description": "Describe the task of node sql_node_4"
+ "description": "Transform concomitant medication data into OMOP drug_exposure records."
},
"type": "sql_node",
"width": 350,
@@ -387,7 +387,7 @@
"path": "$.source_to_concept_map",
"source": "DownloadSTCMSeedCSVs"
},
- "description": "Describe the task of node py2table_node_3"
+ "description": "Convert source-to-concept mappings into a table for terminology lookup."
},
"type": "py2table_node",
"width": 350,
@@ -406,7 +406,7 @@
"map": {},
"name": "DrugRouteData",
"uiMap": { "path": "$.drug_route", "source": "DownloadSTCMSeedCSVs" },
- "description": "Describe the task of node py2table_node_4"
+ "description": "Convert drug route mappings into a table for drug exposure transformation."
},
"type": "py2table_node",
"width": 350,
@@ -423,11 +423,11 @@
"id": "692fd894-bf41-4cdc-8472-8d6175f562f8",
"data": {
"name": "IngestLocationTable",
- "database": "demo_database",
+ "database": "target_db",
"dataframe": "CreateLocationRecords",
- "schemaname": "clinicaltrialsomop",
+ "schemaname": "target_schema",
"dbtablename": "location",
- "description": "IngestLocationRecords"
+ "description": "Write transformed location records to the configured OMOP database and schema."
},
"type": "db_writer_node",
"width": 350,
@@ -444,11 +444,11 @@
"id": "d6f01d61-e8a3-44d2-8932-04445d41cf1e",
"data": {
"name": "IngestPersonTable",
- "database": "demo_database",
+ "database": "target_db",
"dataframe": "CreatePersonRecords",
- "schemaname": "clinicaltrialsomop",
+ "schemaname": "target_schema",
"dbtablename": "person",
- "description": "Describe the task of node db_writer_node_1"
+ "description": "Write transformed Person records to the configured OMOP database and schema."
},
"type": "db_writer_node",
"width": 350,
@@ -465,11 +465,11 @@
"id": "c0b9e1a5-b0b6-4e86-95cd-b561e39477ee",
"data": {
"name": "IngestCareSiteTable",
- "database": "demo_database",
+ "database": "target_db",
"dataframe": "CreateCareSiteRecords",
- "schemaname": "clinicaltrialsomop",
+ "schemaname": "target_schema",
"dbtablename": "care_site",
- "description": "Describe the task of node db_writer_node_2"
+ "description": "Write transformed Care Site records to the configured OMOP database and schema."
},
"type": "db_writer_node",
"width": 350,
@@ -486,11 +486,11 @@
"id": "9fa52bdd-3b3d-4ce4-911b-7f4bfbcfe44f",
"data": {
"name": "IngestVisitOccurrenceTable",
- "database": "demo_database",
+ "database": "target_db",
"dataframe": "CreateVisitOccurrenceRecords",
- "schemaname": "clinicaltrialsomop",
+ "schemaname": "target_schema",
"dbtablename": "visit_occurrence",
- "description": "Describe the task of node db_writer_node_3"
+ "description": "Write transformed Visit Occurrence records to the configured OMOP database and schema."
},
"type": "db_writer_node",
"width": 350,
@@ -507,11 +507,11 @@
"id": "c18e0a68-cb27-4ea8-ae8c-9bf9118230be",
"data": {
"name": "IngestDrugExposureTable",
- "database": "demo_database",
+ "database": "target_db",
"dataframe": "CreateDrugExposureRecords",
- "schemaname": "clinicaltrialsomop",
+ "schemaname": "target_schema",
"dbtablename": "drug_exposure",
- "description": "Describe the task of node db_writer_node_4"
+ "description": "Write transformed Drug Exposure records to the configured OMOP database and schema."
},
"type": "db_writer_node",
"width": 350,
@@ -528,5 +528,11 @@
"variables": [
{ "key": "source_csv_folder", "value": "/app/clinicaltrialstb" }
],
- "importLibs": ["import pandas as pd"]
+ "importLibs": ["import pandas as pd"],
+ "databases": [
+ { "code": "demo_database", "name": "target_db" }
+ ],
+ "schemas": [
+ { "name": "target_schema", "schema": "clinicaltrialsomop" }
+ ]
}
diff --git a/flows/etlPatientToOMOPPerson.json b/flows/etlPatientToOMOPPerson.json
index 329f130..f2a1969 100644
--- a/flows/etlPatientToOMOPPerson.json
+++ b/flows/etlPatientToOMOPPerson.json
@@ -18,7 +18,7 @@
"testdata": [
[]
],
- "description": "Describe the task of node db_reader_node_0"
+ "description": "Read FHIR Patient resources from the configured FHIR database."
},
"type": "db_reader_node",
"width": 354,
@@ -44,7 +44,7 @@
"name": "transform_to_person",
"error": false,
"dataframe": "get_fhir_patients",
- "description": "Describe the task of node transform_fhir_data_node_0",
+ "description": "Transform source FHIR data into OMOP person records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"PersonMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \"
\\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/PersonMap'\\r\\n/// name = 'PersonMap'\\r\\n/// title = 'Mapping Patient resource to Person OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Patient" alias Patient as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/Person" alias PersonTable as target\\r\\n\\r\\ngroup Person(source src : Patient, target tgt : PersonTable) {\\r\\n src.gender as gender -> tgt.gender_concept_id = gender, tgt.gender_source_value = cast(gender, 'string'); // src.id as id -> tgt.person_id = cast(id, "integer");\\r\\n src.birthDate as bdSrc -> tgt.birth_datetime = bdSrc, tgt.year_of_birth = (src.birthDate.toString().substring(0, 4)), tgt.month_of_birth = (src.birthDate.toString().substring(5, 2)), tgt.day_of_birth = (src.birthDate.toString().substring(8, 2));\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/PersonMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"PersonMap\",\n \"title\": \"Mapping Patient resource to Person OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Patient instances to OMOP Person Table objects.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Patient\",\n \"mode\": \"source\",\n \"alias\": \"Patient\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/Person\",\n \"mode\": \"target\",\n \"alias\": \"PersonTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"Person\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Patient\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"PersonTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"person_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"patientId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientId\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"person_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"gender\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"gender\",\n \"variable\": \"gender\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"gender_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"gender\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"setMaleConceptId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"gender\",\n \"variable\": \"g\",\n \"condition\": \"gender = 'male' or gender = 'M'\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"gender_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueInteger\": 8507\n }\n ]\n }\n ]\n },\n {\n \"name\": \"setFemaleConceptId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"gender\",\n \"variable\": \"g\",\n \"condition\": \"gender = 'female' or gender = 'F'\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"gender_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueInteger\": 8532\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"Map FHIR gender to OMOP gender_concept_id: male/M -> 8507, female/F -> 8532\"\n },\n {\n \"name\": \"birthDate\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"birthDate\",\n \"variable\": \"bdSrc\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"birth_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"bdSrc\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"year_of_birth\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"birthDate.substring(0,4)\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"month_of_birth\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"birthDate.substring(5,2)\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"day_of_birth\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"birthDate.substring(8,2)\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"raceConcept\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race').extension.valueCoding.display\",\n \"variable\": \"race\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"race_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"8527\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"ethnicity_concept_id\",\n \"documentation\": \"Map FHIR US Core ethnicity extension to OMOP person.ethnicity_concept_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.where(url = 'ombCategory').valueCoding.code\",\n \"variable\": \"ethnicityCode\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"ethnicity_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"8527\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -70,7 +70,7 @@
"id": "e696b11f-1d31-42ec-a3f2-370d3f958707",
"data": {
"name": "prepare_personIds",
- "description": "Describe the task of node python_node_0",
+ "description": "Assign stable OMOP person identifiers while preserving mappings for previously processed FHIR patients.",
"python_code": "# Input: transform_to_person (dataframe) - transformed OMOP person rows from the mapping node\n# Output: result (dataframe) - person rows with stable/reused `person_id` values\n\n\ndef _normalize_fhir_id(value):\n if value is None:\n return None\n s = str(value).strip()\n return s.split(\"/\")[-1] if \"/\" in s else s\n\n\nDEFAULTS = {\n \"gender_concept_id\": 0,\n \"year_of_birth\": 0,\n \"race_concept_id\": 0,\n \"ethnicity_concept_id\": 0,\n}\n\n\ndef _assign_person_ids(source_values, existing, max_id):\n next_id = max(max_id, max(existing.values(), default=0)) + 1\n assigned = {}\n assigned_ids = []\n\n for source_val in source_values:\n if source_val in existing:\n person_id = existing[source_val]\n elif source_val in assigned:\n person_id = assigned[source_val]\n else:\n person_id = next_id\n assigned[source_val] = person_id\n next_id += 1\n assigned_ids.append(person_id)\n\n return assigned_ids\n\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_person\").result\n database_code = dest_db\n schema_name = dest_schema\n\n if df is None or df.empty:\n return df\n\n if not database_code or not schema_name:\n raise ValueError(\"`database_code` and `schema_name` must be provided\")\n\n for col, default in DEFAULTS.items():\n if col not in df.columns:\n df[col] = default\n else:\n df[col] = df[col].fillna(default)\n\n dao = SqlAlchemyDao(database_code=database_code)\n mapping_dao = DBDao(dialect=SupportedDatabaseDialects.TREX, database_code=database_code)\n mapping_schema = f\"{database_code}_{schema_name}_fhir_mapping\"\n\n df[\"person_source_value\"] = df[\"person_source_value\"].apply(_normalize_fhir_id)\n df = df.dropna(subset=[\"person_source_value\"])\n if df.empty:\n return df\n\n fhir_ids = df[\"person_source_value\"].unique().tolist()\n\n # 1. Look up existing person_ids from data_source before deleting\n escaped_schema = mapping_schema.replace('\"', '\"\"')\n try:\n rows = mapping_dao.execute_sql(\n f\"\"\"\n SELECT DISTINCT ON (fhir_resource_id) fhir_resource_id, omop_id\n FROM \"{escaped_schema}\".\"data_source\"\n WHERE omop_table_name = 'person'\n AND omop_id IS NOT NULL\n ORDER BY fhir_resource_id, transformed_at DESC\n \"\"\",\n fetch=True,\n ) or []\n existing = {row[0]: int(row[1]) for row in rows if row[1] is not None}\n except Exception:\n existing = {}\n\n # 2. Delete existing person rows for these FHIR IDs\n omop_meta = sql.MetaData(schema=schema_name)\n person_table = sql.Table(\"person\", omop_meta, autoload_with=dao.engine)\n\n deleted = dao.execute_sqlalchemy_statement(\n person_table.delete().where(\n person_table.c.person_source_value.in_(fhir_ids)\n ),\n lambda r: r.rowcount,\n )\n print(f\"Deleted {deleted} rows from {schema_name}.person\")\n\n # 3. Get max_id from what remains in the table (after deletion)\n max_id = dao.execute_sqlalchemy_statement(\n sql.select(sql.func.coalesce(sql.func.max(person_table.c.person_id), 0)),\n lambda r: r.scalar(),\n )\n\n # 4. Assign person_ids — reuse existing, mint new for new records\n df = df.copy()\n assigned_ids = _assign_person_ids(df[\"person_source_value\"], existing, max_id)\n df[\"person_id\"] = assigned_ids\n reused = sum(1 for i in assigned_ids if i in existing.values())\n print(f\"Assigned person_ids: {reused} reused, {len(assigned_ids) - reused} new\")\n return df\n"
},
"type": "python_node",
@@ -99,7 +99,7 @@
"dataframe": "py2table_node",
"schemaname": "dest_schema",
"dbtablename": "person",
- "description": "Describe the task of node db_writer_node_0"
+ "description": "Write transformed person records to the configured OMOP CDM schema."
},
"type": "db_writer_node",
"width": 350,
@@ -128,7 +128,7 @@
"path": "$",
"source": "prepare_personIds"
},
- "description": "Describe the task of node py2table_node_1",
+ "description": "Convert prepared person records into a DataFrame for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -152,7 +152,7 @@
"id": "d8fa508e-1860-4c2b-85b9-1061c576534f",
"data": {
"name": "fhir_mapping_node",
- "description": "Describe the task of node fhir_mapping_node_1",
+ "description": "Record mappings between source FHIR patient identifiers and OMOP person identifiers.",
"schema_name": "dest_schema",
"database_code": "dest_db",
"write_key_map": true,
@@ -241,4 +241,4 @@
"schema": "demo_cdm"
}
]
-}
\ No newline at end of file
+}
diff --git a/flows/etlQuestionnaireResponseEQ-5D-5L.json b/flows/etlQuestionnaireResponseEQ-5D-5L.json
index 1034af3..c5a6de8 100644
--- a/flows/etlQuestionnaireResponseEQ-5D-5L.json
+++ b/flows/etlQuestionnaireResponseEQ-5D-5L.json
@@ -107,7 +107,7 @@
"path": "$",
"source": "prepare_measurement_ids"
},
- "description": "Describe the task of node py2table_node_0",
+ "description": "Convert the preceding transformation output into a DataFrame for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -184,7 +184,7 @@
"data": {
"name": "fhir_mapping_node_0",
"error": false,
- "description": "Describe the task of node fhir_mapping_node_0",
+ "description": "Record mappings between source FHIR identifiers and the generated OMOP records.",
"schema_name": "dest_schema",
"errorMessage": null,
"database_code": "dest_db",
diff --git a/flows/etlfhirtoomop.json b/flows/etlfhirtoomop.json
index cdf02ea..f9714b7 100644
--- a/flows/etlfhirtoomop.json
+++ b/flows/etlfhirtoomop.json
@@ -517,7 +517,7 @@
"data": {
"name": "python_node",
"error": false,
- "description": "Describe the task of node python_node_0",
+ "description": "Initialize the FHIR-to-OMOP transformation flow and shared runtime values.",
"python_code": "def exec(myinput):\n transformed = {}\n for key, result_obj in myinput.items():\n transformed[key] = result_obj.result\n return transformed\ndef test_exec(myinput):\n return \"This is test_exec function\"",
"errorMessage": null
},
@@ -548,7 +548,7 @@
"path": "$.AllergyIntolerance",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_0",
+ "description": "Convert Allergy Intolerance resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -578,7 +578,7 @@
"path": "$.Patient",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_1",
+ "description": "Convert Patient resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -608,7 +608,7 @@
"path": "$.Condition",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_2",
+ "description": "Convert Condition resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -638,7 +638,7 @@
"path": "$.Encounter",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_3",
+ "description": "Convert Encounter resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -668,7 +668,7 @@
"path": "$.Immunization",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_4",
+ "description": "Convert Immunization resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -698,7 +698,7 @@
"path": "$.Observation",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_5",
+ "description": "Convert Observation resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -728,7 +728,7 @@
"path": "$.MedicationStatement",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_6",
+ "description": "Convert Medication Statement resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -757,7 +757,7 @@
"path": "$.Observation",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_7"
+ "description": "Convert Observation resource data into a DataFrame for transformation."
},
"type": "py2table_node",
"width": 350,
@@ -786,7 +786,7 @@
"path": "$.Procedure",
"source": "python_node"
},
- "description": "Describe the task of node py2table_node_8",
+ "description": "Convert Procedure resource data into a DataFrame for transformation.",
"errorMessage": null
},
"type": "py2table_node",
@@ -813,7 +813,7 @@
"name": "transform_to_Observation",
"error": false,
"dataframe": "AllergyIntolerance_df",
- "description": "Describe the task of node transform_fhir_data_node_0",
+ "description": "Transform source FHIR data into OMOP Observation records.",
"errorMessage": null,
"structure_map": "{ \"resourceType\": \"StructureMap\", \"id\": \"AllergyMap\", \"text\": { \"status\": \"generated\", \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/AllergyMap'\\r\\n/// name = 'AllergyMap'\\r\\n/// title = 'Mapping Allergy resource to Observation OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/AllergyIntolerance" alias Allergy as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/Observation" alias ObservationTable as target\\r\\n\\r\\ngroup Observation(source src : Allergy, target tgt : ObservationTable) {\\r\\n src.code as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code -> tgt.observation_concept_id, tgt.observation_source_value, tgt.observation_source_concept_id;\\r\\n };\\r\\n }; // src.id as id -> tgt.observation_id = cast(id, "integer");\\r\\n src.onset : dateTime as osd -> tgt.observation_date = cast(osd, 'date'), tgt.observation_datetime = osd; // src.patient as s -> tgt then {\\r\\n src.reaction as s -> tgt then {\\r\\n s.manifestation as sman -> tgt then {\\r\\n sman.concept as smanc -> tgt then {\\r\\n smanc.coding as sc -> tgt then {\\r\\n sc.code -> tgt.value_as_concept_id, tgt.value_source_value;\\r\\n };\\r\\n };\\r\\n };\\r\\n };\\r\\n}\\r\\n\\r\\n \" }, \"extension\": [ { \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\", \"valueCode\": \"brr\" }, { \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\", \"valueInteger\": 1, \"_valueInteger\": { \"extension\": [ { \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\", \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\" } ] } }, { \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\", \"valueCode\": \"informative\", \"_valueCode\": { \"extension\": [ { \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\", \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\" } ] } } ], \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/AllergyMap\", \"version\": \"1.0.0-ballot\", \"name\": \"AllergyMap\", \"title\": \"Mapping Allergy resource to Observation OMOP Domain\", \"status\": \"draft\", \"date\": \"2025-07-29T17:40:15+00:00\", \"publisher\": \"HL7 International / Biomedical Research and Regulation\", \"contact\": [ { \"name\": \"HL7 International / Biomedical Research and Regulation\", \"telecom\": [ { \"system\": \"url\", \"value\": \"http://www.hl7.org/Special/committees/rcrim\" } ] } ], \"description\": \"This mapping maps FHIR AllergyIntolerance instances to OMOP Observation Table objects.\", \"jurisdiction\": [ { \"coding\": [ { \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\", \"code\": \"001\", \"display\": \"World\" } ] } ], \"structure\": [ { \"url\": \"http://hl7.org/fhir/StructureDefinition/AllergyIntolerance\", \"mode\": \"source\", \"alias\": \"Allergy\" }, { \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/Observation\", \"mode\": \"target\", \"alias\": \"ObservationTable\" } ], \"group\": [ { \"name\": \"Observation\", \"input\": [ { \"name\": \"src\", \"type\": \"Allergy\", \"mode\": \"source\" }, { \"name\": \"tgt\", \"type\": \"ObservationTable\", \"mode\": \"target\" } ], \"rule\": [ { \"name\": \"mapObservationId\", \"documentation\": \"Generate a unique OMOP observation_id.\", \"source\": [ { \"context\": \"src\", \"element\": \"id\", \"variable\": \"fhirId\" } ], \"target\": [ { \"context\": \"tgt\", \"element\": \"observation_id\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"fhirId\" } ] } ] }, { \"name\": \"mapPatientId\", \"source\": [ { \"context\": \"src\", \"element\": \"patient.reference\", \"variable\": \"patRef\" } ], \"target\": [ { \"context\": \"tgt\", \"element\": \"person_id\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"patRef\" } ] } ] }, { \"name\": \"code\", \"source\": [ { \"context\": \"src\", \"element\": \"code\", \"variable\": \"s\" } ], \"target\": [ { \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"tgt\" } ] } ], \"rule\": [ { \"name\": \"coding\", \"source\": [ { \"context\": \"s\", \"element\": \"coding\", \"variable\": \"sc\" } ], \"target\": [ { \"transform\": \"copy\", \"context\": \"tgt\", \"parameter\": [ { \"valueId\": \"sc\" } ] } ], \"rule\": [ { \"name\": \"code\", \"source\": [ { \"context\": \"sc\", \"element\": \"code\", \"variable\": \"sc_code\" } ], \"target\": [ { \"context\": \"tgt\", \"element\": \"observation_concept_id\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"sc_code\" } ] }, { \"context\": \"tgt\", \"element\": \"observation_source_value\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"sc_code\" } ] }, { \"context\": \"tgt\", \"element\": \"observation_source_concept_id\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"sc_code\" } ] } ] } ] } ], \"documentation\": \"src.id as id -> tgt.observation_id = cast(id, \\\"integer\\\");\" }, { \"name\": \"onsetDateTime\", \"source\": [ { \"context\": \"src\", \"type\": \"dateTime\", \"element\": \"onset\", \"variable\": \"osd\" } ], \"target\": [ { \"context\": \"tgt\", \"element\": \"observation_date\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"osd\" }, { \"valueString\": \"date\" } ] }, { \"context\": \"tgt\", \"element\": \"observation_datetime\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"osd\" } ] } ], \"documentation\": \"src.patient as s -> tgt then {\" }, { \"name\": \"mapObservationTypeConceptId\", \"documentation\": \"Derive OMOP observation_type_concept_id based on FHIR AllergyIntolerance provenance.\", \"source\": [ { \"context\": \"src\", \"element\": \"id\", \"variable\": \"conceptId\" } ], \"target\": [ { \"context\": \"tgt\", \"element\": \"observation_type_concept_id\", \"transform\": \"copy\", \"parameter\": [ { \"valueId\": \"conceptId\" } ] } ] } ] } ] }",
"output_omop_data": ""
@@ -842,7 +842,7 @@
"name": "transform_to_procedure_occurrence",
"error": false,
"dataframe": "Procedure_df",
- "description": "Describe the task of node transform_fhir_data_node_1",
+ "description": "Transform source FHIR data into OMOP procedure occurrence records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"ProcedureMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/ProcedureMap'\\r\\n/// name = 'ProcedureMap'\\r\\n/// title = 'Mapping Procedure resource to Procedure Occurrence OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Procedure" alias Procedure as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/ProcedureOccurrence" alias ProcedureTable as target\\r\\n\\r\\ngroup ProcedureOccurrence(source src : Procedure, target tgt : ProcedureTable) {\\r\\n src.code as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.procedure_concept_id, tgt.procedure_source_value, tgt.procedure_source_concept_id = a;\\r\\n };\\r\\n }; // src.id as id -> tgt.procedure_occurrence_id = cast(id, "integer");\\r\\n src.occurrence : dateTime as edt -> tgt.procedure_datetime = cast(edt, 'dateTime'), tgt.procedure_date = edt;\\r\\n src.occurrence : Period as s -> tgt then {\\r\\n s.start as start -> tgt.procedure_datetime = cast(start, 'dateTime'), tgt.procedure_date = start;\\r\\n s.end as end -> tgt.procedure_end_datetime, tgt.procedure_end_date = end;\\r\\n };\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/ProcedureMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"ProcedureMap\",\n \"title\": \"Mapping Procedure resource to Procedure Occurrence OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Procedure instances to OMOP Procedure Occurrence Table objects.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Procedure\",\n \"mode\": \"source\",\n \"alias\": \"Procedure\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/ProcedureOccurrence\",\n \"mode\": \"target\",\n \"alias\": \"ProcedureTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"ProcedureOccurrence\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Procedure\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"ProcedureTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"pid\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_occurrence_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"pid\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"procedure_type_concept_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"procedure_type_concept_id\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_type_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueInteger\": 45905771\n }\n ]\n }\n ]\n },\n {\n \"name\": \"mapPatientId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"subject.reference\",\n \"variable\": \"patientRefId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientRefId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"code\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_source_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.id as id -> tgt.procedure_occurrence_id = cast(id, \\\"integer\\\");\"\n },\n {\n \"name\": \"occurrenceDateTime\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"dateTime\",\n \"element\": \"performedDateTime\",\n \"variable\": \"edt\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"edt\"\n },\n {\n \"valueString\": \"dateTime\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"edt\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"occurrencePeriod\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"Period\",\n \"element\": \"performedPeriod\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"start\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"start\",\n \"variable\": \"start\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"start\"\n },\n {\n \"valueString\": \"dateTime\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"start\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"end\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"end\",\n \"variable\": \"end\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_end_datetime\"\n },\n {\n \"context\": \"tgt\",\n \"element\": \"procedure_end_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"end\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -871,7 +871,7 @@
"name": "transform_to_observation",
"error": false,
"dataframe": "Observation_df",
- "description": "Describe the task of node transform_fhir_data_node_2",
+ "description": "Transform source FHIR data into OMOP observation records.",
"errorMessage": null,
"structure_map": "{\"resourceType\":\"StructureMap\",\"id\":\"ObservationMap\",\"text\":{\"status\":\"generated\",\"div\":\" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/ObservationMap'\\r\\n/// name = 'ObservationMap'\\r\\n/// title = 'Mapping Observation resource to Observation OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Observation" alias Observation as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/Observation" alias ObsTable as target\\r\\n\\r\\ngroup Observe(source src : Observation, target tgt : ObsTable) {\\r\\n src where ('social-history' | 'imaging' | 'survey' | 'exam' | 'therapy' | 'activity' | 'procedure').supersetOf(Observation.category.coding.code) then {\\r\\n src.code as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.observation_concept_id = a;\\r\\n };\\r\\n }; // src.id as id -> tgt.observation_id = cast(id, "integer");\\r\\n src.effective : dateTime as a -> tgt.observation_datetime = a, tgt.observation_date = cast(a, 'date'); // src.subject as s -> tgt then {\\r\\n src.effective : instant as einst -> tgt.observation_datetime = cast(einst, 'dateTime'), tgt.observation_date = cast(einst, 'date');\\r\\n src.effective : Period as s -> tgt then {\\r\\n s.start as ss -> tgt.observation_datetime = cast(ss, 'dateTime'), tgt.observation_date = cast(ss, 'date');\\r\\n };\\r\\n src.issued as s where (s.toDate != src.effectiveDate) -> tgt.observation_source_value = cast(s, 'string');\\r\\n src.value : Quantity as s -> tgt then {\\r\\n s.value as a -> tgt.value_as_number = a;\\r\\n s.unit as b -> tgt.unit_concept_id = b;\\r\\n }; // src.performer as s -> tgt then {\\r\\n src.value : CodeableConcept as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.value_as_concept_id = a;\\r\\n };\\r\\n };\\r\\n src.value : string as b -> tgt.value_as_string = b;\\r\\n src.note as d -> tgt.observation_source_value = d;\\r\\n } "OnlyObs";\\r\\n}\\r\\n\\r\\n \"},\"extension\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\"valueCode\":\"brr\"},{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\"valueInteger\":1,\"_valueInteger\":{\"extension\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\"valueCanonical\":\"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"}]}},{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\"valueCode\":\"informative\",\"_valueCode\":{\"extension\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\"valueCanonical\":\"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"}]}}],\"url\":\"http://hl7.org/fhir/uv/omop/StructureMap/ObservationMap\",\"version\":\"1.0.0-ballot\",\"name\":\"ObservationMap\",\"title\":\"Mapping Observation resource to Observation OMOP Domain\",\"status\":\"draft\",\"date\":\"2025-07-29T17:40:15+00:00\",\"publisher\":\"HL7 International / Biomedical Research and Regulation\",\"contact\":[{\"name\":\"HL7 International / Biomedical Research and Regulation\",\"telecom\":[{\"system\":\"url\",\"value\":\"http://www.hl7.org/Special/committees/rcrim\"}]}],\"description\":\"This mapping maps FHIR Observation instances that are NOT considered measurements to OMOP Observation Table objects. Currently, this is done by considering the category code and mapping 'social-history', 'imaging', 'survey', 'exam', 'therapy', 'activity', and 'procedure' Observations.\",\"jurisdiction\":[{\"coding\":[{\"system\":\"http://unstats.un.org/unsd/methods/m49/m49.htm\",\"code\":\"001\",\"display\":\"World\"}]}],\"structure\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/Observation\",\"mode\":\"source\",\"alias\":\"Observation\"},{\"url\":\"http://hl7.org/fhir/uv/omop/StructureDefinition/Observation\",\"mode\":\"target\",\"alias\":\"ObsTable\"}],\"group\":[{\"name\":\"Observe\",\"input\":[{\"name\":\"src\",\"type\":\"Observation\",\"mode\":\"source\"},{\"name\":\"tgt\",\"type\":\"ObsTable\",\"mode\":\"target\"}],\"rule\":[{\"name\":\"mapObservationId\",\"documentation\":\"Generate a unique OMOP observation_id.\",\"source\":[{\"context\":\"src\",\"element\":\"id\",\"variable\":\"fhirId\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"fhirId\"}]}]},{\"name\":\"mapPatientId\",\"source\":[{\"context\":\"src\",\"element\":\"subject.reference\",\"variable\":\"patRef\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"person_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"patRef\"}]}]},{\"name\":\"mapObservationTypeConceptId\",\"documentation\":\"Derive OMOP observation_type_concept_id based on FHIR AllergyIntolerance provenance.\",\"source\":[{\"context\":\"src\",\"element\":\"id\",\"variable\":\"id\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_type_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"id\"}]}]},{\"name\":\"OnlyObs\",\"source\":[{\"context\":\"src\",\"condition\":\"('social-history' | 'imaging' | 'survey' | 'exam' | 'therapy' | 'activity' | 'procedure').supersetOf(Observation.category.coding.code)\"}],\"rule\":[{\"name\":\"code\",\"source\":[{\"context\":\"src\",\"element\":\"code\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"coding\",\"source\":[{\"context\":\"s\",\"element\":\"coding\",\"variable\":\"sc\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"code\",\"source\":[{\"context\":\"sc\",\"element\":\"code\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]}]}]}],\"documentation\":\"src.id as id -> tgt.observation_id = cast(id, \\\"integer\\\");\"},{\"name\":\"effectiveDateTime\",\"source\":[{\"context\":\"src\",\"type\":\"dateTime\",\"element\":\"effective\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_datetime\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]},{\"context\":\"tgt\",\"element\":\"observation_date\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"},{\"valueString\":\"date\"}]}],\"documentation\":\"src.subject as s -> tgt then {\"},{\"name\":\"effectiveInstant\",\"source\":[{\"context\":\"src\",\"type\":\"instant\",\"element\":\"effective\",\"variable\":\"einst\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_datetime\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"einst\"},{\"valueString\":\"dateTime\"}]},{\"context\":\"tgt\",\"element\":\"observation_date\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"einst\"},{\"valueString\":\"date\"}]}]},{\"name\":\"effectivePeriod\",\"source\":[{\"context\":\"src\",\"type\":\"Period\",\"element\":\"effective\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"start\",\"source\":[{\"context\":\"s\",\"element\":\"start\",\"variable\":\"ss\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_datetime\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"ss\"},{\"valueString\":\"dateTime\"}]},{\"context\":\"tgt\",\"element\":\"observation_date\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"ss\"},{\"valueString\":\"date\"}]}]}]},{\"name\":\"issued\",\"source\":[{\"context\":\"src\",\"element\":\"issued\",\"variable\":\"s\",\"condition\":\"(s.toDate != src.effectiveDate)\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_source_value\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"s\"},{\"valueString\":\"string\"}]}]},{\"name\":\"valueQuantity\",\"source\":[{\"context\":\"src\",\"type\":\"Quantity\",\"element\":\"value\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"value\",\"source\":[{\"context\":\"s\",\"element\":\"value\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"value_as_number\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]}]},{\"name\":\"unit\",\"source\":[{\"context\":\"s\",\"element\":\"unit\",\"variable\":\"b\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"unit_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"b\"}]}]}],\"documentation\":\"src.performer as s -> tgt then {\"},{\"name\":\"valueCodeableConcept\",\"source\":[{\"context\":\"src\",\"type\":\"CodeableConcept\",\"element\":\"value\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"coding\",\"source\":[{\"context\":\"s\",\"element\":\"coding\",\"variable\":\"sc\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"code\",\"source\":[{\"context\":\"sc\",\"element\":\"code\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"value_as_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]}]}]}]},{\"name\":\"valueString\",\"source\":[{\"context\":\"src\",\"type\":\"string\",\"element\":\"value\",\"variable\":\"b\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"value_as_string\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"b\"}]}]},{\"name\":\"note\",\"source\":[{\"context\":\"src\",\"element\":\"note\",\"variable\":\"d\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_source_value\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"d\"}]}]},{\"name\":\"note\",\"source\":[{\"context\":\"src\",\"element\":\"note\",\"variable\":\"d\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"observation_source_value\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"d\"}]}]}]}]}]}",
"output_omop_data": ""
@@ -900,7 +900,7 @@
"name": "transform_to_drug_exposure",
"error": false,
"dataframe": "MedicationStatement_df",
- "description": "Describe the task of node transform_fhir_data_node_3",
+ "description": "Transform source FHIR data into OMOP drug exposure records.",
"errorMessage": null,
"structure_map": "{\"resourceType\":\"StructureMap\",\"id\":\"MedicationMap\",\"text\":{\"status\":\"generated\",\"div\":\" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/MedicationMap'\\r\\n/// name = 'MedicationMap'\\r\\n/// title = 'Mapping MedicationStatement resource to DrugExposure OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/MedicationStatement" alias MedState as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/DrugExposure" alias DrugExpTable as target\\r\\n\\r\\ngroup MedExposure(source src : MedState, target tgt : DrugExpTable) {\\r\\n src.medication : CodeableReference as s -> tgt then {\\r\\n s.concept as scs -> tgt then {\\r\\n scs.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.drug_concept_id = a;\\r\\n };\\r\\n };\\r\\n }; // src.id as id -> tgt.drug_exposure_id = cast(id, "integer");\\r\\n src.effective : dateTime as edt -> tgt.drug_exposure_start_datetime = edt, tgt.drug_exposure_start_date = cast(edt, 'date');\\r\\n src.effective : Period as s -> tgt then {\\r\\n s.start as fps -> tgt.drug_exposure_start_datetime = fps, tgt.drug_exposure_start_date = cast(fps, 'date');\\r\\n };\\r\\n src.effective : Period as s -> tgt then {\\r\\n s.end as fpe -> tgt.drug_exposure_end_datetime = fpe, tgt.drug_exposure_end_date = cast(fps, 'date');\\r\\n };\\r\\n src.effective : Period as s -> tgt then {\\r\\n s.end as fpe -> tgt.verbatim_end_date = cast(fps, 'date');\\r\\n };\\r\\n src.category : CodeableConcept as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.drug_type_concept_id = a;\\r\\n };\\r\\n };\\r\\n src.reason : CodeableReference as s -> tgt then {\\r\\n s.concept as scs -> tgt then {\\r\\n scs.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.stop_reason = a;\\r\\n };\\r\\n };\\r\\n };\\r\\n}\\r\\n\\r\\n \"},\"extension\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\"valueCode\":\"brr\"},{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\"valueInteger\":1,\"_valueInteger\":{\"extension\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\"valueCanonical\":\"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"}]}},{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\"valueCode\":\"informative\",\"_valueCode\":{\"extension\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\"valueCanonical\":\"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"}]}}],\"url\":\"http://hl7.org/fhir/uv/omop/StructureMap/MedicationMap\",\"version\":\"1.0.0-ballot\",\"name\":\"MedicationMap\",\"title\":\"Mapping MedicationStatement resource to DrugExposure OMOP Domain\",\"status\":\"draft\",\"date\":\"2025-07-29T17:40:15+00:00\",\"publisher\":\"HL7 International / Biomedical Research and Regulation\",\"contact\":[{\"name\":\"HL7 International / Biomedical Research and Regulation\",\"telecom\":[{\"system\":\"url\",\"value\":\"http://www.hl7.org/Special/committees/rcrim\"}]}],\"description\":\"This mapping maps FHIR MedicationStatement instances to OMOP Drug Exposure Table objects. NOTE: It does not map FHIR MedicationRequest instances although there is a discussion of those instances in the notes.\",\"jurisdiction\":[{\"coding\":[{\"system\":\"http://unstats.un.org/unsd/methods/m49/m49.htm\",\"code\":\"001\",\"display\":\"World\"}]}],\"structure\":[{\"url\":\"http://hl7.org/fhir/StructureDefinition/MedicationStatement\",\"mode\":\"source\",\"alias\":\"MedState\"},{\"url\":\"http://hl7.org/fhir/uv/omop/StructureDefinition/DrugExposure\",\"mode\":\"target\",\"alias\":\"DrugExpTable\"}],\"group\":[{\"name\":\"MedExposure\",\"input\":[{\"name\":\"src\",\"type\":\"MedState\",\"mode\":\"source\"},{\"name\":\"tgt\",\"type\":\"DrugExpTable\",\"mode\":\"target\"}],\"rule\":[{\"name\":\"id\",\"source\":[{\"context\":\"src\",\"element\":\"id\",\"variable\":\"did\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"drug_exposure_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"did\"}]}]},{\"name\":\"mapPatientId\",\"source\":[{\"context\":\"src\",\"element\":\"subject.reference\",\"variable\":\"patientRefId\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"person_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"patientRefId\"}]}]},{\"name\":\"drugTypeConceptId\",\"source\":[{\"context\":\"src\",\"element\":\"id\",\"variable\":\"dtci\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"drug_type_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueInteger\":581452}]}]},{\"name\":\"effectiveDateTime\",\"source\":[{\"context\":\"src\",\"type\":\"dateTime\",\"element\":\"effective\",\"variable\":\"edt\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"drug_exposure_start_datetime\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"edt\"}]},{\"context\":\"tgt\",\"element\":\"drug_exposure_start_date\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"edt\"},{\"valueString\":\"date\"}]}]},{\"name\":\"effectivePeriod\",\"source\":[{\"context\":\"src\",\"type\":\"Period\",\"element\":\"effectivePeriod\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"end\",\"source\":[{\"context\":\"s\",\"element\":\"end\",\"variable\":\"fpe\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"drug_exposure_end_datetime\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"fpe\"}]},{\"context\":\"tgt\",\"element\":\"drug_exposure_end_date\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"fpe\"},{\"valueString\":\"date\"}]}]}]},{\"name\":\"effectivePeriod\",\"source\":[{\"context\":\"src\",\"type\":\"Period\",\"element\":\"effective\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"end\",\"source\":[{\"context\":\"s\",\"element\":\"end\",\"variable\":\"fpe\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"verbatim_end_date\",\"transform\":\"cast\",\"parameter\":[{\"valueId\":\"fps\"},{\"valueString\":\"date\"}]}]}]},{\"name\":\"categoryCodeableConcept\",\"source\":[{\"context\":\"src\",\"type\":\"CodeableConcept\",\"element\":\"category\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"coding\",\"source\":[{\"context\":\"s\",\"element\":\"coding\",\"variable\":\"sc\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"code\",\"source\":[{\"context\":\"sc\",\"element\":\"code\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"drug_type_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]}]}]}]},{\"name\":\"reasonCodeableReference\",\"source\":[{\"context\":\"src\",\"element\":\"reasonCode\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"coding\",\"source\":[{\"context\":\"scs\",\"element\":\"coding\",\"variable\":\"sc\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"code\",\"source\":[{\"context\":\"sc\",\"element\":\"code\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"stop_reason\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]}]}]}]},{\"name\":\"medicationCodeableReference\",\"source\":[{\"context\":\"src\",\"element\":\"medicationCodeableConcept\",\"variable\":\"s\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"coding\",\"source\":[{\"context\":\"s\",\"element\":\"coding\",\"variable\":\"sc\"}],\"target\":[{\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"tgt\"}]}],\"rule\":[{\"name\":\"code\",\"source\":[{\"context\":\"sc\",\"element\":\"code\",\"variable\":\"a\"}],\"target\":[{\"context\":\"tgt\",\"element\":\"drug_concept_id\",\"transform\":\"copy\",\"parameter\":[{\"valueId\":\"a\"}]}]}]}],\"documentation\":\"src.id as id -> tgt.drug_exposure_id = cast(id, \\\"integer\\\");\"}]}]}",
"output_omop_data": ""
@@ -929,7 +929,7 @@
"name": "transform_to_measurement",
"error": false,
"dataframe": "Observation_df",
- "description": "Describe the task of node transform_fhir_data_node_4",
+ "description": "Transform source FHIR data into OMOP measurement records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"MeasurementMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/MeasurementMap'\\r\\n/// name = 'MeasurementMap'\\r\\n/// title = 'Mapping Observation resource to Measurement OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Observation" alias Observation as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/Measurement" alias MeasureTable as target\\r\\n\\r\\ngroup Measures(source src : Observation, target tgt : MeasureTable) {\\r\\n src where ('vital-signs' | 'laboratory').supersetOf(Observation.category.coding.code) then {\\r\\n src.code as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.measurement_concept_id = a;\\r\\n };\\r\\n }; // src.id as id -> tgt.measurement_id = cast(id, "integer");\\r\\n src.effective : dateTime as edt -> tgt.measurement_datetime = edt, tgt.measurement_date = cast(edt, 'date'); // src.subject as s -> tgt then {\\r\\n src.effective : instant as einst -> tgt.measurement_datetime = cast(einst, 'dateTime'), tgt.measurement_date = cast(einst, 'date');\\r\\n src.effective : Period as s -> tgt then {\\r\\n s.start as eps -> tgt.measurement_datetime = cast(eps, 'dateTime'), tgt.measurement_date = cast(eps, 'date');\\r\\n };\\r\\n src.issued as s where (src.issued.toDate != src.effectiveDateTime) -> tgt.measurement_source_value = cast(s, 'string');\\r\\n src.value : Quantity as s -> tgt then {\\r\\n s.value as a -> tgt.value_as_number = a;\\r\\n s.unit as b -> tgt.unit_concept_id = b;\\r\\n }; // src.performer as s -> tgt then {\\r\\n src.value : CodeableConcept as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.value_as_concept_id = a;\\r\\n };\\r\\n };\\r\\n src.value : string as b -> tgt.value_source_value = b;\\r\\n src.interpretation as c -> tgt.value_as_concept_id = c;\\r\\n src.note as d -> tgt.measurement_source_value = d;\\r\\n } "OnlyMeasures";\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/MeasurementMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"MeasurementMap\",\n \"title\": \"Mapping Observation resource to Measurement OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Observation instances that are considered measurements to OMOP Measurement Table objects. Currently, this is done by considering the category code and mapping 'vital-signs' and 'laboratory' Observations.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Observation\",\n \"mode\": \"source\",\n \"alias\": \"Observation\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/Measurement\",\n \"mode\": \"target\",\n \"alias\": \"MeasureTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"Measures\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Observation\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"MeasureTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"mid\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"mid\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"mapPatientId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"subject.reference\",\n \"variable\": \"patientRefId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientRefId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"OnlyMeasures\",\n \"source\": [\n {\n \"context\": \"src\",\n \"condition\": \"('vital-signs' | 'laboratory').supersetOf(Observation.category.coding.code)\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"code\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueString\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.id as id -> tgt.measurement_id = cast(id, \\\"integer\\\");\"\n },\n {\n \"name\": \"effectiveDateTime\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"dateTime\",\n \"element\": \"effective\",\n \"variable\": \"edt\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"edt\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"edt\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n }\n ],\n \"documentation\": \"src.subject as s -> tgt then {\"\n },\n {\n \"name\": \"effectiveInstant\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"instant\",\n \"element\": \"effective\",\n \"variable\": \"einst\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"einst\"\n },\n {\n \"valueString\": \"dateTime\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"einst\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"effectivePeriod\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"Period\",\n \"element\": \"effective\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"start\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"start\",\n \"variable\": \"eps\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"eps\"\n },\n {\n \"valueString\": \"dateTime\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"eps\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"issued\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"issued\",\n \"variable\": \"s\",\n \"condition\": \"(src.issued.toDate != src.effectiveDateTime)\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"s\"\n },\n {\n \"valueString\": \"string\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"valueQuantity\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"Quantity\",\n \"element\": \"value\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"value\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"value\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"value_as_number\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"unit\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"unit\",\n \"variable\": \"b\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"unit_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"b\"\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.performer as s -> tgt then {\"\n },\n {\n \"name\": \"valueCodeableConcept\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"CodeableConcept\",\n \"element\": \"value\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"value_as_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"measurement_type_concept_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"measurement_type_concept_id\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_type_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueInteger\": 581458\n }\n ]\n }\n ]\n },\n {\n \"name\": \"valueString\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"string\",\n \"element\": \"value\",\n \"variable\": \"b\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"value_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"b\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"interpretation\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"interpretation\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"value_as_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"note\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"note\",\n \"variable\": \"d\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"measurement_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"d\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -958,7 +958,7 @@
"name": "transform_to_visit_occurrence",
"error": false,
"dataframe": "Encounter_df",
- "description": "Describe the task of node transform_fhir_data_node_6",
+ "description": "Transform source FHIR data into OMOP visit occurrence records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"EncounterVisitMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/EncounterVisitMap'\\r\\n/// name = 'EncounterVisitMap'\\r\\n/// title = 'Mapping Encounter resource to VisitOccurrence OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Encounter" alias Encounter as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/VisitOccurrence" alias VisitTable as target\\r\\n\\r\\ngroup VisitOccurrence(source src : Encounter, target tgt : VisitTable) {\\r\\n src.class as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.visit_concept_id = a, tgt.visit_source_value = a, tgt.visit_source_concept_id = a;\\r\\n };\\r\\n }; // src.id as id -> tgt.visit_occurrence_id = cast(id, "integer");\\r\\n src.actualPeriod as s -> tgt then {\\r\\n s.start as std -> tgt.visit_start_date = cast(std, 'date'), tgt.visit_start_datetime = std;\\r\\n s.end as ed -> tgt.visit_end_date = cast(ed, 'date'), tgt.visit_end_datetime = ed;\\r\\n };\\r\\n src.admission as s -> tgt then {\\r\\n s.admitSource as sa -> tgt then {\\r\\n sa.coding as sc -> tgt then {\\r\\n sc.code as code -> tgt.admitted_from_concept_id = code, tgt.admitted_from_source_value = code;\\r\\n };\\r\\n };\\r\\n s.dischargeDisposition as sd -> tgt then {\\r\\n sd.coding as sc -> tgt then {\\r\\n sc.code as code -> tgt.discharged_to_concept_id = code, tgt.discharged_to_source_value = code;\\r\\n };\\r\\n };\\r\\n };\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/EncounterVisitMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"EncounterVisitMap\",\n \"title\": \"Mapping Encounter resource to VisitOccurrence OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Encounter instances to OMOP Visit Occurence Table objects.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Encounter\",\n \"mode\": \"source\",\n \"alias\": \"Encounter\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/VisitOccurrence\",\n \"mode\": \"target\",\n \"alias\": \"VisitTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"VisitOccurrence\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Encounter\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"VisitTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"vid\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"visit_occurrence_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"vid\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"visitTypeConceptId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"visitTypeConceptId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"visit_type_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueInteger\": 32817\n }\n ]\n }\n ]\n },\n {\n \"name\": \"subject\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"subject.reference\",\n \"variable\": \"patientRef\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"patientRef.substring(8)\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"mapPatientId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"subject.reference\",\n \"variable\": \"patientRefId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientRefId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"class\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"class\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"visit_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"visit_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"visit_source_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.id as id -> tgt.visit_occurrence_id = cast(id, \\\"integer\\\");\"\n },\n {\n \"name\": \"actualPeriod\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"period\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"start\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"start\",\n \"variable\": \"std\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"visit_start_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"std\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"visit_start_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"std\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"end\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"end\",\n \"variable\": \"ed\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"visit_end_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"ed\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"visit_end_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"ed\"\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"admission\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"admission\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"admitSource\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"admitSource\",\n \"variable\": \"sa\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"sa\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"code\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"admitted_from_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"code\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"admitted_from_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"code\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"dischargeDisposition\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"dischargeDisposition\",\n \"variable\": \"sd\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"sd\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"code\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"discharged_to_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"code\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"discharged_to_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"code\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -987,7 +987,7 @@
"name": "transform_to_condition_occurrence",
"error": false,
"dataframe": "Condition_df",
- "description": "Describe the task of node transform_fhir_data_node_7",
+ "description": "Transform source FHIR data into OMOP condition occurrence records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"ConditionMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/ConditionMap'\\r\\n/// name = 'ConditionMap'\\r\\n/// title = 'Mapping Condition resource to Condition Occurrence OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Condition" alias Condition as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/ConditionOccurrence" alias ConOccTable as target\\r\\n\\r\\ngroup ConditionOccurrence(source src : Condition, target tgt : ConOccTable) {\\r\\n src.code as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.condition_concept_id = a;\\r\\n };\\r\\n }; // src.id as id -> tgt.condition_occurrence_id = cast(id, "integer");\\r\\n src.recordedDate as rd -> tgt.condition_start_datetime = cast(rd, 'dateTime'), tgt.condition_start_date = rd;\\r\\n src.onset : dateTime as osd -> tgt.condition_start_datetime = osd, tgt.condition_start_date = cast(osd, 'date');\\r\\n src.abatement : dateTime as abdt -> tgt.condition_end_datetime = adt, tgt.condition_end_date = cast(abdt, 'date');\\r\\n src.category as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.condition_type_concept_id = a;\\r\\n };\\r\\n };\\r\\n src.clinicalStatus as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code as a -> tgt.condition_status_concept_id = a;\\r\\n };\\r\\n };\\r\\n src.evidence as s -> tgt then {\\r\\n s.concept as sc -> tgt then {\\r\\n sc.coding as sci -> tgt then {\\r\\n sci.code as a -> tgt.condition_source_concept_id = a;\\r\\n };\\r\\n };\\r\\n }; // src.encounter as s -> tgt then {\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/ConditionMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"ConditionMap\",\n \"title\": \"Mapping Condition resource to Condition Occurrence OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Condition instances to OMOP Condition Occurence Table objects.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Condition\",\n \"mode\": \"source\",\n \"alias\": \"Condition\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/ConditionOccurrence\",\n \"mode\": \"target\",\n \"alias\": \"ConOccTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"ConditionOccurrence\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Condition\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"ConOccTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"condition_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"conditionId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_occurrence_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"conditionId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"mapPatientId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"subject.reference\",\n \"variable\": \"patRef\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patRef\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"code\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.id as id -> tgt.condition_occurrence_id = cast(id, \\\"integer\\\");\"\n },\n {\n \"name\": \"recordedDate\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"recordedDate\",\n \"variable\": \"rd\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_start_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"rd\"\n },\n {\n \"valueString\": \"dateTime\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"condition_start_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"rd\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"onsetDateTime\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"dateTime\",\n \"element\": \"onset\",\n \"variable\": \"osd\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_start_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"osd\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"condition_start_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"osd\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"abatementDateTime\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"dateTime\",\n \"element\": \"abatement\",\n \"variable\": \"abdt\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_end_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"adt\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"condition_end_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"abdt\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"category\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"category\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_type_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"clinicalStatus\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"clinicalStatus\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_status_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"evidence\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"evidence\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"concept\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"concept\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"coding\",\n \"variable\": \"sci\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sci\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"condition_source_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.encounter as s -> tgt then {\"\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -1016,7 +1016,7 @@
"name": "transform_to_person",
"error": false,
"dataframe": "Patient_df",
- "description": "Describe the task of node transform_fhir_data_node_8",
+ "description": "Transform source FHIR data into OMOP person records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"PersonMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/PersonMap'\\r\\n/// name = 'PersonMap'\\r\\n/// title = 'Mapping Patient resource to Person OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Patient" alias Patient as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/Person" alias PersonTable as target\\r\\n\\r\\ngroup Person(source src : Patient, target tgt : PersonTable) {\\r\\n src.gender as gender -> tgt.gender_concept_id = gender, tgt.gender_source_value = cast(gender, 'string'); // src.id as id -> tgt.person_id = cast(id, "integer");\\r\\n src.birthDate as bdSrc -> tgt.birth_datetime = bdSrc, tgt.year_of_birth = (src.birthDate.toString().substring(0, 4)), tgt.month_of_birth = (src.birthDate.toString().substring(5, 2)), tgt.day_of_birth = (src.birthDate.toString().substring(8, 2));\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/PersonMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"PersonMap\",\n \"title\": \"Mapping Patient resource to Person OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Patient instances to OMOP Person Table objects.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Patient\",\n \"mode\": \"source\",\n \"alias\": \"Patient\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/Person\",\n \"mode\": \"target\",\n \"alias\": \"PersonTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"Person\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Patient\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"PersonTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"person_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"patientId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"gender\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"gender\",\n \"variable\": \"gender\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"gender_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"gender\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"gender_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"gender\"\n },\n {\n \"valueString\": \"string\"\n }\n ]\n }\n ],\n \"documentation\": \"src.id as id -> tgt.person_id = cast(id, \\\"integer\\\");\"\n },\n {\n \"name\": \"birthDate\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"birthDate\",\n \"variable\": \"bdSrc\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"birth_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"bdSrc\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"year_of_birth\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"birthDate.substring(0,4)\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"month_of_birth\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"birthDate.substring(5,2)\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"day_of_birth\",\n \"transform\": \"evaluate\",\n \"parameter\": [\n {\n \"valueId\": \"src\"\n },\n {\n \"valueString\": \"birthDate.substring(8,2)\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"raceConcept\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-race').extension.valueCoding.display\",\n \"variable\": \"race\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"race_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"race\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"ethnicity_concept_id\",\n \"documentation\": \"Map FHIR US Core ethnicity extension to OMOP person.ethnicity_concept_id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.where(url = 'ombCategory').valueCoding.code\",\n \"variable\": \"ethnicityCode\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"ethnicity_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"ethnicityCode\"\n }\n ]\n }\n ]\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -1045,7 +1045,7 @@
"name": "transform_to_drug_exposure",
"error": false,
"dataframe": "Immunization_df",
- "description": "Describe the task of node transform_fhir_data_node_8",
+ "description": "Transform source FHIR data into OMOP drug exposure records.",
"errorMessage": null,
"structure_map": "{\n \"resourceType\": \"StructureMap\",\n \"id\": \"ImmunizationMap\",\n \"text\": {\n \"status\": \"generated\",\n \"div\": \" \\r\\n/// url = 'http://hl7.org/fhir/uv/omop/StructureMap/ImmunizationMap'\\r\\n/// name = 'ImmunizationMap'\\r\\n/// title = 'Mapping Immunization resource to Drug Exposure OMOP Domain'\\r\\n/// status = 'draft'\\r\\n\\r\\nuses "http://hl7.org/fhir/StructureDefinition/Immunization" alias Immunization as source\\r\\nuses "http://hl7.org/fhir/uv/omop/StructureDefinition/DrugExposure" alias DrugExposureTable as target\\r\\n\\r\\ngroup DrugExposure(source src : Immunization, target tgt : DrugExposureTable) {\\r\\n src.vaccineCode as s -> tgt then {\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code -> tgt.drug_concept_id, tgt.drug_source_value, tgt.drug_source_concept_id;\\r\\n };\\r\\n }; // src.id as id -> tgt.drug_exposure_id = cast(id, "integer");\\r\\n src.doseQuantity as s -> tgt then {\\r\\n s.value as s -> tgt.quantity = cast(s, 'decimal');\\r\\n s.code as s -> tgt.dose_unit_source_value = cast(s, 'string');\\r\\n }; // src.patient as s -> tgt then {\\r\\n src.route as s -> tgt then {\\r\\n s.text as s -> tgt.route_source_value = cast(s, 'string');\\r\\n s.coding as sc -> tgt then {\\r\\n sc.code -> tgt.route_concept_id, tgt.route_source_value;\\r\\n };\\r\\n };\\r\\n src.occurrence : dateTime as odt -> tgt.drug_exposure_start_date = cast(odt, 'date'), tgt.drug_exposure_start_datetime = odt, tgt.drug_exposure_end_date = cast(odt, 'date'), tgt.drug_exposure_end_datetime = odt;\\r\\n src.lotNumber as s -> tgt.lot_number = cast(s, 'string'); // src.encounter as s -> tgt then {\\r\\n}\\r\\n\\r\\n \"\n },\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-wg\",\n \"valueCode\": \"brr\"\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-fmm\",\n \"valueInteger\": 1,\n \"_valueInteger\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n },\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status\",\n \"valueCode\": \"informative\",\n \"_valueCode\": {\n \"extension\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/structuredefinition-conformance-derivedFrom\",\n \"valueCanonical\": \"http://hl7.org/fhir/uv/omop/ImplementationGuide/hl7.fhir.uv.omop\"\n }\n ]\n }\n }\n ],\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureMap/ImmunizationMap\",\n \"version\": \"1.0.0-ballot\",\n \"name\": \"ImmunizationMap\",\n \"title\": \"Mapping Immunization resource to Drug Exposure OMOP Domain\",\n \"status\": \"draft\",\n \"date\": \"2025-07-29T17:40:15+00:00\",\n \"publisher\": \"HL7 International / Biomedical Research and Regulation\",\n \"contact\": [\n {\n \"name\": \"HL7 International / Biomedical Research and Regulation\",\n \"telecom\": [\n {\n \"system\": \"url\",\n \"value\": \"http://www.hl7.org/Special/committees/rcrim\"\n }\n ]\n }\n ],\n \"description\": \"This mapping maps FHIR Immunization instances to OMOP Drug Exposure Table objects.\",\n \"jurisdiction\": [\n {\n \"coding\": [\n {\n \"system\": \"http://unstats.un.org/unsd/methods/m49/m49.htm\",\n \"code\": \"001\",\n \"display\": \"World\"\n }\n ]\n }\n ],\n \"structure\": [\n {\n \"url\": \"http://hl7.org/fhir/StructureDefinition/Immunization\",\n \"mode\": \"source\",\n \"alias\": \"Immunization\"\n },\n {\n \"url\": \"http://hl7.org/fhir/uv/omop/StructureDefinition/DrugExposure\",\n \"mode\": \"target\",\n \"alias\": \"DrugExposureTable\"\n }\n ],\n \"group\": [\n {\n \"name\": \"DrugExposure\",\n \"input\": [\n {\n \"name\": \"src\",\n \"type\": \"Immunization\",\n \"mode\": \"source\"\n },\n {\n \"name\": \"tgt\",\n \"type\": \"DrugExposureTable\",\n \"mode\": \"target\"\n }\n ],\n \"rule\": [\n {\n \"name\": \"id\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"id\",\n \"variable\": \"did\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"drug_exposure_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"did\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"mapPatientId\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"patient.reference\",\n \"variable\": \"patientRefId\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"person_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"patientRefId\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"vaccineCode\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"vaccineCode\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\",\n \"variable\": \"a\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"drug_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"drug_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"drug_source_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"drug_type_concept_id\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"a\"\n }\n ]\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.id as id -> tgt.drug_exposure_id = cast(id, \\\"integer\\\");\"\n },\n {\n \"name\": \"doseQuantity\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"doseQuantity\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"value\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"value\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"quantity\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"s\"\n },\n {\n \"valueString\": \"decimal\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"code\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"dose_unit_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"s\"\n },\n {\n \"valueString\": \"string\"\n }\n ]\n }\n ]\n }\n ],\n \"documentation\": \"src.patient as s -> tgt then {\"\n },\n {\n \"name\": \"route\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"route\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"text\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"text\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"route_source_value\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"s\"\n },\n {\n \"valueString\": \"string\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"coding\",\n \"source\": [\n {\n \"context\": \"s\",\n \"element\": \"coding\",\n \"variable\": \"sc\"\n }\n ],\n \"target\": [\n {\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"tgt\"\n }\n ]\n }\n ],\n \"rule\": [\n {\n \"name\": \"code\",\n \"source\": [\n {\n \"context\": \"sc\",\n \"element\": \"code\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"route_concept_id\"\n },\n {\n \"context\": \"tgt\",\n \"element\": \"route_source_value\"\n }\n ]\n }\n ]\n }\n ]\n },\n {\n \"name\": \"occurrenceDateTime\",\n \"source\": [\n {\n \"context\": \"src\",\n \"type\": \"dateTime\",\n \"element\": \"occurrence\",\n \"variable\": \"odt\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"drug_exposure_start_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"odt\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"drug_exposure_start_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"odt\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"drug_exposure_end_date\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"odt\"\n },\n {\n \"valueString\": \"date\"\n }\n ]\n },\n {\n \"context\": \"tgt\",\n \"element\": \"drug_exposure_end_datetime\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"odt\"\n }\n ]\n }\n ]\n },\n {\n \"name\": \"lotNumber\",\n \"source\": [\n {\n \"context\": \"src\",\n \"element\": \"lotNumber\",\n \"variable\": \"s\"\n }\n ],\n \"target\": [\n {\n \"context\": \"tgt\",\n \"element\": \"lot_number\",\n \"transform\": \"copy\",\n \"parameter\": [\n {\n \"valueId\": \"s\"\n },\n {\n \"valueString\": \"string\"\n }\n ]\n }\n ],\n \"documentation\": \"src.encounter as s -> tgt then {\"\n }\n ]\n }\n ]\n}",
"output_omop_data": ""
@@ -1072,7 +1072,7 @@
"data": {
"name": "validate_cdm_data_drug_exp",
"error": false,
- "description": "Describe the task of node python_node_1",
+ "description": "Validate transformed drug exposure records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"drug_exposure_id\",\n \"person_id\",\n \"drug_concept_id\",\n \"drug_exposure_start_date\",\n \"drug_exposure_end_date\",\n \"drug_type_concept_id\"\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_drug_exposure\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1103,7 +1103,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_drug_expo"
},
- "description": "Describe the task of node py2table_node_9",
+ "description": "Convert validated drug exposure records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1128,7 +1128,7 @@
"data": {
"name": "validate_cdm_data_meas",
"error": false,
- "description": "Describe the task of node python_node_2",
+ "description": "Validate transformed measurement records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"measurement_id\",\n \"person_id\",\n \"measurement_concept_id\",\n \"measurement_date\",\n \"measurement_type_concept_id\"\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_measurement\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1159,7 +1159,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_meas"
},
- "description": "Describe the task of node py2table_node_10",
+ "description": "Convert validated measurement records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1183,7 +1183,7 @@
"id": "7d661465-6ce0-44af-80d7-fd533a1acae9",
"data": {
"name": "validate_cdm_data_drug_exp",
- "description": "Describe the task of node python_node_3",
+ "description": "Validate transformed drug exposure records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"drug_exposure_id\",\n \"person_id\",\n \"drug_concept_id\",\n \"drug_exposure_start_date\",\n \"drug_exposure_end_date\",\n \"drug_type_concept_id\"\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_drug_exposure\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n"
},
"type": "python_node",
@@ -1213,7 +1213,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_drug_exp"
},
- "description": "Describe the task of node py2table_node_11",
+ "description": "Convert validated drug exposure records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1238,7 +1238,7 @@
"data": {
"name": "validate_cdm_data_Obs",
"error": false,
- "description": "Describe the task of node python_node_4",
+ "description": "Validate transformed observation records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"observation_date\",\n \"observation_id\",\n \"person_id\",\n \"observation_type_concept_id\",\n \"observation_concept_id\",\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_observation\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1269,7 +1269,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_obs"
},
- "description": "Describe the task of node py2table_node_12",
+ "description": "Convert validated observation records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1294,7 +1294,7 @@
"data": {
"name": "validate_cdm_data_proc_occ",
"error": false,
- "description": "Describe the task of node python_node_5",
+ "description": "Validate transformed procedure occurrence records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"procedure_occurrence_id\",\n \"person_id\",\n \"procedure_concept_id\",\n \"procedure_date\",\n \"procedure_type_concept_id\"\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_procedure_occurrence\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1325,7 +1325,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_procedure_occ"
},
- "description": "Describe the task of node py2table_node_13",
+ "description": "Convert validated procedure occurrence records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1355,7 +1355,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_visit_occ"
},
- "description": "Describe the task of node py2table_node_14",
+ "description": "Convert validated visit occurrence records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1380,7 +1380,7 @@
"data": {
"name": "validate_cdm_data_co",
"error": false,
- "description": "Describe the task of node python_node_7",
+ "description": "Validate transformed condition occurrence records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"condition_occurrence_id\",\n \"person_id\",\n \"condition_concept_id\",\n \"condition_start_date\",\n \"condition_type_concept_id\"\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_condition_occurrence\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1411,7 +1411,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_co"
},
- "description": "Describe the task of node py2table_node_15",
+ "description": "Convert validated condition occurrence records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1436,7 +1436,7 @@
"data": {
"name": "validate_cdm_data_person",
"error": false,
- "description": "Describe the task of node python_node_8",
+ "description": "Validate transformed person records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"person_id\",\n \"gender_concept_id\",\n \"year_of_birth\",\n \"race_concept_id\",\n \"ethnicity_concept_id\",\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_person\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1467,7 +1467,7 @@
"path": "$",
"source": "Truncate_OMOP_cdm_table_person"
},
- "description": "Describe the task of node py2table_node_16",
+ "description": "Convert validated person records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1492,7 +1492,7 @@
"data": {
"name": "validate_cdm_data",
"error": false,
- "description": "Describe the task of node python_node_9",
+ "description": "Validate transformed observation records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"observation_date\",\n \"observation_id\",\n \"person_id\",\n \"observation_type_concept_id\",\n \"observation_concept_id\",\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_Observation\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1523,7 +1523,7 @@
"path": "$",
"source": "Truncate_OMOP__table_observation"
},
- "description": "Describe the task of node py2table_node_17",
+ "description": "Convert validated observation records into a table for database loading.",
"errorMessage": null
},
"type": "py2table_node",
@@ -1548,7 +1548,7 @@
"data": {
"name": "validate_cdm_data_vo",
"error": false,
- "description": "Describe the task of node python_node_9",
+ "description": "Validate transformed visit occurrence records against OMOP CDM requirements.",
"python_code": "import pandas as pd\n\nREQUIRED_COLS = [\n \"visit_occurrence_id\",\n \"person_id\",\n \"visit_concept_id\",\n \"visit_end_date\",\n \"visit_start_date\",\n \"visit_type_concept_id\",\n]\n\ndef exec(myinput):\n df = myinput.get(\"transform_to_visit_occurrence\").result\n valid_df = df.dropna(subset=REQUIRED_COLS)\n return valid_df\n",
"errorMessage": null
},
@@ -1574,7 +1574,7 @@
"data": {
"name": "Truncate_OMOP__table_observation",
"error": false,
- "description": "Describe the task of node python_node_10",
+ "description": "Remove existing observation records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"observation\"\n source_col = \"observation_source_value\"\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n return data",
"errorMessage": null
},
@@ -1600,7 +1600,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_person",
"error": false,
- "description": "Describe the task of node python_node_11",
+ "description": "Remove existing person records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"person\"\n source_col = \"person_source_value\"\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1626,7 +1626,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_co",
"error": false,
- "description": "Describe the task of node python_node_12",
+ "description": "Remove existing condition occurrence records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"condition_occurrence\"\n source_col = \"condition_source_value\"\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1652,7 +1652,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_visit_occ",
"error": false,
- "description": "Describe the task of node python_node_13",
+ "description": "Remove existing visit occurrence records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"visit_occurrence\"\n source_col = \"visit_source_value\"\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1678,7 +1678,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_drug_expo",
"error": false,
- "description": "Describe the task of node python_node_14",
+ "description": "Remove existing drug exposure records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"drug_exposure\"\n source_col = \"drug_source_value\"\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1704,7 +1704,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_meas",
"error": false,
- "description": "Describe the task of node python_node_15",
+ "description": "Remove existing measurement records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"measurement\"\n source_col = \"measurement_source_value\"\n\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1730,7 +1730,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_drug_exp",
"error": false,
- "description": "Describe the task of node python_node_16",
+ "description": "Remove existing drug exposure records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"drug_exposure\"\n source_col = \"drug_source_value\"\n\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1756,7 +1756,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_obs",
"error": false,
- "description": "Describe the task of node python_node_17",
+ "description": "Remove existing observation records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"observation\"\n source_col = \"observation_source_value\"\n\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -1782,7 +1782,7 @@
"data": {
"name": "Truncate_OMOP_cdm_table_procedure_occ",
"error": false,
- "description": "Describe the task of node python_node_18",
+ "description": "Remove existing procedure occurrence records from the configured OMOP schema before loading replacements.",
"python_code": "def exec(myinput):\n data = myinput.get(\"validate_cdm_data\").result\n database_code = dest_db\n cdm_schema = dest_schema\n dao = SqlAlchemyDao(database_code=database_code)\n table_name = \"procedure_occurrence\"\n source_col = \"procedure_source_value\"\n\n source_ids = data[source_col].dropna().unique().tolist()\n metadata_obj = sql.MetaData(schema=cdm_schema)\n table_obj = sql.Table(table_name, metadata_obj, autoload_with=dao.engine)\n delete_stmt = table_obj.delete().where(table_obj.c[source_col].in_(source_ids))\n dao.execute_sqlalchemy_statement(delete_stmt, lambda r: r.rowcount)\n\n return data",
"errorMessage": null
},
@@ -2283,4 +2283,4 @@
"schema": "demo_cdm"
}
]
-}
\ No newline at end of file
+}
diff --git a/flows/fhir_anonymizer.json b/flows/fhir_anonymizer.json
index a8cc8ea..3446411 100644
--- a/flows/fhir_anonymizer.json
+++ b/flows/fhir_anonymizer.json
@@ -73,7 +73,7 @@
"id": "1a256c27-e86e-41d5-bd6d-338f2fe2ee7a",
"data": {
"name": "anonymizer",
- "description": "Describe the task of node python_node_2",
+ "description": "Load the FHIR anonymization library and expose its processing functions to downstream nodes.",
"python_code": "import subprocess\n\ndef exec(myinput) -> str:\n input_dir = myinput[\"SetConstants\"].result.get(\"INPUT_DIR\")\n ANONYMIZER = myinput[\"SetConstants\"].result.get(\"ANONYMIZER\")\n output_dir = myinput[\"SetConstants\"].result.get(\"OUTPUT_DIR\")\n\n config_dir = Path(myinput[\"SetConstants\"].result.get(\"CONFIG_FILE\"))\n # Get the first (and presumably only) file inside the folder\n config_file = next(config_dir.glob(\"*\"))\n print(f\"Take input from {input_dir} anonymize with {ANONYMIZER}, with config at {config_file}, output to {output_dir}\")\n # Run the anonymizer tool\n cmd = [\n \"dotnet\", ANONYMIZER,\n \"-i\", input_dir,\n \"-o\", output_dir,\n \"-b\", input_dir,\n \"-c\", str(config_file)\n ]\n subprocess.run(cmd, check=True)\n return output_dir\n "
},
"type": "python_node",
@@ -97,7 +97,7 @@
"id": "a1c23953-e541-4487-9825-2825f8204cc1",
"data": {
"name": "JsonConfiguration",
- "description": "Describe the task of node file_node_1"
+ "description": "Load the JSON configuration that defines which FHIR fields must be anonymized."
},
"type": "file_node",
"width": 350,
@@ -120,7 +120,7 @@
"id": "053a77a5-d4c0-4c77-b040-7a53fb2b5037",
"data": {
"name": "R4 Fhir Anonymizer - Mac",
- "description": "Describe the task of node python_node_2",
+ "description": "Anonymize FHIR R4 resources using the macOS-compatible processing path.",
"python_code": "from io import BytesIO\n\ndef exec(myinput):\n \"\"\"\n Downloads and extracts the latest Microsoft FHIR Anonymizer CommandLineTool.zip\n into /app/flows/data_transformation/fhir-anonymizer, returning the DLL path.\n \"\"\"\n TARGET_DIR = Path(\"/app/downloads/fhir-anonymizer\")\n TARGET_DIR.mkdir(parents=True, exist_ok=True)\n\n print(\"Fetching latest FHIR Anonymizer release info...\")\n #always get the latest version of fhir anonymizer\n release_api = \"https://api.github.com/repos/microsoft/Tools-for-Health-Data-Anonymization/releases/latest\"\n response = requests.get(release_api)\n response.raise_for_status()\n release_data = response.json()\n\n # Find the R4 CommandLineTool asset\n assets = release_data.get(\"assets\", [])\n asset = next(\n (a for a in assets if a[\"name\"] == \"Microsoft.Health.Fhir.Anonymizer.R4.CommandLineTool.zip\"),\n None\n )\n\n if not asset:\n raise RuntimeError(\"Could not find Microsoft.Health.Fhir.Anonymizer.R4.CommandLineTool.zip in latest release\")\n\n asset_url = asset[\"url\"]\n print(f\"Downloading asset from GitHub API asset URL: {asset_url}\")\n\n # The asset API URL requires this header to get the binary content\n headers = {\"Accept\": \"application/octet-stream\"}\n download = requests.get(asset_url, headers=headers, stream=True)\n download.raise_for_status()\n\n # Extract directly from memory\n with zipfile.ZipFile(BytesIO(download.content)) as zip_ref:\n zip_ref.extractall(TARGET_DIR)\n\n dll_path = TARGET_DIR / \"Microsoft.Health.Fhir.Anonymizer.R4.CommandLineTool.dll\"\n print(f\"Extracted FHIR Anonymizer to {TARGET_DIR}\")\n return str(dll_path)\n"
},
"type": "python_node",
@@ -144,7 +144,7 @@
"id": "b74c1f79-18ea-402a-9d94-c5e6e2a427d3",
"data": {
"name": "R4 Fhir Anonymizer - Windows",
- "description": "Describe the task of node python_node_3",
+ "description": "Anonymize FHIR R4 resources using the Windows-compatible processing path.",
"python_code": "from io import BytesIO\n\ndef exec(myinput):\n \"\"\"\n Downloads and extracts the latest Microsoft FHIR Anonymizer CommandLineTool.zip\n into /app/flows/data_transformation/fhir-anonymizer, returning the DLL path.\n \"\"\"\n TARGET_DIR = Path(\"/app/downloads/fhir-anonymizer\")\n TARGET_DIR.mkdir(parents=True, exist_ok=True)\n\n print(\"Fetching latest FHIR Anonymizer release info...\")\n #always get the latest version of fhir anonymizer\n release_api = \"https://api.github.com/repos/microsoft/Tools-for-Health-Data-Anonymization/releases/latest\"\n response = requests.get(release_api)\n response.raise_for_status()\n release_data = response.json()\n\n # Find the R4 CommandLineTool asset\n assets = release_data.get(\"assets\", [])\n asset = next(\n (a for a in assets if a[\"name\"] == \"Microsoft.Health.Fhir.Anonymizer.R4.CommandLineTool.zip\"),\n None\n )\n\n if not asset:\n raise RuntimeError(\"Could not find Microsoft.Health.Fhir.Anonymizer.R4.CommandLineTool.zip in latest release\")\n\n asset_url = asset[\"url\"]\n print(f\"Downloading asset from GitHub API asset URL: {asset_url}\")\n\n # The asset API URL requires this header to get the binary content\n headers = {\"Accept\": \"application/octet-stream\"}\n download = requests.get(asset_url, headers=headers, stream=True)\n download.raise_for_status()\n\n # Extract directly from memory\n with zipfile.ZipFile(BytesIO(download.content)) as zip_ref:\n zip_ref.extractall(TARGET_DIR)\n\n dll_path = TARGET_DIR / \"Microsoft.Health.Fhir.Anonymizer.R4.CommandLineTool.exe\"\n print(f\"Extracted FHIR Anonymizer to {TARGET_DIR}\")\n return str(dll_path)\n"
},
"type": "python_node",
@@ -168,7 +168,7 @@
"id": "5bcc2df2-c109-4d43-8215-8c00b2bdff22",
"data": {
"name": "Stu3 Fhir Anonymizer - Mac",
- "description": "Describe the task of node python_node_4",
+ "description": "Anonymize FHIR STU3 resources using the macOS-compatible processing path.",
"python_code": "from io import BytesIO\n\ndef exec(myinput):\n \"\"\"\n Downloads and extracts the latest Microsoft FHIR Anonymizer CommandLineTool.zip\n into /app/flows/data_transformation/fhir-anonymizer, returning the DLL path.\n \"\"\"\n TARGET_DIR = Path(\"/app/downloads/fhir-anonymizer\")\n TARGET_DIR.mkdir(parents=True, exist_ok=True)\n\n print(\"Fetching latest FHIR Anonymizer release info...\")\n #always get the latest version of fhir anonymizer\n release_api = \"https://api.github.com/repos/microsoft/Tools-for-Health-Data-Anonymization/releases/latest\"\n response = requests.get(release_api)\n response.raise_for_status()\n release_data = response.json()\n\n # Find the R4 CommandLineTool asset\n assets = release_data.get(\"assets\", [])\n asset = next(\n (a for a in assets if a[\"name\"] == \"Microsoft.Health.Fhir.Anonymizer.Stu3.CommandLineTool.zip\"),\n None\n )\n\n if not asset:\n raise RuntimeError(\"Could not find Microsoft.Health.Fhir.Anonymizer.Stu3.CommandLineTool.zip in latest release\")\n\n asset_url = asset[\"url\"]\n print(f\"Downloading asset from GitHub API asset URL: {asset_url}\")\n\n # The asset API URL requires this header to get the binary content\n headers = {\"Accept\": \"application/octet-stream\"}\n download = requests.get(asset_url, headers=headers, stream=True)\n download.raise_for_status()\n\n # Extract directly from memory\n with zipfile.ZipFile(BytesIO(download.content)) as zip_ref:\n zip_ref.extractall(TARGET_DIR)\n\n dll_path = TARGET_DIR / \"Microsoft.Health.Fhir.Anonymizer.Stu3.CommandLineTool.dll\"\n print(f\"Extracted FHIR Anonymizer to {TARGET_DIR}\")\n return str(dll_path)\n"
},
"type": "python_node",
@@ -192,7 +192,7 @@
"id": "06d68a83-c85b-48cf-a599-e0126d7b9aab",
"data": {
"name": "Stu3 Fhir Anonymizer - Windows",
- "description": "Describe the task of node python_node_5",
+ "description": "Anonymize FHIR STU3 resources using the Windows-compatible processing path.",
"python_code": "from io import BytesIO\n\ndef exec(myinput):\n \"\"\"\n Downloads and extracts the latest Microsoft FHIR Anonymizer CommandLineTool.zip\n into /app/flows/data_transformation/fhir-anonymizer, returning the DLL path.\n \"\"\"\n TARGET_DIR = Path(\"/app/downloads/fhir-anonymizer\")\n TARGET_DIR.mkdir(parents=True, exist_ok=True)\n\n print(\"Fetching latest FHIR Anonymizer release info...\")\n #always get the latest version of fhir anonymizer\n release_api = \"https://api.github.com/repos/microsoft/Tools-for-Health-Data-Anonymization/releases/latest\"\n response = requests.get(release_api)\n response.raise_for_status()\n release_data = response.json()\n\n # Find the R4 CommandLineTool asset\n assets = release_data.get(\"assets\", [])\n asset = next(\n (a for a in assets if a[\"name\"] == \"Microsoft.Health.Fhir.Anonymizer.Stu3.CommandLineTool.zip\"),\n None\n )\n\n if not asset:\n raise RuntimeError(\"Could not find Microsoft.Health.Fhir.Anonymizer.Stu3.CommandLineTool.zip in latest release\")\n\n asset_url = asset[\"url\"]\n print(f\"Downloading asset from GitHub API asset URL: {asset_url}\")\n\n # The asset API URL requires this header to get the binary content\n headers = {\"Accept\": \"application/octet-stream\"}\n download = requests.get(asset_url, headers=headers, stream=True)\n download.raise_for_status()\n\n # Extract directly from memory\n with zipfile.ZipFile(BytesIO(download.content)) as zip_ref:\n zip_ref.extractall(TARGET_DIR)\n\n dll_path = TARGET_DIR / \"Microsoft.Health.Fhir.Anonymizer.Stu3.CommandLineTool.exe\"\n print(f\"Extracted FHIR Anonymizer to {TARGET_DIR}\")\n return str(dll_path)\n\n "
},
"type": "python_node",
@@ -239,7 +239,7 @@
"id": "2829b691-ca0d-426d-92f1-80278d0d5957",
"data": {
"name": "data_file_processor",
- "description": "Describe the task of node python_node_6",
+ "description": "Read the supplied NDJSON file and prepare its FHIR resources for anonymization.",
"python_code": "from _shared_flow_utils.api.SupabaseStorageAPI import SupabaseStorageAPI\n\ndef exec(myinput):\n node_id = myinput[\"data_file\"].result.get(\"node_id\")\n filename = myinput[\"data_file\"].result.get(\"filename\")\n raw_data = SupabaseStorageAPI().get_file(node_id, filename)\n output_folder = Path(\"./downloads/data_file\")\n\n output_folder.mkdir(exist_ok=True)\n save_path = output_folder / filename\n save_path.write_bytes(raw_data)\n return save_path"
},
"type": "python_node",
@@ -263,7 +263,7 @@
"id": "ced70aef-4591-4987-9887-99547808ceb1",
"data": {
"name": "config_file_processor",
- "description": "Describe the task of node python_node_7",
+ "description": "Parse and validate the supplied FHIR anonymization configuration.",
"python_code": "from _shared_flow_utils.api.SupabaseStorageAPI import SupabaseStorageAPI\n\ndef exec(myinput):\n node_id = myinput[\"JsonConfiguration\"].result.get(\"node_id\")\n filename = myinput[\"JsonConfiguration\"].result.get(\"filename\")\n raw_data = SupabaseStorageAPI().get_file(node_id, filename)\n output_folder = Path(\"./downloads/config_file\")\n\n output_folder.mkdir(exist_ok=True)\n save_path = output_folder / filename\n save_path.write_bytes(raw_data)\n return save_path"
},
"type": "python_node",
@@ -287,7 +287,7 @@
"id": "799c1f43-031e-496e-8c2d-781eebf8a018",
"data": {
"name": "README",
- "description": "Describe the task of node python_node_8",
+ "description": "Explain how to configure inputs and run this flow.",
"python_code": "def exec(myinput):\n \"\"\" This tool requires a user defined configuration file so that the user\n can choose to hide certain fields of the dataset.\n One such configuration is provided here, copy and paste the contents \n below into a .json file and upload it to the JsonConfiguration\n node to test the tool.\n For a more specific anonymization behavior, such as date and value perturbation,\n please refer to the website: \n https://github.com/microsoft/Tools-for-Health-Data-Anonymization/blob/master/README.md\n \"\"\"\n return {\n \"fhirVersion\": \"R4\",\n \"processingError\":\"raise\",\n \"fhirPathRules\": [\n {\"path\": \"nodesByType('Extension')\", \"method\": \"redact\"},\n {\"path\": \"Organization.identifier\", \"method\": \"keep\"},\n {\"path\": \"nodesByType('Address').country\", \"method\": \"keep\"},\n {\"path\": \"Resource.id\", \"method\": \"cryptoHash\"},\n {\"path\": \"nodesByType('Reference').reference\", \"method\": \"cryptoHash\"},\n {\"path\": \"Group.name\", \"method\": \"redact\"},\n {\"path\": \"nodesByType('identifier').value\", \"method\": \"cryptoHash\"},\n {\n \"path\": \"Observation.valueQuantity.value\",\n \"method\": \"perturb\",\n \"span\": 0.2,\n \"rangeType\": \"proportional\",\n \"roundTo\": 0\n },\n { \"path\": \"nodesByType('date')\", \"method\": \"dateShift\" }\n ],\n \"parameters\": {\n \"dateShiftKey\": \"\",\n \"cryptoHashKey\": \"\",\n \"encryptKey\": \"\",\n \"enablePartialAgesForRedact\": true\n }\n }"
},
"type": "python_node",
diff --git a/flows/nlp_pyner.json b/flows/nlp_pyner.json
index ce7f3af..d6d8a07 100644
--- a/flows/nlp_pyner.json
+++ b/flows/nlp_pyner.json
@@ -138,14 +138,6 @@
}
],
"variables": [
- {
- "key": "database_code",
- "value": "alpdev_pg"
- },
- {
- "key": "schema_name",
- "value": "cdmdefault"
- },
{
"key": "note_table",
"value": "note"
@@ -172,5 +164,17 @@
"from py_name_entity_recognition import extract_entities",
"from prefect.blocks.system import Secret",
"import asyncio, os"
+ ],
+ "databases": [
+ {
+ "code": "demo_database",
+ "name": "database_code"
+ }
+ ],
+ "schemas": [
+ {
+ "name": "schema_name",
+ "schema": "demo_cdm"
+ }
]
-}
\ No newline at end of file
+}
diff --git a/flows/nlpflow.json b/flows/nlpflow.json
index e38aff3..34833ce 100644
--- a/flows/nlpflow.json
+++ b/flows/nlpflow.json
@@ -22,7 +22,7 @@
"id": "8fd5613a-2833-4bbe-b614-f52e84ac5189",
"data": {
"name": "flow_node",
- "description": "Describe the task of node python_node_0",
+ "description": "Extract clinical entities from OMOP notes, map them to standard concepts, and append NOTE_NLP records.",
"python_code": "from _shared_flow_utils.dao.DBDao import DBDao\nfrom datetime import datetime\nimport os\n\n\ndef exec(myinput):\n logger = get_run_logger()\n model_info = spacy.info()['pipelines']\n logger.info(f\"The following spacy models are available: {model_info}\")\n logger.info(\"Start the connection to database\")\n\n dbdao = DBDao(database_code=database_code)\n entity_extractor_linker = myinput.get(\"nel_node\").result\n mapper = myinput.get(\"umls2omop_node\").result\n\n with dbdao.ibis_connect() as conn:\n logger.info(\"Loading Notes\")\n note = conn.table(note_table, database=schema_name)\n note_nlp = conn.table(note_nlp_table, database=schema_name)\n record = note.select(['note_id','note_text']).execute()\n count = note_nlp.count().execute()\n rst_df = pd.DataFrame()\n\n for note_id, note_text in record.values:\n # Two steps of add_pipeline and extract\n logger.info(f\"Start to analyze note {note_id}\")\n medical_ner_nel = entity_extractor_linker(mapper)\n medical_ner_nel.add_pipeline(model_name=\"en_ner_bc5cdr_md\", linker_name=\"umls\")\n df1 = medical_ner_nel.extract_entities(text=note_text, confidence_threshold=0.8)\n\n medical_ner_nel = entity_extractor_linker(mapper)\n medical_ner_nel.add_pipeline(model_name=\"en_core_med7_trf\", linker_name=\"rxnorm\")\n df2 = medical_ner_nel.extract_entities(text=note_text, confidence_threshold=0.8)\n note_df = pd.concat([df1,df2]).reset_index(drop=True)\n\n # logger.info(f\"Complete the analysis of note {note_id}\")\n # map note_df to note_nlp table\n note_df['note_id'] = note_id\n note_df['section_concept_id'] = -1\n note_df['snippet'] = note_df.apply(lambda x: note_text[x['start']-10:x['end']+10], axis=1)\n note_df['note_nlp_source_concept_id'] = -1\n note_df['nlp_system'] = note_df.apply(lambda x: '-'.join(x[['model','linker']]+[f'-{model_info[x.model]}']), axis=1)\n note_df['nlp_date'] = datetime.now().strftime(\"%Y-%m-%d\")\n note_df['nlp_datetime'] = datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n note_df['term_exists'] = 'U'\n note_df['term_temporal'] ='N/A'\n note_df['term_modifiers'] ='N/A'\n note_df = note_df.rename(columns={'start':'offset',\n 'raw_text':'lexical_variant',\n 'concept_id':'note_nlp_concept_id',\n })\n note_df['note_nlp_id'] = note_df.index.values + 1 + count\n \n rst_df = pd.concat([rst_df,note_df]).reset_index(drop=True)\n count += len(note_df)\n logger.info(f\"Results of note_id: {note_id} for confidence_threshold=0.8 done\")\n \n cols = ['note_nlp_id',\n 'note_id',\n 'section_concept_id',\n 'snippet',\n 'offset',\n 'lexical_variant',\n 'note_nlp_concept_id',\n 'note_nlp_source_concept_id',\n 'nlp_system',\n 'nlp_date',\n 'nlp_datetime',\n 'term_exists',\n 'term_temporal',\n 'term_modifiers']\n with dbdao.engine.connect() as conn:\n rst_df[cols].to_sql(name = note_nlp_table,\n con = conn,\n schema = schema_name,\n if_exists = 'append',\n index = False,\n chunksize = 32,\n )"
},
"type": "python_node",
@@ -40,7 +40,7 @@
"id": "5401d4c1-e1ee-4511-b4ff-e26af639170d",
"data": {
"name": "nel_node",
- "description": "Describe the task of node python_node_1",
+ "description": "Build the clinical named-entity extraction and terminology-linking pipeline.",
"python_code": "from scispacy.linking import EntityLinker\nfrom scispacy.abbreviation import AbbreviationDetector\n\nclass EntityExtractorLinker(object):\n def __init__(self, mapper) -> None:\n self.pipelines= list()\n self.mapper = mapper\n\n def add_pipeline(self, model_name:str, linker_name:str):\n logger = get_run_logger()\n logger.info(f\"Adding pipeline for model '{model_name}' and linker '{linker_name}'\")\n logger.info(f\"Loading model ...\")\n nlp = spacy.load(model_name) \n logger.info(f\"Adding pipe ...\")\n nlp.add_pipe(\"abbreviation_detector\")\n logger.info(\"Loading linker ...\")\n nlp.add_pipe(\"scispacy_linker\", config={\"resolve_abbreviations\": True, \"linker_name\": linker_name})\n logger.info(\"Adding pipeline done\")\n self.pipelines.append((model_name, linker_name, nlp))\n\n def extract_entities(self, text:str, confidence_threshold:float=0.8):\n logger = get_run_logger()\n if len(self.pipelines) == 0:\n logger.info(\"No NLP pipeline defined - use 'add_pipeline' before calling 'extract_entities'!\")\n return None\n \n data = dict() \n for model_name, linker_name, nlp in self.pipelines:\n linker = nlp.get_pipe(\"scispacy_linker\")\n doc = nlp(text)\n logger.info(f\"Found {len(doc.ents)} entities.\")\n\n for entity in doc.ents:\n # list of matches in knowledge base (e.g. in case of UMLS, list of (cui_code, match_probability) tuples):\n kb_matches = entity._.kb_ents\n if len(kb_matches)==0:\n logger.info(f\"No knowledge base mapping found for entity '{entity}'. Skipping.\")\n continue\n\n code, confidence = kb_matches[0]\n if confidence < confidence_threshold:\n logger.info(f\"Confidence below threshold ({confidence} < {confidence_threshold}) for entity '{entity}'. Skipping.\")\n continue\n \n #convert CUI codes to rxNorm or SNOMED\n mappings = self.mapper.get_codes(code)\n if not any(key in mappings for key in [\"RxNorm\",\"SNOMED\"]):\n logger.info(\"No mapping found for UMLS CUI '{code}' to either RxNorm or SNOMED. Skipping.\")\n continue\n\n omop_code, vocabulary = (mappings.get(\"RxNorm\"), \"RxNorm\") if \"RxNorm\" in mappings else (mappings.get(\"SNOMED\"), \"SNOMED\") \n data.setdefault(\"raw_text\", list()).append(text[entity.start_char:entity.end_char])\n data.setdefault(\"start\", list()).append(entity.start_char)\n data.setdefault(\"end\", list()).append(entity.end_char)\n data.setdefault(\"label\", list()).append(entity.label_)\n data.setdefault(\"model\", list()).append(model_name)\n data.setdefault(\"linker\", list()).append(linker_name)\n\n kb_entity = linker.kb.cui_to_entity[code]\n data.setdefault(\"concept_id\", list()).append(omop_code)\n data.setdefault(\"vocabulary\", list()).append(vocabulary)\n data.setdefault(\"confidence\", list()).append(confidence)\n data.setdefault(\"UMLS_canonical_name\", list()).append(kb_entity.canonical_name)\n data.setdefault(\"UMLS_definition\", list()).append(kb_entity.definition)\n\n return pd.DataFrame(data)\n\ndef exec(myinput):\n return EntityExtractorLinker"
},
"type": "python_node",
@@ -58,7 +58,7 @@
"id": "3e488b24-5a1f-4789-a135-4a9c36775a6a",
"data": {
"name": "umls2omop_node",
- "description": "Describe the task of node python_node_2",
+ "description": "Load mappings from UMLS CUIs to standard OMOP concept identifiers.",
"python_code": "from typing import List, Union\n\nCUItoOHDSI_CSV=f\"flows/ner_extract_plugin/external/CUItoOHDSIv1.csv\"\n\nclass CIO2OMOP(object):\n def __init__(self, mapping_csv: str) -> None:\n with open(mapping_csv, 'r') as in_mappings:\n self.mappings_df = pd.read_csv(in_mappings, index_col=0)\n self.coding_systems = list(self.mappings_df[\"vocabulary_id\"].unique())\n\n def get_supported_vocabulaires(self) -> List[str]:\n return self.coding_systems\n\n def get_codes(self, CUI:str):\n try:\n results = self.mappings_df.loc[[CUI]]\n except KeyError:\n # CUI code not found\n return dict()\n \n return dict([(vocabulary_id, (results.loc[results[\"vocabulary_id\"]==vocabulary_id][\"concept_id\"]).squeeze()) \n for vocabulary_id in results[\"vocabulary_id\"]])\n\n def get_mappings(self, CUI:Union[str,List[str]]):\n return self.mappings_df.loc[CUI]\n\ndef exec(myinput):\n mapper = CIO2OMOP(mapping_csv=CUItoOHDSI_CSV)\n return mapper"
},
"type": "python_node",
@@ -74,8 +74,6 @@
}
],
"variables": [
- { "key": "database_code", "value": "alpdev_pg" },
- { "key": "schema_name", "value": "cdmdefault" },
{ "key": "note_table", "value": "note" },
{ "key": "note_nlp_table", "value": "note_nlp" }
],
@@ -83,5 +81,11 @@
"from prefect.logging import get_run_logger",
"import pandas as pd",
"import spacy"
+ ],
+ "databases": [
+ { "code": "demo_database", "name": "database_code" }
+ ],
+ "schemas": [
+ { "name": "schema_name", "schema": "demo_cdm" }
]
}
diff --git a/flows/pyomop.json b/flows/pyomop.json
index 9fce841..eb01b2d 100644
--- a/flows/pyomop.json
+++ b/flows/pyomop.json
@@ -30,7 +30,7 @@
"data": {
"name": "InsertPersonRecords",
"description": "Insert person table records",
- "python_code": "async def exec(myinput):\n tenant_configs = myinput[\"GetDBCredentials\"].result\n \n cdm = CdmEngineFactory(\n db='pgsql', \n host=tenant_configs.host, \n port=tenant_configs.port,\n user=tenant_configs.adminUser,\n pw=tenant_configs.adminPassword.get_secret_value(),\n name=tenant_configs.databaseName, \n schema='demo_cdm'\n )\n \n engine = cdm.engine\n\n async with cdm.session() as session:\n async with session.begin():\n session.add(\n Person(\n person_id=100,\n gender_concept_id=8532,\n gender_source_concept_id=8512,\n year_of_birth=1980,\n month_of_birth=1,\n day_of_birth=1,\n birth_datetime=datetime.datetime(1980, 1, 1),\n race_concept_id=8552,\n race_source_concept_id=8552,\n ethnicity_concept_id=38003564,\n ethnicity_source_concept_id=38003564,\n )\n )\n\n session.add(\n Person(\n person_id=101,\n gender_concept_id=8532,\n gender_source_concept_id=8512,\n year_of_birth=1980,\n month_of_birth=1,\n day_of_birth=1,\n birth_datetime=datetime.datetime(1980, 1, 1),\n race_concept_id=8552,\n race_source_concept_id=8552,\n ethnicity_concept_id=38003564,\n ethnicity_source_concept_id=38003564,\n )\n )\n await session.commit()\n\n await session.close()\n await engine.dispose()\n \n return cdm"
+ "python_code": "async def exec(myinput):\n tenant_configs = myinput[\"GetDBCredentials\"].result\n \n cdm = CdmEngineFactory(\n db='pgsql', \n host=tenant_configs.host, \n port=tenant_configs.port,\n user=tenant_configs.adminUser,\n pw=tenant_configs.adminPassword.get_secret_value(),\n name=tenant_configs.databaseName, \n schema=schema_name\n )\n \n engine = cdm.engine\n\n async with cdm.session() as session:\n async with session.begin():\n session.add(\n Person(\n person_id=100,\n gender_concept_id=8532,\n gender_source_concept_id=8512,\n year_of_birth=1980,\n month_of_birth=1,\n day_of_birth=1,\n birth_datetime=datetime.datetime(1980, 1, 1),\n race_concept_id=8552,\n race_source_concept_id=8552,\n ethnicity_concept_id=38003564,\n ethnicity_source_concept_id=38003564,\n )\n )\n\n session.add(\n Person(\n person_id=101,\n gender_concept_id=8532,\n gender_source_concept_id=8512,\n year_of_birth=1980,\n month_of_birth=1,\n day_of_birth=1,\n birth_datetime=datetime.datetime(1980, 1, 1),\n race_concept_id=8552,\n race_source_concept_id=8552,\n ethnicity_concept_id=38003564,\n ethnicity_source_concept_id=38003564,\n )\n )\n await session.commit()\n\n await session.close()\n await engine.dispose()\n \n return cdm"
},
"type": "python_node",
"width": 350,
@@ -48,7 +48,7 @@
"data": {
"name": "GetDBCredentials",
"description": "Get database credentials",
- "python_code": "def exec(myinput):\n dbdao = DBDao(database_code=\"demo_database\")\n return dbdao.tenant_configs"
+ "python_code": "def exec(myinput):\n dbdao = DBDao(database_code = database_code)\n return dbdao.tenant_configs"
},
"type": "python_node",
"width": 350,
@@ -106,5 +106,11 @@
"from sqlalchemy.future import select",
"from pyomop import CdmEngineFactory, CdmVocabulary, CdmVector",
"from pyomop.cdm54 import Person, Cohort, Vocabulary, Base"
+ ],
+ "databases": [
+ { "code": "demo_database", "name": "database_code" }
+ ],
+ "schemas": [
+ { "name": "schema_name", "schema": "demo_cdm" }
]
}