sitegen/src/file-viewer/models/BlobAsset.ts

58 lines
1.7 KiB
TypeScript
Raw Normal View History

2025-06-21 16:04:57 -07:00
const db = getDb("cache.sqlite");
db.table(
"blob_assets",
/* SQL */ `
CREATE TABLE IF NOT EXISTS blob_assets (
hash TEXT PRIMARY KEY,
refs INTEGER NOT NULL DEFAULT 0
);
`,
);
/**
* Uncompressed files are read directly from the media store root. Compressed
* files are stored as `<compress store>/<first 2 chars of hash>/<hash>` Since
* multiple files can share the same hash, the number of references is tracked
* so that when a file is deleted, the compressed data is only removed when all
* references are gone.
*/
export class BlobAsset {
/** sha1 of the contents */
hash!: string;
refs!: number;
decrementOrDelete() {
BlobAsset.decrementOrDelete(this.hash);
}
static get(hash: string) {
return getQuery.get(hash);
}
static putOrIncrement(hash: string) {
ASSERT(hash.length === 40);
putOrIncrementQuery.get(hash);
return BlobAsset.get(hash)!;
}
static decrementOrDelete(hash: string) {
ASSERT(hash.length === 40);
decrementQuery.run(hash);
return deleteQuery.run(hash).changes > 0;
}
}
const getQuery = db.prepare<[hash: string]>(/* SQL */ `
SELECT * FROM blob_assets WHERE hash = ?;
`).as(BlobAsset);
const putOrIncrementQuery = db.prepare<[hash: string]>(/* SQL */ `
INSERT INTO blob_assets (hash, refs) VALUES (?, 1)
ON CONFLICT(hash) DO UPDATE SET refs = refs + 1;
`);
const decrementQuery = db.prepare<[hash: string]>(/* SQL */ `
UPDATE blob_assets SET refs = refs - 1 WHERE hash = ? AND refs > 0;
`);
const deleteQuery = db.prepare<[hash: string]>(/* SQL */ `
DELETE FROM blob_assets WHERE hash = ? AND refs <= 0;
`);
import { getDb } from "#sitegen/sqlite";