sitegen/src/file-viewer/models/AssetRef.ts
2025-07-07 20:58:02 -07:00

73 lines
2.2 KiB
TypeScript

const db = getDb("cache.sqlite");
db.table(
"asset_refs",
/* SQL */ `
create table if not exists asset_refs (
id integer primary key autoincrement,
key text not null UNIQUE,
refs integer not null
);
create table if not exists asset_ref_files (
file text not null,
id integer not null,
foreign key (id) references asset_refs(id) ON DELETE CASCADE
);
create index asset_ref_files_id on asset_ref_files(id);
`,
);
/**
* Uncompressed files are read directly from the media store root. Derivied
* assets like compressed files, optimized images, and streamable video are
* stored in the `derived` folder. After scanning, the derived assets are
* uploaded into the store (storage1/clofi-derived dataset on NAS). Since
* multiple files can share the same hash, the number of references is
* tracked, and the derived content is only produced once. This means if a
* file is deleted, it should only decrement a reference count; deleting it
* once all references are removed.
*/
export class AssetRef {
/** Key which aws referenced */
id!: number;
key!: string;
refs!: number;
unref() {
decrementQuery.run(this.key);
deleteUnreferencedQuery.run().changes > 0;
}
addFiles(files: string[]) {
for (const file of files) {
addFileQuery.run({ id: this.id, file });
}
}
static get(key: string) {
return getQuery.get(key);
}
static putOrIncrement(key: string) {
putOrIncrementQuery.get(key);
return UNWRAP(AssetRef.get(key));
}
}
const getQuery = db.prepare<[key: string]>(/* SQL */ `
select * from asset_refs where key = ?;
`).as(AssetRef);
const putOrIncrementQuery = db.prepare<[key: string]>(/* SQL */ `
insert into asset_refs (key, refs) values (?, 1)
on conflict(key) do update set refs = refs + 1;
`);
const decrementQuery = db.prepare<[key: string]>(/* SQL */ `
update asset_refs set refs = refs - 1 where key = ? and refs > 0;
`);
const deleteUnreferencedQuery = db.prepare(/* SQL */ `
delete from asset_refs where refs <= 0;
`);
const addFileQuery = db.prepare<[{ id: number; file: string }]>(/* SQL */ `
insert into asset_ref_files (id, file) values ($id, $file);
`);
import { getDb } from "#sitegen/sqlite";