feat: enhance DbService with improved error handling and documentation

- Added detailed JSDoc comments for better understanding of DbService methods and usage.
- Implemented error handling during database initialization and migration processes to ensure robustness.
- Introduced a method to check if the database is initialized before accessing it.
- Updated the migrateSeed method to throw errors on failure, improving error reporting.
This commit is contained in:
fullex 2025-11-21 13:29:24 +08:00
parent 7419cadd80
commit ab99366a0a

View File

@ -13,17 +13,52 @@ const logger = loggerService.withContext('DbService')
const DB_NAME = 'cherrystudio.sqlite' const DB_NAME = 'cherrystudio.sqlite'
const MIGRATIONS_BASE_PATH = 'migrations/sqlite-drizzle' const MIGRATIONS_BASE_PATH = 'migrations/sqlite-drizzle'
/**
* Database service managing SQLite connection via Drizzle ORM
* Implements singleton pattern for centralized database access
*
* Features:
* - Database initialization and connection management
* - Migration and seeding support
*
* @example
* ```typescript
* import { dbService } from '@data/db/DbService'
*
* // Run migrations
* await dbService.migrateDb()
*
* // Get database instance
* const db = dbService.getDb()
* ```
*/
class DbService { class DbService {
private static instance: DbService private static instance: DbService
private db: DbType private db: DbType
private isInitialized = false
private constructor() { private constructor() {
this.db = drizzle({ try {
connection: { url: pathToFileURL(path.join(app.getPath('userData'), DB_NAME)).href }, this.db = drizzle({
casing: 'snake_case' connection: { url: pathToFileURL(path.join(app.getPath('userData'), DB_NAME)).href },
}) casing: 'snake_case'
})
this.isInitialized = true
logger.info('Database connection initialized', {
dbPath: path.join(app.getPath('userData'), DB_NAME)
})
} catch (error) {
logger.error('Failed to initialize database connection', error as Error)
throw new Error('Database initialization failed')
}
} }
/**
* Get singleton instance of DbService
* Creates a new instance if one doesn't exist
* @returns {DbService} The singleton DbService instance
* @throws {Error} If database initialization fails
*/
public static getInstance(): DbService { public static getInstance(): DbService {
if (!DbService.instance) { if (!DbService.instance) {
DbService.instance = new DbService() DbService.instance = new DbService()
@ -31,23 +66,58 @@ class DbService {
return DbService.instance return DbService.instance
} }
public async migrateDb() { /**
const migrationsFolder = this.getMigrationsFolder() * Run database migrations
await migrate(this.db, { migrationsFolder }) * @throws {Error} If migration fails
*/
public async migrateDb(): Promise<void> {
try {
const migrationsFolder = this.getMigrationsFolder()
await migrate(this.db, { migrationsFolder })
logger.info('Database migration completed successfully')
} catch (error) {
logger.error('Database migration failed', error as Error)
throw error
}
} }
/**
* Get the database instance
* @throws {Error} If database is not initialized
*/
public getDb(): DbType { public getDb(): DbType {
if (!this.isInitialized) {
throw new Error('Database is not initialized')
}
return this.db return this.db
} }
public async migrateSeed(seedName: keyof typeof Seeding): Promise<boolean> { /**
* Check if database is initialized
*/
public isReady(): boolean {
return this.isInitialized
}
/**
* Run seed data migration
* @param seedName - Name of the seed to run
* @throws {Error} If seed migration fails
*/
public async migrateSeed(seedName: keyof typeof Seeding): Promise<void> {
try { try {
const Seed = Seeding[seedName] const Seed = Seeding[seedName]
if (!Seed) {
throw new Error(`Seed "${seedName}" not found`)
}
await new Seed().migrate(this.db) await new Seed().migrate(this.db)
return true
logger.info('Seed migration completed successfully', { seedName })
} catch (error) { } catch (error) {
logger.error('migration seeding failed', error as Error) logger.error('Seed migration failed', error as Error, { seedName })
return false throw error
} }
} }
@ -55,7 +125,7 @@ class DbService {
* Get the migrations folder based on the app's packaging status * Get the migrations folder based on the app's packaging status
* @returns The path to the migrations folder * @returns The path to the migrations folder
*/ */
private getMigrationsFolder() { private getMigrationsFolder(): string {
if (app.isPackaged) { if (app.isPackaged) {
//see electron-builder.yml, extraResources from/to //see electron-builder.yml, extraResources from/to
return path.join(process.resourcesPath, MIGRATIONS_BASE_PATH) return path.join(process.resourcesPath, MIGRATIONS_BASE_PATH)