57 lines
1.7 KiB
TypeScript
57 lines
1.7 KiB
TypeScript
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";
|