Files
big-agi/src/modules/dblobs/dblobs.db.ts
T
2024-06-13 16:24:06 -07:00

137 lines
4.3 KiB
TypeScript

import Dexie from 'dexie';
import { DBlobAsset, DBlobAssetId, DBlobAssetType, DBlobDBAsset } from './dblobs.types';
/**
* Dexie DB for Big-AGI
* - assets: we store large assets like images/audio/video/documents...
*
* [DEV NOTE] To delete the full DB (don't do it!):
* - indexedDB.deleteDatabase('NAME').onsuccess = console.log;
*
* [DEV NOTE] This is related to storageUtils.ts's requestPersistentStorage,
* aswe need to request persistent storage for the current origin, sot that
* indexedDB's content is not evicted.
*/
class BigAgiDB extends Dexie {
largeAssets!: Dexie.Table<DBlobDBAsset, string>;
constructor() {
super('Big-AGI');
this.version(1).stores({
// Index common properties (and compound indexes)
largeAssets: 'id, [contextId+scopeId], assetType, [assetType+contextId+scopeId], data.mimeType, origin.ot, origin.source, createdAt, updatedAt',
});
// Note: can re-add wId and uId in version 2 if needed
}
}
// In development mode, reuse the same instance of the DB to avoid re-creating it on every hot reload
const globalForDexie = globalThis as unknown as {
bigAgiDB: BigAgiDB | undefined;
};
const _db = globalForDexie.bigAgiDB ?? new BigAgiDB();
if (process.env.NODE_ENV !== 'production') globalForDexie.bigAgiDB = _db;
const assetsTable = _db.largeAssets;
// CRUD
export async function _addDBAsset<T extends DBlobAsset>(asset: T, contextId: DBlobDBAsset['contextId'], scopeId: DBlobDBAsset['scopeId']): Promise<DBlobAssetId> {
try {
// returns the id of the added asset
return await assetsTable.add({
...asset,
contextId,
scopeId,
});
} catch (error) {
console.error('addDBAsset: Error adding asset', error);
throw error;
}
}
// READ
// export async function getDBlobAssetIds(): Promise<DBlobAssetId[]> {
// return assetsTable.toCollection().primaryKeys();
// }
// async function _getDBlobAssetIdsByScope(contextId: DBlobDBAsset['contextId'], scopeId: DBlobDBAsset['scopeId']): Promise<DBlobAssetId[]> {
// return assetsTable.where({
// contextId: contextId,
// scopeId: scopeId,
// }).primaryKeys();
// }
export async function getDBAsset<T extends DBlobAsset = DBlobDBAsset>(id: DBlobAssetId) {
return await assetsTable.get(id) as T | undefined;
}
/**
* Warning: this function all the matching assets data in memory - not suitable for large datasets.
*/
// export async function getDBAssetsByType<T extends DBlobAsset = DBlobDBAsset>(assetType: T['assetType']) {
// return await assetsTable.where({
// assetType: assetType,
// }).toArray() as unknown as T[];
// }
/**
* Warning: this function all the matching assets data in memory - not suitable for large datasets.
*/
export async function getDBAssetsByScopeAndType<T extends DBlobAsset = DBlobDBAsset>(assetType: T['assetType'], contextId: DBlobDBAsset['contextId'], scopeId: DBlobDBAsset['scopeId']) {
const assets = await assetsTable.where({
assetType: assetType, contextId: contextId, scopeId: scopeId,
}).sortBy('createdAt');
return assets.reverse() as unknown as T[];
}
// UPDATE
export async function updateDBAsset<T extends DBlobAsset = DBlobDBAsset>(id: DBlobAssetId, updates: Partial<T>) {
return assetsTable.update(id, updates);
}
// DELETE
export async function deleteDBAsset(id: DBlobAssetId) {
return assetsTable.delete(id);
}
// export async function deleteDBAssets(ids: DBlobAssetId[]) {
// return assetsTable.bulkDelete(ids);
// }
// export async function deleteAllScopedAssets(contextId: DBlobDBAsset['contextId'], scopeId: DBlobDBAsset['scopeId']) {
// return (contextId && scopeId) ? assetsTable.where({
// contextId: contextId,
// scopeId: scopeId,
// }).delete() : 0;
// }
export async function gcDBAssetsByScope(contextId: DBlobDBAsset['contextId'], scopeId: DBlobDBAsset['scopeId'], assetType: DBlobAssetType | null, keepIds: DBlobAssetId[]) {
// get all the DB keys
const dbAssetIds = await assetsTable.where((assetType !== null) ? {
assetType: assetType,
contextId: contextId,
scopeId: scopeId,
} : {
contextId: contextId,
scopeId: scopeId,
}).primaryKeys();
// find the unreferenced keys
const unreferencedAssetIds = keepIds.length ? dbAssetIds.filter(id => !keepIds.includes(id)) : dbAssetIds;
// delete the unreferenced keys
if (unreferencedAssetIds.length > 0)
await assetsTable.bulkDelete(unreferencedAssetIds);
}