mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Patching a bug when delete an organization, add refetch.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,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 () => {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user