mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 06:19:05 +08:00
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:
parent
7419cadd80
commit
ab99366a0a
@ -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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user