import { all } from "./db";
import { accountDb, repoDb } from "./scoped-db";
import { backfillDone, backfillRepos } from "./backfill";
/**
* Attachments live in each repository's RepoState but quotas are per account. Each account's AccountState keeps
* `attachment_bytes`: per repository, the bytes it owns (quota owner) and uploaded. Entries are recomputed from the
* repository's rows (never incremented), so a retry or the backfill can't double-count.
*/
export const ATTACHMENT_BYTES = "attachment-bytes";
/** Recomputes `accountIds`' entries for one repository from its attachment rows. */
export async function syncAttachmentBytes(repoId: string, accountIds: Iterable<string>): Promise<void> {
const db = repoDb(repoId);
await Promise.all(
[...new Set(accountIds)].map(async (accountId) => {
const row = await db.first<{ owned: number | null; uploaded: number | null }>(
`SELECT (SELECT SUM(size) FROM attachments WHERE owner_id = ?1) AS owned,
(SELECT SUM(size) FROM attachments WHERE uploader_id = ?1) AS uploaded`,
accountId,
);
const owned = row?.owned ?? 0;
const uploaded = row?.uploaded ?? 0;
const account = accountDb(accountId);
if (owned === 0 && uploaded === 0) {
await account.run("DELETE FROM attachment_bytes WHERE repo_id = ?", repoId);
return;
}
await account.run(
`INSERT INTO attachment_bytes (repo_id, owned, uploaded) VALUES (?, ?, ?)
ON CONFLICT (repo_id) DO UPDATE SET owned = excluded.owned, uploaded = excluded.uploaded`,
repoId,
owned,
uploaded,
);
}),
);
}
/** Before a repository's object is destroyed: its bytes stop counting for everyone who had them. */