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";