Initial commit: NestJS backend for Child Gold Land
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { Inject, Injectable, Logger, OnModuleDestroy, OnModuleInit, Optional } from '@nestjs/common'
|
||||
import { ConfigService } from '@nestjs/config'
|
||||
import Database from 'better-sqlite3'
|
||||
import { mkdirSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { EXPECTED_TABLES, listUserTables, runSchemaMigrations } from './migration.service'
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseService implements OnModuleInit, OnModuleDestroy {
|
||||
private readonly logger = new Logger(DatabaseService.name)
|
||||
private db: Database.Database | null = null
|
||||
private readonly dbPath: string
|
||||
|
||||
constructor(@Optional() @Inject(ConfigService) private readonly config?: ConfigService) {
|
||||
const configured = this.config?.get<string>('DB_PATH') ?? process.env.DB_PATH
|
||||
this.dbPath = configured ?? join(process.cwd(), 'data', 'app.db')
|
||||
}
|
||||
|
||||
onModuleInit(): void {
|
||||
mkdirSync(dirname(this.dbPath), { recursive: true })
|
||||
this.db = new Database(this.dbPath)
|
||||
this.db.pragma('journal_mode = WAL')
|
||||
runSchemaMigrations(this.db)
|
||||
this.logger.log(`SQLite ready at ${this.dbPath}`)
|
||||
}
|
||||
|
||||
onModuleDestroy(): void {
|
||||
if (this.db) {
|
||||
this.db.close()
|
||||
this.db = null
|
||||
this.logger.log('SQLite connection closed')
|
||||
}
|
||||
}
|
||||
|
||||
getDbPath(): string {
|
||||
return this.dbPath
|
||||
}
|
||||
|
||||
getDb(): Database.Database {
|
||||
if (!this.db) {
|
||||
throw new Error('Database is not initialized')
|
||||
}
|
||||
return this.db
|
||||
}
|
||||
|
||||
transaction<T>(fn: () => T): T {
|
||||
return this.getDb().transaction(fn)()
|
||||
}
|
||||
|
||||
verifyMigrationsApplied(): { ok: boolean; tables: string[]; missing: string[] } {
|
||||
const tables = listUserTables(this.getDb())
|
||||
const missing = EXPECTED_TABLES.filter((name) => !tables.includes(name))
|
||||
return { ok: missing.length === 0, tables, missing }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user