initial public release.
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
// src/core/io/KGStorage.ts
|
||||
|
||||
import { openDB } from 'idb'
|
||||
import type { IDBPDatabase } from 'idb'
|
||||
import { plainToClass, instanceToPlain } from 'class-transformer'
|
||||
import { DB_CONSTANTS } from '../../constants/coreConstants'
|
||||
|
||||
export interface StorageEntry {
|
||||
name: string
|
||||
data: Record<string, unknown>
|
||||
lastModified: number
|
||||
}
|
||||
|
||||
export class DuplicateEntryError extends Error {
|
||||
constructor(name: string) {
|
||||
super(`Entry "${name}" already exists`)
|
||||
this.name = 'DuplicateEntryError'
|
||||
}
|
||||
}
|
||||
|
||||
export class KGStorage {
|
||||
private static instance: KGStorage
|
||||
private dbPromises: Map<string, Promise<IDBPDatabase>>
|
||||
|
||||
private constructor() {
|
||||
this.dbPromises = new Map()
|
||||
}
|
||||
|
||||
public static getInstance(): KGStorage {
|
||||
if (!KGStorage.instance) {
|
||||
KGStorage.instance = new KGStorage()
|
||||
}
|
||||
return KGStorage.instance
|
||||
}
|
||||
|
||||
private getDB(dbName: string, _storeName: string, version: number = 1): Promise<IDBPDatabase> {
|
||||
const key = `${dbName}_${version}`
|
||||
|
||||
if (!this.dbPromises.has(key)) {
|
||||
const dbPromise = openDB(dbName, version, {
|
||||
upgrade(db) {
|
||||
// Create all required object stores for this database
|
||||
const requiredStores = [
|
||||
DB_CONSTANTS.PROJECTS_STORE_NAME,
|
||||
DB_CONSTANTS.CONFIG_STORE_NAME
|
||||
];
|
||||
|
||||
for (const store of requiredStores) {
|
||||
if (!db.objectStoreNames.contains(store)) {
|
||||
db.createObjectStore(store, { keyPath: 'name' })
|
||||
console.log(`Created object store: ${store}`)
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
this.dbPromises.set(key, dbPromise)
|
||||
}
|
||||
|
||||
return this.dbPromises.get(key)!
|
||||
}
|
||||
|
||||
public async save<T>(
|
||||
dbName: string,
|
||||
storeName: string,
|
||||
name: string,
|
||||
data: T,
|
||||
overwrite: boolean = false,
|
||||
version: number = 1
|
||||
): Promise<void> {
|
||||
const db = await this.getDB(dbName, storeName, version)
|
||||
const existing = await db.get(storeName, name)
|
||||
if (existing && !overwrite) {
|
||||
throw new DuplicateEntryError(name)
|
||||
}
|
||||
const entry: StorageEntry = {
|
||||
name: name,
|
||||
data: instanceToPlain(data) as Record<string, unknown>,
|
||||
lastModified: Date.now(),
|
||||
}
|
||||
await db.put(storeName, entry)
|
||||
}
|
||||
|
||||
public async load<T>(
|
||||
dbName: string,
|
||||
storeName: string,
|
||||
name: string,
|
||||
classType: new() => T,
|
||||
version: number = 1
|
||||
): Promise<T | null> {
|
||||
try {
|
||||
const db = await this.getDB(dbName, storeName, version)
|
||||
const entry = await db.get(storeName, name)
|
||||
|
||||
if (!entry?.data) {
|
||||
console.log(`No data found for entry "${name}" in store "${storeName}" of database "${dbName}"`)
|
||||
return null
|
||||
}
|
||||
|
||||
const instance = plainToClass(classType, entry.data)
|
||||
const loadedInstance = Array.isArray(instance) ? instance[0] || null : instance
|
||||
|
||||
if (loadedInstance && typeof (loadedInstance as { setName?: (projectName: string) => void }).setName === 'function') {
|
||||
(loadedInstance as { setName: (projectName: string) => void }).setName(name)
|
||||
}
|
||||
|
||||
return loadedInstance
|
||||
} catch (error) {
|
||||
console.log(`Error loading entry "${name}" from store "${storeName}" of database "${dbName}":`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
public async list(
|
||||
dbName: string,
|
||||
storeName: string,
|
||||
version: number = 1
|
||||
): Promise<string[]> {
|
||||
const db = await this.getDB(dbName, storeName, version)
|
||||
const all = await db.getAllKeys(storeName)
|
||||
return all as string[]
|
||||
}
|
||||
|
||||
public async delete(
|
||||
dbName: string,
|
||||
storeName: string,
|
||||
name: string,
|
||||
version: number = 1
|
||||
): Promise<void> {
|
||||
const db = await this.getDB(dbName, storeName, version)
|
||||
await db.delete(storeName, name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user