feat: implement database service with SQL Server and MySQL support
- Add database types (QueryResult, TransactionResult) - Implement DatabaseService with connection management for SQL Server and MySQL - Add query execution methods for both database types - Include comprehensive error handling and logging - Add unit test for error handling - Configure Jest for testing Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
8
jest.config.js
Normal file
8
jest.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
roots: ['<rootDir>/tests'],
|
||||
testMatch: ['**/*.test.ts'],
|
||||
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.d.ts'],
|
||||
moduleFileExtensions: ['ts', 'js', 'json'],
|
||||
};
|
||||
9
src/main/models/database.types.ts
Normal file
9
src/main/models/database.types.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export interface QueryResult {
|
||||
rows: any[];
|
||||
rowCount: number;
|
||||
}
|
||||
|
||||
export interface TransactionResult {
|
||||
success: boolean;
|
||||
rowsAffected: number;
|
||||
}
|
||||
109
src/main/services/database.service.ts
Normal file
109
src/main/services/database.service.ts
Normal file
@@ -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<void> {
|
||||
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<void> {
|
||||
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<QueryResult> {
|
||||
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<QueryResult> {
|
||||
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<void> {
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
26
tests/unit/services/database.service.test.ts
Normal file
26
tests/unit/services/database.service.test.ts
Normal file
@@ -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');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user