// src/repositories/DicomStudyRepository.ts import { DicomStudy, CreateDicomStudyDTO, UpdateDicomStudyDTO, DBDicomStudy, DicomStudySearchParams } from '../types/dicom'; import pool from '../config/db'; import logger from '../utils/logger'; import { Pool } from 'mysql2/promise'; import { RowDataPacket, ResultSetHeader } from 'mysql2'; export class DicomStudyRepository { constructor(private pool: Pool) {} // Modified constructor private async getRouterStringId(numericId: number): Promise { try { const [result] = await pool.query( 'SELECT router_id FROM routers WHERE id = ?', [numericId] ); const rows = result as any[]; if (rows.length === 0) { throw new Error(`Router not found with id: ${numericId}`); } return rows[0].router_id; } catch (error) { logger.error('Error getting router string ID:', error); throw error; } } private async getRouterNumericId(routerId: string): Promise { try { const [result] = await pool.query( 'SELECT id FROM routers WHERE router_id = ?', [routerId] ); const rows = result as any[]; if (rows.length === 0) { throw new Error(`Router not found with router_id: ${routerId}`); } return rows[0].id; } catch (error) { logger.error('Error getting router numeric ID:', error); throw error; } } private async mapDBStudyToDicomStudy(dbStudy: DBDicomStudy): Promise { return { id: dbStudy.id, router_id: dbStudy.router_id.toString(), study_instance_uid: dbStudy.study_instance_uid, patient_id: dbStudy.patient_id, patient_name: dbStudy.patient_name, accession_number: dbStudy.accession_number, study_date: dbStudy.study_date, modality: dbStudy.modality, study_description: dbStudy.study_description, series_instance_uid: dbStudy.series_instance_uid, procedure_code: dbStudy.procedure_code, referring_physician_name: dbStudy.referring_physician_name, study_status_code: dbStudy.study_status_code, association_id: dbStudy.association_id, created_at: dbStudy.created_at, updated_at: dbStudy.updated_at }; } async create(studyData: CreateDicomStudyDTO): Promise { try { const [result] = await pool.query( `INSERT INTO dicom_study_overview ( router_id, study_instance_uid, patient_id, patient_name, accession_number, study_date, modality, study_description, series_instance_uid, procedure_code, referring_physician_name, study_status_code, association_id, created_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`, [ studyData.router_id, studyData.study_instance_uid, studyData.patient_id, studyData.patient_name, studyData.accession_number, studyData.study_date, studyData.modality, studyData.study_description, studyData.series_instance_uid, studyData.procedure_code, studyData.referring_physician_name, studyData.study_status_code, studyData.association_id ] ); // Get the created study with the correct router_id format const insertId = (result as any).insertId; return await this.findById(insertId) as DicomStudy; } catch (error) { logger.error('Error creating DICOM study:', error); throw new Error('Failed to create DICOM study'); } } async findAll(): Promise { try { const [rows] = await pool.query(` SELECT d.*, r.router_id as router_string_id FROM dicom_study_overview d JOIN routers r ON d.router_id = r.id ORDER BY d.created_at DESC `); return Promise.all((rows as DBDicomStudy[]).map(row => this.mapDBStudyToDicomStudy(row))); } catch (error) { logger.error('Error fetching all DICOM studies:', error); throw new Error('Failed to fetch DICOM studies'); } } async findById(id: number): Promise { try { const [rows] = await pool.query(` SELECT d.*, r.router_id as router_string_id FROM dicom_study_overview d JOIN routers r ON d.router_id = r.id WHERE d.id = ? `, [id]); const results = rows as DBDicomStudy[]; if (results.length === 0) { return null; } return await this.mapDBStudyToDicomStudy(results[0]); } catch (error) { logger.error('Error fetching DICOM study by ID:', error); throw new Error('Failed to fetch DICOM study'); } } async findByRouterId(routerId: string): Promise { try { const numericRouterId = await this.getRouterNumericId(routerId); const [rows] = await pool.query(` SELECT d.*, r.router_id as router_string_id FROM dicom_study_overview d JOIN routers r ON d.router_id = r.id WHERE d.router_id = ? ORDER BY d.created_at DESC `, [numericRouterId]); return Promise.all((rows as DBDicomStudy[]).map(row => this.mapDBStudyToDicomStudy(row))); } catch (error) { logger.error('Error fetching DICOM studies by router ID:', error); throw new Error('Failed to fetch DICOM studies'); } } async update(id: number, studyData: UpdateDicomStudyDTO): Promise { try { // First check if study exists const existingStudy = await this.findById(id); if (!existingStudy) { return null; } // Build update query dynamically based on provided fields const updateFields: string[] = []; const updateValues: any[] = []; Object.entries(studyData).forEach(([key, value]) => { if (value !== undefined) { updateFields.push(`${key} = ?`); updateValues.push(value); } }); if (updateFields.length > 0) { // Add updated_at timestamp updateFields.push('updated_at = CURRENT_TIMESTAMP'); // Add id for WHERE clause updateValues.push(id); await pool.query(` UPDATE dicom_study_overview SET ${updateFields.join(', ')} WHERE id = ? `, updateValues); } // Return updated study return await this.findById(id); } catch (error) { logger.error('Error updating DICOM study:', error); throw new Error('Failed to update DICOM study'); } } async delete(id: number): Promise { try { const [result] = await pool.query( 'DELETE FROM dicom_study_overview WHERE id = ?', [id] ); return (result as any).affectedRows > 0; } catch (error) { logger.error('Error deleting DICOM study:', error); throw new Error('Failed to delete DICOM study'); } } async search(params: DicomStudySearchParams): Promise { try { let query = ` SELECT d.*, r.router_id as router_string_id FROM dicom_study_overview d JOIN routers r ON d.router_id = r.id WHERE 1=1 `; const values: any[] = []; if (params.startDate) { query += ' AND d.study_date >= ?'; values.push(params.startDate); } if (params.endDate) { query += ' AND d.study_date <= ?'; values.push(params.endDate); } if (params.modality) { query += ' AND d.modality = ?'; values.push(params.modality); } if (params.patientName) { query += ' AND d.patient_name LIKE ?'; values.push(`%${params.patientName}%`); } // Add sorting query += ' ORDER BY d.created_at DESC'; const [rows] = await pool.query(query, values); return Promise.all((rows as DBDicomStudy[]).map(row => this.mapDBStudyToDicomStudy(row))); } catch (error) { logger.error('Error searching DICOM studies:', error); throw new Error('Failed to search DICOM studies'); } } async findByStudyInstanceUid(studyInstanceUid: string): Promise { try { // Use RowDataPacket[] to align with mysql2/promise type expectations const [rows] = await pool.query(` SELECT * FROM dicom_study_overview WHERE study_instance_uid = ?`, [studyInstanceUid] ); // Check if rows is empty if (rows.length === 0) { return null; } // Map the first result to your DicomStudy object return await this.mapDBStudyToDicomStudy(rows[0]); } catch (error) { logger.error('Error fetching DICOM study by Study Instance UID:', error); throw new Error('Failed to fetch DICOM study'); } } }