Files
BIPMaterialManager/src/main/ipc/database-handler.ts
Misaka a05c8a9037 feat: add TypeORM, logger, schemas, hooks and stores
- Add TypeORM integration with data-source, entities and repositories
- Add logger service for structured logging
- Add Zod validation schemas for auth, cleaner and extractor
- Add custom React hooks (useAuth, useCleaner, useExtractor, useValidation)
- Add Zustand stores (useAppStore, useUserStore)
- Add UI components (Button, Modal, Toast)
- Add error types and ErpBrowserManager
- Refactor IPC handlers and services
- Add unit tests for new modules

Co-Authored-By: Claude (glm-5) <noreply@anthropic.com>
2026-03-02 23:10:15 +08:00

230 lines
7.4 KiB
TypeScript

import { ipcMain } from 'electron'
import { MySqlService } from '../services/database/mysql'
import { SqlServerService } from '../services/database/sql-server'
import { createLogger } from '../services/logger'
import { DatabaseQueryError, ValidationError } from '../types/errors'
import type {
MySqlConfig,
MySqlQueryResult,
SqlServerConfig,
SqlServerQueryResult
} from '../types/ipc-api.types'
const log = createLogger('DatabaseHandler')
// Store MySQL service instances per window/connection
const mysqlServices = new Map<string, MySqlService>()
// Store SQL Server service instances per window/connection
const sqlServerServices = new Map<string, SqlServerService>()
/**
* Get or create MySQL service for a connection ID
*/
function getMySqlService(connectionId: string): MySqlService | undefined {
return mysqlServices.get(connectionId)
}
/**
* Set MySQL service for a connection ID
*/
function setMySqlService(connectionId: string, service: MySqlService): void {
mysqlServices.set(connectionId, service)
}
/**
* Delete MySQL service for a connection ID
*/
function deleteMySqlService(connectionId: string): void {
mysqlServices.delete(connectionId)
}
/**
* Get or create SQL Server service for a connection ID
*/
function getSqlServerService(connectionId: string): SqlServerService | undefined {
return sqlServerServices.get(connectionId)
}
/**
* Set SQL Server service for a connection ID
*/
function setSqlServerService(connectionId: string, service: SqlServerService): void {
sqlServerServices.set(connectionId, service)
}
/**
* Delete SQL Server service for a connection ID
*/
function deleteSqlServerService(connectionId: string): void {
sqlServerServices.delete(connectionId)
}
/**
* Register IPC handlers for database operations
*/
export function registerDatabaseHandlers(): void {
// Connect to MySQL
ipcMain.handle('database:mysql:connect', async (event, config: MySqlConfig): Promise<void> => {
try {
// Use window ID as connection identifier
const windowId = (event.sender as { id: number }).id.toString()
log.info('Connecting to MySQL', { windowId })
const service = new MySqlService(config)
await service.connect()
setMySqlService(windowId, service)
log.info('MySQL connected', { windowId })
} catch (error) {
const message = error instanceof Error ? error.message : 'Failed to connect to MySQL'
log.error('MySQL connection failed', { error: message })
throw new DatabaseQueryError(
message,
'DB_CONNECTION_FAILED',
error instanceof Error ? error : undefined
)
}
})
// Disconnect from MySQL
ipcMain.handle('database:mysql:disconnect', async (event): Promise<void> => {
try {
const windowId = (event.sender as { id: number }).id.toString()
const service = getMySqlService(windowId)
if (service) {
await service.disconnect()
deleteMySqlService(windowId)
log.info('MySQL disconnected', { windowId })
}
} catch (error) {
const message = error instanceof Error ? error.message : 'Failed to disconnect from MySQL'
log.error('MySQL disconnect failed', { error: message })
throw new DatabaseQueryError(
message,
'DB_CONNECTION_FAILED',
error instanceof Error ? error : undefined
)
}
})
// Check if MySQL is connected
ipcMain.handle('database:mysql:isConnected', async (event): Promise<boolean> => {
const windowId = (event.sender as { id: number }).id.toString()
const service = getMySqlService(windowId)
return service ? service.isConnected() : false
})
// Execute MySQL query
ipcMain.handle(
'database:mysql:query',
async (event, sql: string, params?: unknown[]): Promise<MySqlQueryResult> => {
try {
const windowId = (event.sender as { id: number }).id.toString()
const service = getMySqlService(windowId)
if (!service) {
throw new ValidationError(
'Not connected to MySQL. Call connect() first.',
'VAL_INVALID_INPUT'
)
}
log.debug('Executing MySQL query', { windowId, sql: sql.substring(0, 100) })
return await service.query(sql, params)
} catch (error) {
const message = error instanceof Error ? error.message : 'MySQL query failed'
log.error('MySQL query failed', { error: message })
throw new DatabaseQueryError(
message,
'DB_QUERY_FAILED',
error instanceof Error ? error : undefined
)
}
}
)
// Connect to SQL Server
ipcMain.handle(
'database:sqlserver:connect',
async (event, config: SqlServerConfig): Promise<void> => {
try {
const windowId = (event.sender as { id: number }).id.toString()
log.info('Connecting to SQL Server', { windowId })
const service = new SqlServerService(config)
await service.connect()
setSqlServerService(windowId, service)
log.info('SQL Server connected', { windowId })
} catch (error) {
const message = error instanceof Error ? error.message : 'Failed to connect to SQL Server'
log.error('SQL Server connection failed', { error: message })
throw new DatabaseQueryError(
message,
'DB_CONNECTION_FAILED',
error instanceof Error ? error : undefined
)
}
}
)
// Disconnect from SQL Server
ipcMain.handle('database:sqlserver:disconnect', async (event): Promise<void> => {
try {
const windowId = (event.sender as { id: number }).id.toString()
const service = getSqlServerService(windowId)
if (service) {
await service.disconnect()
deleteSqlServerService(windowId)
log.info('SQL Server disconnected', { windowId })
}
} catch (error) {
const message =
error instanceof Error ? error.message : 'Failed to disconnect from SQL Server'
log.error('SQL Server disconnect failed', { error: message })
throw new DatabaseQueryError(
message,
'DB_CONNECTION_FAILED',
error instanceof Error ? error : undefined
)
}
})
// Check if SQL Server is connected
ipcMain.handle('database:sqlserver:isConnected', async (event): Promise<boolean> => {
const windowId = (event.sender as { id: number }).id.toString()
const service = getSqlServerService(windowId)
return service ? service.isConnected() : false
})
// Execute SQL Server query
ipcMain.handle(
'database:sqlserver:query',
async (
event,
sqlString: string,
params?: Record<string, unknown>
): Promise<SqlServerQueryResult> => {
try {
const windowId = (event.sender as { id: number }).id.toString()
const service = getSqlServerService(windowId)
if (!service) {
throw new ValidationError(
'Not connected to SQL Server. Call connect() first.',
'VAL_INVALID_INPUT'
)
}
log.debug('Executing SQL Server query', { windowId, sql: sqlString.substring(0, 100) })
return await service.query(sqlString, params)
} catch (error) {
const message = error instanceof Error ? error.message : 'SQL Server query failed'
log.error('SQL Server query failed', { error: message })
throw new DatabaseQueryError(
message,
'DB_QUERY_FAILED',
error instanceof Error ? error : undefined
)
}
}
)
}