From c3ef951ee5d68ebea0ce7c765058bcc4f061a263 Mon Sep 17 00:00:00 2001 From: Anitha Varghese Date: Mon, 21 Oct 2024 13:20:27 +0530 Subject: [PATCH] update: generate sql for combined_cgm_tracing.invoke through surveilr shell #29 --- lib/service/diabetes-research-hub/drhctl.ts | 31 ++-- .../diabetes-research-hub/package.sql.ts | 79 +++++++++-- .../generate-cgm-combined-sql.ts | 133 ++++++++++++++++++ 3 files changed, 212 insertions(+), 31 deletions(-) create mode 100644 lib/service/diabetes-research-hub/study-specific-stateless/generate-cgm-combined-sql.ts diff --git a/lib/service/diabetes-research-hub/drhctl.ts b/lib/service/diabetes-research-hub/drhctl.ts index f26cfaebb..775683da4 100644 --- a/lib/service/diabetes-research-hub/drhctl.ts +++ b/lib/service/diabetes-research-hub/drhctl.ts @@ -19,6 +19,7 @@ const dbFilePath = "resource-surveillance.sqlite.db"; // Path to your SQLite DB const RSC_BASE_URL = "https://raw.githubusercontent.com/surveilr/www.surveilr.com/main/lib/service/diabetes-research-hub"; const UX_URL = "https://www.surveilr.com/lib/service/diabetes-research-hub"; +//const UX_URL = "http://localhost:4321/lib/service/diabetes-research-hub"; @@ -225,21 +226,17 @@ try { } -// This function retrieves the SQL script for data de-identification. -// Note: Deidentification functions are only available through the `surveilr shell` or `surveilr orchestrate` commands. -// Issues prevail while executing these commands on Windows OS. -// Therefore avoiding deidentification till the issue is resolved -// try { -// console.log(colors.dim(`Performing DeIdentification: ${folderName}...`)); -// await executeCommand( -// [toolCmd, "orchestrate", "-n", "deidentification"], -// deidentificationSQLSupplier, -// ); -// console.log(colors.green("Deidentification successful.")); -// } catch (error) { -// console.error(colors.cyan("Error during DeIdentification:"), error.message); -// //Deno.exit(1); -// } +try { + console.log(colors.dim(`Performing DeIdentification: ${folderName}...`)); + await executeCommand( + [toolCmd, "orchestrate", "-n", "deidentification"], + deidentificationSQLSupplier, + ); + console.log(colors.green("Deidentification successful.")); +} catch (error) { + console.error(colors.cyan("Error during DeIdentification:"), error.message); + //Deno.exit(1); +} // This function is for the dynamic combined view generation // try { @@ -252,8 +249,8 @@ try { try { console.log(colors.dim(`Performing UX orchestration: ${folderName}...`)); - //await executeCommand([toolCmd, "shell"], uxSQLSupplier); - executeSqlCommands(uxSQL); // Execute UX SQL commands + await executeCommand([toolCmd, "shell"], uxSQLSupplier); + //executeSqlCommands(uxSQL); // Execute UX SQL commands console.log(colors.green("UX orchestration completed successfully.")); } catch (error) { console.error(colors.cyan("Error during UX orchestration:"), error.message); diff --git a/lib/service/diabetes-research-hub/package.sql.ts b/lib/service/diabetes-research-hub/package.sql.ts index a08a6a22c..4a8c2165d 100755 --- a/lib/service/diabetes-research-hub/package.sql.ts +++ b/lib/service/diabetes-research-hub/package.sql.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env --allow-run --allow-sys +#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env --allow-run --allow-sys --allow-ffi import { sqlPageNB as spn } from "./deps.ts"; import { console as c, @@ -8,6 +8,7 @@ import { } from "../../std/web-ui-content/mod.ts"; import * as sppn from "../..//std/notebook/sqlpage.ts"; +import { createUVACombinedCGMViewSQL,generateDetrendedDSCombinedCGMViewSQL } from './study-specific-stateless/generate-cgm-combined-sql.ts'; // custom decorator that makes navigation for this notebook type-safe function drhNav(route: Omit) { @@ -154,6 +155,15 @@ export class DRHSqlPages extends spn.TypicalSqlPageNotebook { `; } + combinedViewDDL() + { + const dbFilePath = "./resource-surveillance.sqlite.db"; + const sqlStatements= createUVACombinedCGMViewSQL(dbFilePath); + return this.SQL` + ${sqlStatements} + `; + } + @spn.navigationPrimeTopLevel({ caption: "DRH EDGE UI Home", description: "Welcome to Diabetes Research Hub EDGE UI", @@ -204,7 +214,7 @@ export class DRHSqlPages extends spn.TypicalSqlPageNotebook { SELECT 'card' as component, 'Features ' as title, - 8 as columns; + 9 as columns; SELECT @@ -269,6 +279,13 @@ export class DRHSqlPages extends spn.TypicalSqlPageNotebook { 'book' as icon, 'red' as color; + SELECT + 'Combined CGM Tracing' AS title, + '/drh/cgm-combined-data/index.sql' AS link, + 'Explore the comprehensive CGM dataset, integrating glucose monitoring data from all participants for in-depth analysis of glycemic patterns and trends across the study.' AS description, + 'book' as icon, + 'red' as color; + SELECT 'PHI De-Identification Results' AS title, @@ -501,6 +518,51 @@ This section provides information about the publications resulting from a study. `; } + + @drhNav({ + caption: "Combined CGM Tracing", + abbreviatedCaption: "Combined CGM Tracing", + description: "Combined CGM Tracing", + siblingOrder: 21, + }) + "drh/cgm-combined-data/index.sql"() { + const viewName = `combined_cgm_tracing`; + const pagination = this.pagination({ tableOrViewName: viewName }); + return this.SQL` + ${this.activePageTitle()} + + + SELECT +'text' as component, +' + +The **Combined CGM Tracing** refers to a consolidated dataset of continuous glucose monitoring (CGM) data, collected from multiple participants in a research study. CGM devices track glucose levels at regular intervals throughout the day, providing detailed insights into the participants'' glycemic control over time. + +In a research study, this combined dataset is crucial for analyzing glucose trends across different participants and understanding overall patterns in response to interventions or treatments. The **Combined CGM Tracing** dataset typically includes: +- **Participant ID**: A unique identifier for each participant, ensuring the data is de-identified while allowing for tracking individual responses. +- **Date_Time**: The timestamp for each CGM reading, formatted uniformly to allow accurate time-based analysis.(YYYY-MM-DD HH:MM:SS) +- **CGM_Value**: The recorded glucose level at each time point, often converted to a standard unit (e.g., mg/dL or mmol/L) and stored as a real number for precise calculations. + +This combined view enables researchers to perform comparative analyses, evaluate glycemic variability, and assess overall glycemic control across participants, which is essential for understanding the efficacy of treatments or interventions in the study. By aggregating data from multiple sources, researchers can identify population-level trends while maintaining the integrity of individual data. + +' as contents_md; + +${pagination.init()} + +-- Display uniform_resource table with pagination +SELECT 'table' AS component, + TRUE AS sort, + TRUE AS search; +SELECT * FROM ${viewName} +LIMIT $limit +OFFSET $offset; + +${pagination.renderSimpleMarkdown()} + + `; + } + + @drhNav({ caption: "CGM File MetaData Information", abbreviatedCaption: "CGM File MetaData Information", @@ -1038,19 +1100,8 @@ Participants are individuals who volunteer to take part in CGM research studies. export async function drhSQL() { return await spn.TypicalSqlPageNotebook.SQL( - new class extends spn.TypicalSqlPageNotebook { - + new class extends spn.TypicalSqlPageNotebook { - // async deidentifyDRHSQL() { - // // This function retrieves the SQL script for data de-identification. - // // Note: Deidentification functions are only available through the `surveilr shell` or `surveilr orchestrate` commands. - // // Issues prevail while executing these commands on Windows OS. - // return await spn.TypicalSqlPageNotebook.fetchText( - // import.meta.resolve( - // "./orchestration/deidentification-orchestration.sql", - // ), - // ); - // } async vandvDRHSQL() { // This function retrieves the SQL script for verfication and validation diff --git a/lib/service/diabetes-research-hub/study-specific-stateless/generate-cgm-combined-sql.ts b/lib/service/diabetes-research-hub/study-specific-stateless/generate-cgm-combined-sql.ts new file mode 100644 index 000000000..cc5f04273 --- /dev/null +++ b/lib/service/diabetes-research-hub/study-specific-stateless/generate-cgm-combined-sql.ts @@ -0,0 +1,133 @@ +#!/usr/bin/env -S deno run --allow-read --allow-write --allow-env --allow-run --allow-net + +import { Database } from "https://deno.land/x/sqlite3@0.12.0/mod.ts"; + +// Common function to log errors into the database +function logError(db: Database, errorMessage: string): void { + db.exec(`CREATE TABLE IF NOT EXISTS error_log ( + errorLogId INTEGER PRIMARY KEY AUTOINCREMENT, + datetime TEXT DEFAULT (datetime('now')), + error_message TEXT + );`); + + const params = JSON.stringify({ message: errorMessage }); + db.prepare("INSERT INTO error_log (error_message) VALUES (?);").run(params); +} + +// Function to create the initial view and return SQL for combined CGM tracing view (first dataset) +export function createUVACombinedCGMViewSQL(dbFilePath: string): string { + const db = new Database(dbFilePath); + + try { + // Execute the initial view + db.exec(`DROP VIEW IF EXISTS drh_participant_file_names;`); + db.exec(` + CREATE VIEW drh_participant_file_names AS + SELECT patient_id, GROUP_CONCAT(file_name, ', ') AS file_names + FROM uniform_resource_cgm_file_metadata + GROUP BY patient_id; + `); + //console.log("View 'drh_participant_file_names' created successfully."); + } catch (error) { + //console.error("Error creating view 'drh_participant_file_names':", error); + logError(db, error.message); + db.close(); + return ""; + } + + const participantsStmt = db.prepare("SELECT DISTINCT patient_id FROM drh_participant_file_names;"); + const participants = participantsStmt.all(); + + const sqlParts: string[] = []; + for (const { patient_id } of participants) { + const fileNamesStmt = db.prepare("SELECT file_names FROM drh_participant_file_names WHERE patient_id = ?;"); + const file_names_row = fileNamesStmt.get(patient_id); + + if (!file_names_row) { + //console.log(`No file names found for participant ${patient_id}.`); + continue; + } + + const file_names = file_names_row.file_names; + if (file_names) { + const participantTableNames = file_names.split(', ').map(fileName => `uniform_resource_${fileName}`); + participantTableNames.forEach(tableName => { + sqlParts.push(` + SELECT + '${patient_id}' as participant_id, + strftime('%Y-%m-%d %H:%M:%S', date_time) as Date_Time, + CAST(CGM_Value as REAL) as CGM_Value + FROM ${tableName} + `); + }); + } + fileNamesStmt.finalize(); + } + + let combinedViewSQL = ''; + if (sqlParts.length > 0) { + const combinedUnionAllQuery = sqlParts.join(' UNION ALL '); + combinedViewSQL = `CREATE VIEW combined_cgm_tracing AS ${combinedUnionAllQuery};`; + } else { + //console.log("No participant tables found, so the combined view will not be created."); + } + + participantsStmt.finalize(); + db.close(); + + return combinedViewSQL; // Return the SQL string instead of executing it +} + +// Function to generate the combined CGM tracing view SQL for the second dataset +export function generateDetrendedDSCombinedCGMViewSQL(dbFilePath: string): string { + const db = new Database(dbFilePath); + + const tablesStmt = db.prepare("SELECT name AS table_name FROM sqlite_master WHERE type = 'table' AND name LIKE 'uniform_resource_case__%'"); + const tables = tablesStmt.all(); + const sqlParts: string[] = []; + + // Loop through each table and generate the SQL for their CGM data + for (const { table_name } of tables) { + const participantId = table_name.split('__').pop(); // Extract participant ID from the table name + + // Generate SQL for each participant's CGM data + sqlParts.push(` + SELECT + '${participantId}' AS participant_id, + TRIM('2012-01-01 ' || hora ) AS Date_Time, + CAST(glucemia AS REAL) AS CGM_Value + FROM ${table_name} + `); + } + + let combinedViewSQL = ''; + if (sqlParts.length > 0) { + const combinedUnionAllQuery = sqlParts.join(' UNION ALL '); + combinedViewSQL = `CREATE VIEW combined_cgm_tracing AS ${combinedUnionAllQuery};`; + } else { + //console.log("No participant tables found, so the combined view will not be created."); + } + + db.close(); + + return combinedViewSQL; // Return the SQL string instead of executing it +} + +// If the script is being run directly, execute the functions +if (import.meta.main) { + const dbFilePath = "resource-surveillance.sqlite.db"; + + // Run the first dataset view creation and get the SQL for combined view + const dclp1combinedCGMViewSQL= createUVACombinedCGMViewSQL(dbFilePath); + if (dclp1combinedCGMViewSQL) { + console.log("Generated SQL for DCLP1 Study dataset:"); + console.log(dclp1combinedCGMViewSQL); + } + + // Generate and log the SQL for the second dataset + const detrendedDSCombinedCGMViewSQL = generateDetrendedDSCombinedCGMViewSQL(dbFilePath); + if (detrendedDSCombinedCGMViewSQL) { + console.log("Generated SQL for detrended fluctuation analysis dataset:"); + console.log(detrendedDSCombinedCGMViewSQL); + } +}