2026-05-21 07:51:08 +02:00
|
|
|
import {pgTable, text, boolean, timestamp, uuid, integer, pgEnum, bigint} from "drizzle-orm/pg-core";
|
2026-04-10 18:37:35 +02:00
|
|
|
import {Agent, agent, AgentWith} from "./08_agent";
|
2025-08-29 15:31:23 +02:00
|
|
|
import {Project, project} from "./06_project";
|
2025-08-02 20:13:29 +02:00
|
|
|
import {relations} from "drizzle-orm";
|
|
|
|
|
import {dbmsEnum, statusEnum} from "./types";
|
|
|
|
|
import {createSelectSchema} from "drizzle-zod";
|
|
|
|
|
import {z} from "zod";
|
2025-08-29 15:31:23 +02:00
|
|
|
import {timestamps} from "@/db/schema/00_common";
|
2025-11-23 17:13:07 +01:00
|
|
|
import {AlertPolicy, alertPolicy} from "@/db/schema/10_alert-policy";
|
2026-01-13 22:22:01 +01:00
|
|
|
import {StoragePolicy, storagePolicy} from "@/db/schema/13_storage-policy";
|
2026-01-17 15:57:37 +01:00
|
|
|
import {BackupStorage, backupStorage} from "@/db/schema/14_storage-backup";
|
2026-06-06 22:46:36 +02:00
|
|
|
import {JobLog, jobLog} from "@/db/schema/17_job-log";
|
2025-05-16 15:54:17 +02:00
|
|
|
|
|
|
|
|
export const database = pgTable("databases", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
2026-07-05 17:10:55 +02:00
|
|
|
agentDatabaseId: uuid("agent_database_id").defaultRandom(),
|
2025-05-16 15:54:17 +02:00
|
|
|
name: text("name").notNull(),
|
|
|
|
|
dbms: dbmsEnum("dbms").notNull(),
|
2025-07-16 18:15:28 +02:00
|
|
|
description: text("description"),
|
2025-05-16 15:54:17 +02:00
|
|
|
backupPolicy: text("backup_policy"),
|
|
|
|
|
isWaitingForBackup: boolean("is_waiting_for_backup").default(false).notNull(),
|
|
|
|
|
backupToRestore: text("backup_to_restore"),
|
2026-03-28 16:35:02 +01:00
|
|
|
healthErrorCount: integer("health_error_count"),
|
2025-05-16 15:54:17 +02:00
|
|
|
agentId: uuid("agent_id")
|
2025-08-02 20:13:29 +02:00
|
|
|
.references(() => agent.id, {onDelete: "cascade"}),
|
2025-05-16 15:54:17 +02:00
|
|
|
lastContact: timestamp("last_contact"),
|
|
|
|
|
projectId: uuid("project_id")
|
2025-07-16 18:15:28 +02:00
|
|
|
.references(() => project.id),
|
2025-08-29 15:31:23 +02:00
|
|
|
...timestamps
|
2025-08-27 21:16:13 +02:00
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
});
|
|
|
|
|
|
2025-11-23 17:13:07 +01:00
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
export const backup = pgTable(
|
|
|
|
|
"backups",
|
|
|
|
|
{
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
status: statusEnum("status").default("waiting").notNull(),
|
|
|
|
|
file: text("file"),
|
2026-05-21 07:51:08 +02:00
|
|
|
fileSize: bigint("file_size", { mode: "number" }),
|
2026-06-06 22:46:36 +02:00
|
|
|
durationMs: bigint("duration_ms", { mode: "number" }),
|
2025-05-16 15:54:17 +02:00
|
|
|
databaseId: uuid("database_id")
|
|
|
|
|
.notNull()
|
2025-08-02 20:13:29 +02:00
|
|
|
.references(() => database.id, {onDelete: "cascade"}),
|
2026-01-17 20:56:57 +01:00
|
|
|
imported: boolean('imported').default(false),
|
2026-04-29 22:39:37 +02:00
|
|
|
migrated: boolean('migrated').default(false),
|
2025-08-29 15:31:23 +02:00
|
|
|
...timestamps
|
2025-05-16 15:54:17 +02:00
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
|
2025-08-27 21:16:13 +02:00
|
|
|
export const retentionPolicyType = pgEnum("retention_policy_type", ["count", "days", "gfs"]);
|
|
|
|
|
|
|
|
|
|
export const retentionPolicy = pgTable("retention_policies", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
databaseId: uuid("database_id").notNull().references(() => database.id, {onDelete: "cascade"}),
|
|
|
|
|
type: retentionPolicyType("type").notNull(),
|
|
|
|
|
count: integer("count").default(7), // for "count"
|
|
|
|
|
days: integer("days").default(30), // for "days"
|
|
|
|
|
gfsDaily: integer("gfs_daily").default(7),
|
|
|
|
|
gfsWeekly: integer("gfs_weekly").default(4),
|
|
|
|
|
gfsMonthly: integer("gfs_monthly").default(12),
|
|
|
|
|
gfsYearly: integer("gfs_yearly").default(3),
|
2025-08-29 15:31:23 +02:00
|
|
|
...timestamps
|
2025-08-27 21:16:13 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
export const restoration = pgTable("restorations", {
|
|
|
|
|
id: uuid("id").primaryKey().defaultRandom(),
|
|
|
|
|
status: statusEnum("status").default("waiting").notNull(),
|
2026-06-07 11:15:21 +02:00
|
|
|
durationMs: bigint("duration_ms", { mode: "number" }),
|
2026-01-17 17:27:33 +01:00
|
|
|
backupStorageId: uuid("backup_storage_id")
|
|
|
|
|
.references(() => backupStorage.id, {onDelete: "cascade"}),
|
2025-05-16 15:54:17 +02:00
|
|
|
backupId: uuid("backup_id")
|
|
|
|
|
.notNull()
|
2025-08-02 20:13:29 +02:00
|
|
|
.references(() => backup.id, {onDelete: "cascade"}),
|
|
|
|
|
databaseId: uuid("database_id").references(() => database.id, {onDelete: "cascade"}),
|
2025-08-29 15:31:23 +02:00
|
|
|
...timestamps
|
|
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
});
|
|
|
|
|
|
2025-08-02 20:13:29 +02:00
|
|
|
export const databaseRelations = relations(database, ({one, many}) => ({
|
2025-09-14 16:46:23 +02:00
|
|
|
retentionPolicy: one(retentionPolicy, {
|
|
|
|
|
fields: [database.id],
|
|
|
|
|
references: [retentionPolicy.databaseId],
|
|
|
|
|
}),
|
2025-08-02 20:13:29 +02:00
|
|
|
agent: one(agent, {fields: [database.agentId], references: [agent.id]}),
|
|
|
|
|
project: one(project, {fields: [database.projectId], references: [project.id]}),
|
2025-05-16 15:54:17 +02:00
|
|
|
backups: many(backup),
|
|
|
|
|
restorations: many(restoration),
|
2025-11-23 17:13:07 +01:00
|
|
|
alertPolicies: many(alertPolicy),
|
2026-01-13 22:22:01 +01:00
|
|
|
storagePolicies: many(storagePolicy),
|
2025-05-16 15:54:17 +02:00
|
|
|
}));
|
|
|
|
|
|
2025-08-02 20:13:29 +02:00
|
|
|
export const backupRelations = relations(backup, ({one, many}) => ({
|
|
|
|
|
database: one(database, {fields: [backup.databaseId], references: [database.id]}),
|
2025-05-16 15:54:17 +02:00
|
|
|
restorations: many(restoration),
|
2026-01-14 21:54:13 +01:00
|
|
|
storages: many(backupStorage),
|
2026-06-06 22:46:36 +02:00
|
|
|
logs: many(jobLog),
|
|
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
}));
|
|
|
|
|
|
2026-06-06 22:46:36 +02:00
|
|
|
export const restorationRelations = relations(restoration, ({one, many}) => ({
|
2025-08-02 20:13:29 +02:00
|
|
|
backup: one(backup, {fields: [restoration.backupId], references: [backup.id]}),
|
|
|
|
|
database: one(database, {fields: [restoration.databaseId], references: [database.id]}),
|
2026-01-17 17:27:33 +01:00
|
|
|
backupStorage: one(backupStorage, {fields: [restoration.backupStorageId], references: [backupStorage.id]}),
|
2026-06-06 22:46:36 +02:00
|
|
|
logs: many(jobLog),
|
2025-05-16 15:54:17 +02:00
|
|
|
}));
|
|
|
|
|
|
2025-09-14 16:46:23 +02:00
|
|
|
|
|
|
|
|
export const retentionPolicyRelations = relations(retentionPolicy, ({one}) => ({
|
|
|
|
|
database: one(database, {
|
|
|
|
|
fields: [retentionPolicy.databaseId],
|
|
|
|
|
references: [database.id],
|
|
|
|
|
}),
|
|
|
|
|
}));
|
|
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
export const databaseSchema = createSelectSchema(database);
|
|
|
|
|
export type Database = z.infer<typeof databaseSchema>;
|
|
|
|
|
|
|
|
|
|
export const backupSchema = createSelectSchema(backup);
|
|
|
|
|
export type Backup = z.infer<typeof backupSchema>;
|
|
|
|
|
|
|
|
|
|
export const restorationSchema = createSelectSchema(restoration);
|
|
|
|
|
export type Restoration = z.infer<typeof restorationSchema>;
|
|
|
|
|
|
2025-08-27 21:16:13 +02:00
|
|
|
export const retentionPolicySchema = createSelectSchema(retentionPolicy);
|
|
|
|
|
export type RetentionPolicy = z.infer<typeof retentionPolicySchema>;
|
|
|
|
|
|
|
|
|
|
|
2025-05-16 15:54:17 +02:00
|
|
|
export type DatabaseWith = Database & {
|
2026-04-10 18:37:35 +02:00
|
|
|
agent?: Agent | AgentWith | null;
|
2025-08-02 20:13:29 +02:00
|
|
|
project?: Project | null;
|
|
|
|
|
backups?: Backup[] | null;
|
|
|
|
|
restorations?: Restoration[] | null;
|
2025-08-27 21:16:13 +02:00
|
|
|
retentionPolicy?: RetentionPolicy | null;
|
2025-11-23 17:13:07 +01:00
|
|
|
alertPolicies?: AlertPolicy[] | null;
|
2026-01-13 22:22:01 +01:00
|
|
|
storagePolicies?: StoragePolicy[] | null;
|
2025-05-16 15:54:17 +02:00
|
|
|
};
|
2025-08-02 20:13:29 +02:00
|
|
|
|
2026-01-17 15:57:37 +01:00
|
|
|
|
|
|
|
|
export type BackupWith = Backup & {
|
|
|
|
|
restorations?: Restoration[] | null;
|
|
|
|
|
storages?: BackupStorage[] | null;
|
2026-06-06 22:46:36 +02:00
|
|
|
logs?: JobLog[] | null;
|
2026-07-07 19:39:25 +02:00
|
|
|
hasLogs?: boolean;
|
2026-06-07 11:15:21 +02:00
|
|
|
};
|
2026-06-06 22:46:36 +02:00
|
|
|
|
2026-06-07 11:15:21 +02:00
|
|
|
export type RestorationWith = Restoration & {
|
|
|
|
|
logs?: JobLog[] | null;
|
2026-07-07 19:39:25 +02:00
|
|
|
hasLogs?: boolean;
|
2026-01-17 15:57:37 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2026-06-07 11:15:21 +02:00
|
|
|
|