diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..f05988a --- /dev/null +++ b/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/tests'], + testMatch: ['**/*.test.ts'], + collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts'], + moduleFileExtensions: ['ts', 'js', 'json'], +}; diff --git a/src/main/models/database.types.ts b/src/main/models/database.types.ts new file mode 100644 index 0000000..9d0225a --- /dev/null +++ b/src/main/models/database.types.ts @@ -0,0 +1,9 @@ +export interface QueryResult { + rows: any[]; + rowCount: number; +} + +export interface TransactionResult { + success: boolean; + rowsAffected: number; +} diff --git a/src/main/services/database.service.ts b/src/main/services/database.service.ts new file mode 100644 index 0000000..63d0c12 --- /dev/null +++ b/src/main/services/database.service.ts @@ -0,0 +1,109 @@ +import sql from 'mssql'; +import mysql from 'mysql2/promise'; +import { SQLServerConfig, MySQLConfig } from '../models/config.types'; +import { QueryResult } from '../models/database.types'; +import { LoggerService } from './logger.service'; + +export class DatabaseService { + private sqlServerPool?: sql.ConnectionPool; + private mysqlPool?: mysql.Pool; + + constructor( + private sqlServerConfig: SQLServerConfig, + private mysqlConfig: MySQLConfig + ) {} + + async connectToSQLServer(): Promise { + try { + LoggerService.info('Connecting to SQL Server...'); + + this.sqlServerPool = await sql.connect({ + server: this.sqlServerConfig.server, + database: this.sqlServerConfig.database, + user: this.sqlServerConfig.username, + password: this.sqlServerConfig.password, + driver: this.sqlServerConfig.driver, + options: { + trustServerCertificate: + this.sqlServerConfig.trustServerCertificate === 'yes', + }, + }); + + LoggerService.info('SQL Server connection established'); + } catch (error) { + LoggerService.error('Failed to connect to SQL Server', error); + throw error; + } + } + + async connectToMySQL(): Promise { + try { + LoggerService.info('Connecting to MySQL...'); + + this.mysqlPool = mysql.createPool({ + host: this.mysqlConfig.host, + port: this.mysqlConfig.port, + database: this.mysqlConfig.database, + user: this.mysqlConfig.username, + password: this.mysqlConfig.password, + }); + + LoggerService.info('MySQL connection established'); + } catch (error) { + LoggerService.error('Failed to connect to MySQL', error); + throw error; + } + } + + async executeSQLServerQuery(query: string, params?: any[]): Promise { + if (!this.sqlServerPool) { + throw new Error('SQL Server not connected'); + } + + try { + const request = this.sqlServerPool.request(); + if (params) { + params.forEach((param, index) => { + request.input(`param${index}`, param); + }); + } + + const result = await request.query(query); + return { + rows: result.recordset, + rowCount: result.rowsAffected[0], + }; + } catch (error) { + LoggerService.error('SQL Server query failed', { query, error }); + throw error; + } + } + + async executeMySQLQuery(query: string, params?: any[]): Promise { + if (!this.mysqlPool) { + throw new Error('MySQL not connected'); + } + + try { + const [rows] = await this.mysqlPool.execute(query, params); + return { + rows: rows as any[], + rowCount: (rows as any[]).length, + }; + } catch (error) { + LoggerService.error('MySQL query failed', { query, error }); + throw error; + } + } + + async closeAll(): Promise { + if (this.sqlServerPool) { + await this.sqlServerPool.close(); + LoggerService.info('SQL Server connection closed'); + } + if (this.mysqlPool) { + await this.mysqlPool.end(); + LoggerService.info('MySQL connection closed'); + } + } +} diff --git a/tests/unit/services/database.service.test.ts b/tests/unit/services/database.service.test.ts new file mode 100644 index 0000000..42afc2f --- /dev/null +++ b/tests/unit/services/database.service.test.ts @@ -0,0 +1,26 @@ +import { DatabaseService } from '../../../src/main/services/database.service'; + +describe('DatabaseService', () => { + it('should throw error when querying without connection', async () => { + const service = new DatabaseService( + { + server: 'localhost', + database: 'test', + username: 'test', + password: 'test', + driver: 'test', + }, + { + host: 'localhost', + port: 3306, + database: 'test', + username: 'test', + password: 'test', + } + ); + + await expect( + service.executeSQLServerQuery('SELECT 1') + ).rejects.toThrow('SQL Server not connected'); + }); +});