Patching a bug when delete an organization, add refetch.

This commit is contained in:
charlesgauthereau
2025-08-27 21:16:13 +02:00
parent dd7a65262c
commit 2f9e33f4db
16 changed files with 1842 additions and 38 deletions
+50
View File
@@ -0,0 +1,50 @@
import {db} from "@/db";
import {enforceRetentionCount} from "@/lib/tasks/database/retention-count";
import {enforceRetentionDays} from "@/lib/tasks/database/retention-days";
import {enforceRetentionGFS} from "@/lib/tasks/database/retention-gsf";
import {retentionPolicy} from "@/db/schema/06_database";
export const retentionCleanTask = async () => {
try {
const databases = await db.query.database.findMany({
with: {
retentionPolicy: true,
backups: true,
},
});
for (const db of databases) {
if (!db.retentionPolicy) continue; // no policy = skip
await enforceRetention(db.id, db.retentionPolicy);
}
} catch (e: any) {
console.error("Retention cleanup failed:", e);
throw e;
}
};
export async function enforceRetention(
databaseId: string,
policy: typeof retentionPolicy.$inferSelect
) {
switch (policy.type) {
case "count":
await enforceRetentionCount(databaseId, policy.count ?? 7);
break;
case "days":
await enforceRetentionDays(databaseId, policy.days ?? 30);
break;
case "gfs":
await enforceRetentionGFS(databaseId, {
daily: policy.gfsDaily ?? 7,
weekly: policy.gfsWeekly ?? 4,
monthly: policy.gfsMonthly ?? 12,
yearly: policy.gfsYearly ?? 3,
});
break;
}
}
+17
View File
@@ -0,0 +1,17 @@
import * as drizzleDb from "@/db";
import {db} from "@/db";
import {desc, eq} from "drizzle-orm";
export async function enforceRetentionCount(databaseId: string, count: number) {
const backups = await db.query.backup.findMany({
where: eq(drizzleDb.schemas.backup.databaseId, databaseId),
orderBy: desc(drizzleDb.schemas.backup.createdAt),
});
const toDelete = backups.slice(count); // keep first `count`, delete rest
for (const b of toDelete) {
await db.delete(drizzleDb.schemas.backup).where(eq(drizzleDb.schemas.backup.id, b.id));
// TODO: delete backup file from storage
}
}
+14
View File
@@ -0,0 +1,14 @@
import {db} from "@/db";
import {eq, lt} from "drizzle-orm";
import * as drizzleDb from "@/db";
export async function enforceRetentionDays(databaseId: string, days: number) {
const cutoff = new Date(Date.now() - days * 86400000); // days → ms
await db.delete(drizzleDb.schemas.backup).where(
eq(drizzleDb.schemas.backup.databaseId, databaseId) &&
lt(drizzleDb.schemas.backup.createdAt, cutoff)
);
// Note: files should also be deleted from storage
}
+59
View File
@@ -0,0 +1,59 @@
import {db} from "@/db";
import {subDays, subWeeks, subMonths, subYears, startOfWeek, startOfMonth, startOfYear} from "date-fns";
import {eq, desc} from "drizzle-orm";
import * as drizzleDb from "@/db";
export async function enforceRetentionGFS(databaseId: string, gfsSettings: {
daily: number;
weekly: number;
monthly: number;
yearly: number;
}) {
const backups = await db.query.backup.findMany({
where: eq(drizzleDb.schemas.backup.databaseId, databaseId),
orderBy: desc(drizzleDb.schemas.backup.createdAt),
});
const now = new Date();
const toKeep: Set<string> = new Set();
// DAILY
backups.forEach((b) => {
if (b.createdAt >= subDays(now, gfsSettings.daily)) toKeep.add(b.id);
});
// WEEKLY
const weekStartDates = Array.from({length: gfsSettings.weekly}, (_, i) => startOfWeek(subWeeks(now, i)));
weekStartDates.forEach((weekStart) => {
const backupOfWeek = backups.find(
(b) => b.createdAt >= weekStart && b.createdAt < subWeeks(weekStart, -1)
);
if (backupOfWeek) toKeep.add(backupOfWeek.id);
});
// MONTHLY
const monthStartDates = Array.from({length: gfsSettings.monthly}, (_, i) => startOfMonth(subMonths(now, i)));
monthStartDates.forEach((monthStart) => {
const backupOfMonth = backups.find(
(b) => b.createdAt >= monthStart && b.createdAt < subMonths(monthStart, -1)
);
if (backupOfMonth) toKeep.add(backupOfMonth.id);
});
// YEARLY
const yearStartDates = Array.from({length: gfsSettings.yearly}, (_, i) => startOfYear(subYears(now, i)));
yearStartDates.forEach((yearStart) => {
const backupOfYear = backups.find(
(b) => b.createdAt >= yearStart && b.createdAt < subYears(yearStart, -1)
);
if (backupOfYear) toKeep.add(backupOfYear.id);
});
// Delete backups not in `toKeep`
for (const b of backups) {
if (!toKeep.has(b.id)) {
await db.delete(drizzleDb.schemas.backup).where(eq(drizzleDb.schemas.backup.id, b.id));
// TODO: delete backup file from storage
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import cron from "node-cron";
import {retentionCleanTask} from "@/lib/tasks/project";
import {retentionCleanTask} from "@/lib/tasks/database";
export const retentionJob = cron.schedule("* * * * *", async () => {
-12
View File
@@ -1,12 +0,0 @@
import {db} from "@/db";
import * as drizzleDb from "@/db";
export const retentionCleanTask = async () => {
try {
const projects = await db.query.project.findMany();
console.log(projects);
} catch (e: any) {
throw e;
}
}