Skip to content
File

Blob: src/worker/do/repo/db/dal/packCatalog.ts

typescript104 lines
1import type { DrizzleSqliteDODatabase } from "drizzle-orm/durable-sqlite";
2import type { PackCatalogRow } from "../schema";
3 
4import { desc, eq, inArray, sql } from "drizzle-orm";
5import { packCatalog } from "../schema";
6import { SAFE_ROWS_1COL } from "./shared";
7 
8export async function getPackCatalogCount(db: DrizzleSqliteDODatabase): Promise<number> {
9 return await db.$count(packCatalog);
10}
11 
12/** Count only active (non-superseded) packs — used by idle cleanup to determine repo emptiness. */
13export async function getActivePackCatalogCount(db: DrizzleSqliteDODatabase): Promise<number> {
14 const rows = await db
15 .select({ count: sql<number>`count(*)` })
16 .from(packCatalog)
17 .where(eq(packCatalog.state, "active"));
18 return rows[0]?.count ?? 0;
19}
20 
21export async function listPackCatalog(db: DrizzleSqliteDODatabase): Promise<PackCatalogRow[]> {
22 return await db
23 .select()
24 .from(packCatalog)
25 .orderBy(desc(packCatalog.seqHi), desc(packCatalog.tier));
26}
27 
28export async function listActivePackCatalog(
29 db: DrizzleSqliteDODatabase
30): Promise<PackCatalogRow[]> {
31 return await db
32 .select()
33 .from(packCatalog)
34 .where(eq(packCatalog.state, "active"))
35 .orderBy(desc(packCatalog.seqHi), desc(packCatalog.tier));
36}
37 
38export async function getPackCatalogRow(
39 db: DrizzleSqliteDODatabase,
40 packKey: string
41): Promise<PackCatalogRow | undefined> {
42 const rows = await db.select().from(packCatalog).where(eq(packCatalog.packKey, packKey)).limit(1);
43 return rows[0];
44}
45 
46export async function getPackCatalogSeqMax(db: DrizzleSqliteDODatabase): Promise<number> {
47 const rows = await db
48 .select({
49 maxSeqHi: sql<number>`coalesce(max(${packCatalog.seqHi}), 0)`,
50 })
51 .from(packCatalog);
52 return rows[0]?.maxSeqHi || 0;
53}
54 
55export async function upsertPackCatalogRow(
56 db: DrizzleSqliteDODatabase,
57 row: PackCatalogRow
58): Promise<void> {
59 await db
60 .insert(packCatalog)
61 .values(row)
62 .onConflictDoUpdate({
63 target: packCatalog.packKey,
64 set: {
65 kind: row.kind,
66 state: row.state,
67 tier: row.tier,
68 seqLo: row.seqLo,
69 seqHi: row.seqHi,
70 objectCount: row.objectCount,
71 packBytes: row.packBytes,
72 idxBytes: row.idxBytes,
73 createdAt: row.createdAt,
74 supersededBy: row.supersededBy,
75 },
76 });
77}
78 
79export async function supersedePackCatalogRows(
80 db: DrizzleSqliteDODatabase,
81 packKeys: string[],
82 supersededBy: string | null = null
83): Promise<void> {
84 if (!packKeys.length) return;
85 for (let i = 0; i < packKeys.length; i += SAFE_ROWS_1COL) {
86 const batch = packKeys.slice(i, i + SAFE_ROWS_1COL);
87 await db
88 .update(packCatalog)
89 .set({ state: "superseded", supersededBy })
90 .where(inArray(packCatalog.packKey, batch));
91 }
92}
93 
94export async function deletePackCatalogRows(
95 db: DrizzleSqliteDODatabase,
96 packKeys: string[]
97): Promise<void> {
98 if (!packKeys.length) return;
99 for (let i = 0; i < packKeys.length; i += SAFE_ROWS_1COL) {
100 const batch = packKeys.slice(i, i + SAFE_ROWS_1COL);
101 await db.delete(packCatalog).where(inArray(packCatalog.packKey, batch));
102 }
103}