refactor: tag snapshots with schedule short_id instead of db id (#248)

* refactor: tag snapshots with schedule short_id instead of db id

* chore: formatting issues
This commit is contained in:
Nico 2025-12-28 11:42:25 +01:00 committed by GitHub
parent 54068d5269
commit ae5233d9fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 8885 additions and 7758 deletions

View file

@ -1390,6 +1390,7 @@ export type ListBackupSchedulesResponses = {
keepWithinDuration?: string; keepWithinDuration?: string;
keepYearly?: number; keepYearly?: number;
} | null; } | null;
shortId: string;
updatedAt: number; updatedAt: number;
volume: { volume: {
autoRemount: boolean; autoRemount: boolean;
@ -1500,6 +1501,7 @@ export type CreateBackupScheduleResponses = {
keepWithinDuration?: string; keepWithinDuration?: string;
keepYearly?: number; keepYearly?: number;
} | null; } | null;
shortId: string;
updatedAt: number; updatedAt: number;
volumeId: number; volumeId: number;
}; };
@ -1637,6 +1639,7 @@ export type GetBackupScheduleResponses = {
keepWithinDuration?: string; keepWithinDuration?: string;
keepYearly?: number; keepYearly?: number;
} | null; } | null;
shortId: string;
updatedAt: number; updatedAt: number;
volume: { volume: {
autoRemount: boolean; autoRemount: boolean;
@ -1748,6 +1751,7 @@ export type UpdateBackupScheduleResponses = {
keepWithinDuration?: string; keepWithinDuration?: string;
keepYearly?: number; keepYearly?: number;
} | null; } | null;
shortId: string;
updatedAt: number; updatedAt: number;
volumeId: number; volumeId: number;
}; };
@ -1865,6 +1869,7 @@ export type GetBackupScheduleForVolumeResponses = {
keepWithinDuration?: string; keepWithinDuration?: string;
keepYearly?: number; keepYearly?: number;
} | null; } | null;
shortId: string;
updatedAt: number; updatedAt: number;
volume: { volume: {
autoRemount: boolean; autoRemount: boolean;

View file

@ -85,8 +85,7 @@ export const SnapshotsTable = ({ snapshots, repositoryId, backups }: Props) => {
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{snapshots.map((snapshot) => { {snapshots.map((snapshot) => {
const backupIds = snapshot.tags.map(Number).filter((tag) => !Number.isNaN(tag)); const backup = backups.find((b) => snapshot.tags.includes(b.shortId));
const backup = backups.find((b) => backupIds.includes(b.id));
return ( return (
<TableRow <TableRow

View file

@ -80,7 +80,7 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
isLoading, isLoading,
failureReason, failureReason,
} = useQuery({ } = useQuery({
...listSnapshotsOptions({ path: { id: schedule.repository.id }, query: { backupId: schedule.id.toString() } }), ...listSnapshotsOptions({ path: { id: schedule.repository.id }, query: { backupId: schedule.shortId } }),
}); });
const updateSchedule = useMutation({ const updateSchedule = useMutation({

View file

@ -25,7 +25,7 @@ import { cn } from "~/client/lib/utils";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/client/components/ui/tabs";
import { RepositoryInfoTabContent } from "../tabs/info"; import { RepositoryInfoTabContent } from "../tabs/info";
import { RepositorySnapshotsTabContent } from "../tabs/snapshots"; import { RepositorySnapshotsTabContent } from "../tabs/snapshots";
import { Loader2, Stethoscope, Trash2, X } from "lucide-react"; import { Loader2, Stethoscope, Trash2 } from "lucide-react";
export const handle = { export const handle = {
breadcrumb: (match: Route.MetaArgs) => [ breadcrumb: (match: Route.MetaArgs) => [

View file

@ -116,8 +116,7 @@ export default function SnapshotDetailsPage({ loaderData }: Route.ComponentProps
{(value) => { {(value) => {
if (!value.data) return null; if (!value.data) return null;
const backupIds = value.data.tags.map(Number).filter((tag) => !Number.isNaN(tag)); const backupSchedule = schedules.data?.find((s) => value.data.tags.includes(s.shortId));
const backupSchedule = schedules.data?.find((s) => backupIds.includes(s.id));
return ( return (
<> <>

View file

@ -29,8 +29,7 @@ export const RepositorySnapshotsTabContent = ({ repository }: Props) => {
if (!searchQuery) return true; if (!searchQuery) return true;
const searchLower = searchQuery.toLowerCase(); const searchLower = searchQuery.toLowerCase();
const backupIds = snapshot.tags.map(Number).filter((tag) => !Number.isNaN(tag)); const backup = schedules.data?.find((b) => snapshot.tags.includes(b.shortId));
const backup = schedules.data?.find((b) => backupIds.includes(b.id));
return ( return (
snapshot.short_id.toLowerCase().includes(searchLower) || snapshot.short_id.toLowerCase().includes(searchLower) ||

View file

@ -0,0 +1,3 @@
ALTER TABLE `backup_schedules_table` ADD `short_id` text;--> statement-breakpoint
UPDATE `backup_schedules_table` SET `short_id` = lower(hex(randomblob(4))) WHERE `short_id` IS NULL;--> statement-breakpoint
CREATE UNIQUE INDEX `backup_schedules_table_short_id_unique` ON `backup_schedules_table` (`short_id`);

View file

@ -0,0 +1,31 @@
PRAGMA foreign_keys=OFF;--> statement-breakpoint
CREATE TABLE `__new_backup_schedules_table` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`short_id` text NOT NULL,
`name` text NOT NULL,
`volume_id` integer NOT NULL,
`repository_id` text NOT NULL,
`enabled` integer DEFAULT true NOT NULL,
`cron_expression` text NOT NULL,
`retention_policy` text,
`exclude_patterns` text DEFAULT '[]',
`exclude_if_present` text DEFAULT '[]',
`include_patterns` text DEFAULT '[]',
`last_backup_at` integer,
`last_backup_status` text,
`last_backup_error` text,
`next_backup_at` integer,
`one_file_system` integer DEFAULT false NOT NULL,
`sort_order` integer DEFAULT 0 NOT NULL,
`created_at` integer DEFAULT (unixepoch() * 1000) NOT NULL,
`updated_at` integer DEFAULT (unixepoch() * 1000) NOT NULL,
FOREIGN KEY (`volume_id`) REFERENCES `volumes_table`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`repository_id`) REFERENCES `repositories_table`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
INSERT INTO `__new_backup_schedules_table`("id", "short_id", "name", "volume_id", "repository_id", "enabled", "cron_expression", "retention_policy", "exclude_patterns", "exclude_if_present", "include_patterns", "last_backup_at", "last_backup_status", "last_backup_error", "next_backup_at", "one_file_system", "sort_order", "created_at", "updated_at") SELECT "id", "short_id", "name", "volume_id", "repository_id", "enabled", "cron_expression", "retention_policy", "exclude_patterns", "exclude_if_present", "include_patterns", "last_backup_at", "last_backup_status", "last_backup_error", "next_backup_at", "one_file_system", "sort_order", "created_at", "updated_at" FROM `backup_schedules_table`;--> statement-breakpoint
DROP TABLE `backup_schedules_table`;--> statement-breakpoint
ALTER TABLE `__new_backup_schedules_table` RENAME TO `backup_schedules_table`;--> statement-breakpoint
PRAGMA foreign_keys=ON;--> statement-breakpoint
CREATE UNIQUE INDEX `backup_schedules_table_short_id_unique` ON `backup_schedules_table` (`short_id`);--> statement-breakpoint
CREATE UNIQUE INDEX `backup_schedules_table_name_unique` ON `backup_schedules_table` (`name`);

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -204,12 +193,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -217,22 +202,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -352,12 +330,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -365,12 +339,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -438,9 +408,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -537,16 +505,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -594,12 +558,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -660,9 +620,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -760,16 +718,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -204,12 +193,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -217,22 +202,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -356,9 +334,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -367,12 +343,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -380,12 +352,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -453,9 +421,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -552,16 +518,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -609,12 +571,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -675,9 +633,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -775,16 +731,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -204,12 +193,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -217,22 +202,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -364,9 +342,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -375,12 +351,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -388,12 +360,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -461,9 +429,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -560,16 +526,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -617,12 +579,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -683,9 +641,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -783,16 +739,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -212,12 +201,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -225,22 +210,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -372,9 +350,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -383,12 +359,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -396,12 +368,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -469,9 +437,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -568,16 +534,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -625,12 +587,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -691,9 +649,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -791,16 +747,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -212,12 +201,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -225,22 +210,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -380,9 +358,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -391,12 +367,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -404,12 +376,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -477,9 +445,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -576,16 +542,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -633,12 +595,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -699,9 +657,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -799,16 +755,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -212,12 +201,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -225,22 +210,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -388,9 +366,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -399,12 +375,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -412,12 +384,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -485,9 +453,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -584,16 +550,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -641,12 +603,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -707,9 +665,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -807,16 +763,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -120,26 +117,18 @@
"backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk": { "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id"
],
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
}, },
"backup_schedule_mirrors_table_repository_id_repositories_table_id_fk": { "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id"
],
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
@ -211,36 +200,25 @@
"backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk": { "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id"
],
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
}, },
"backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk": { "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk": {
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id"
],
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -388,9 +366,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -398,26 +374,18 @@
"backup_schedules_table_volume_id_volumes_table_id_fk": { "backup_schedules_table_volume_id_volumes_table_id_fk": {
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id"
],
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
}, },
"backup_schedules_table_repository_id_repositories_table_id_fk": { "backup_schedules_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id"
],
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
@ -485,9 +453,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -584,16 +550,12 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"repositories_table_name_unique": { "repositories_table_name_unique": {
"name": "repositories_table_name_unique", "name": "repositories_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -640,13 +602,9 @@
"sessions_table_user_id_users_table_id_fk": { "sessions_table_user_id_users_table_id_fk": {
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id"
],
"tableTo": "users_table", "tableTo": "users_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
@ -707,9 +665,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -807,16 +763,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -121,12 +118,8 @@
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -134,12 +127,8 @@
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -212,12 +201,8 @@
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -225,22 +210,15 @@
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -388,9 +366,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -399,12 +375,8 @@
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
}, },
@ -412,12 +384,8 @@
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -485,9 +453,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -584,9 +550,7 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -634,12 +598,8 @@
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"tableTo": "users_table", "tableTo": "users_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id" "columnsTo": ["id"],
],
"columnsTo": [
"id"
],
"onDelete": "cascade", "onDelete": "cascade",
"onUpdate": "no action" "onUpdate": "no action"
} }
@ -700,9 +660,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -800,16 +758,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -109,10 +109,7 @@
"indexes": { "indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": { "backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique", "name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": [ "columns": ["schedule_id", "repository_id"],
"schedule_id",
"repository_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -120,26 +117,18 @@
"backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk": { "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id"
],
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
}, },
"backup_schedule_mirrors_table_repository_id_repositories_table_id_fk": { "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk", "name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table", "tableFrom": "backup_schedule_mirrors_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id"
],
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
@ -211,36 +200,25 @@
"backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk": { "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk", "name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"columnsFrom": [ "columnsFrom": ["schedule_id"],
"schedule_id"
],
"tableTo": "backup_schedules_table", "tableTo": "backup_schedules_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
}, },
"backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk": { "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk": {
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk", "name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table", "tableFrom": "backup_schedule_notifications_table",
"columnsFrom": [ "columnsFrom": ["destination_id"],
"destination_id"
],
"tableTo": "notification_destinations_table", "tableTo": "notification_destinations_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
}, },
"compositePrimaryKeys": { "compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": { "backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": [ "columns": ["schedule_id", "destination_id"],
"schedule_id",
"destination_id"
],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk" "name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
} }
}, },
@ -388,9 +366,7 @@
"indexes": { "indexes": {
"backup_schedules_table_name_unique": { "backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique", "name": "backup_schedules_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -398,26 +374,18 @@
"backup_schedules_table_volume_id_volumes_table_id_fk": { "backup_schedules_table_volume_id_volumes_table_id_fk": {
"name": "backup_schedules_table_volume_id_volumes_table_id_fk", "name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["volume_id"],
"volume_id"
],
"tableTo": "volumes_table", "tableTo": "volumes_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
}, },
"backup_schedules_table_repository_id_repositories_table_id_fk": { "backup_schedules_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedules_table_repository_id_repositories_table_id_fk", "name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table", "tableFrom": "backup_schedules_table",
"columnsFrom": [ "columnsFrom": ["repository_id"],
"repository_id"
],
"tableTo": "repositories_table", "tableTo": "repositories_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
@ -485,9 +453,7 @@
"indexes": { "indexes": {
"notification_destinations_table_name_unique": { "notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique", "name": "notification_destinations_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },
@ -584,9 +550,7 @@
"indexes": { "indexes": {
"repositories_table_short_id_unique": { "repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique", "name": "repositories_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
} }
}, },
@ -633,13 +597,9 @@
"sessions_table_user_id_users_table_id_fk": { "sessions_table_user_id_users_table_id_fk": {
"name": "sessions_table_user_id_users_table_id_fk", "name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table", "tableFrom": "sessions_table",
"columnsFrom": [ "columnsFrom": ["user_id"],
"user_id"
],
"tableTo": "users_table", "tableTo": "users_table",
"columnsTo": [ "columnsTo": ["id"],
"id"
],
"onUpdate": "no action", "onUpdate": "no action",
"onDelete": "cascade" "onDelete": "cascade"
} }
@ -700,9 +660,7 @@
"indexes": { "indexes": {
"users_table_username_unique": { "users_table_username_unique": {
"name": "users_table_username_unique", "name": "users_table_username_unique",
"columns": [ "columns": ["username"],
"username"
],
"isUnique": true "isUnique": true
} }
}, },
@ -800,16 +758,12 @@
"indexes": { "indexes": {
"volumes_table_short_id_unique": { "volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique", "name": "volumes_table_short_id_unique",
"columns": [ "columns": ["short_id"],
"short_id"
],
"isUnique": true "isUnique": true
}, },
"volumes_table_name_unique": { "volumes_table_name_unique": {
"name": "volumes_table_name_unique", "name": "volumes_table_name_unique",
"columns": [ "columns": ["name"],
"name"
],
"isUnique": true "isUnique": true
} }
}, },

View file

@ -0,0 +1,798 @@
{
"version": "6",
"dialect": "sqlite",
"id": "94ebc8c3-f11f-48cb-9814-d8d550422d26",
"prevId": "19421265-4e3a-46b8-9ca1-a01d1e293dbc",
"tables": {
"app_metadata": {
"name": "app_metadata",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"backup_schedule_mirrors_table": {
"name": "backup_schedule_mirrors_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"schedule_id": {
"name": "schedule_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"repository_id": {
"name": "repository_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"last_copy_at": {
"name": "last_copy_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_copy_status": {
"name": "last_copy_status",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_copy_error": {
"name": "last_copy_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": ["schedule_id", "repository_id"],
"isUnique": true
}
},
"foreignKeys": {
"backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table",
"columnsFrom": ["schedule_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"backup_schedule_mirrors_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table",
"columnsFrom": ["repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"backup_schedule_notifications_table": {
"name": "backup_schedule_notifications_table",
"columns": {
"schedule_id": {
"name": "schedule_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"destination_id": {
"name": "destination_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"notify_on_start": {
"name": "notify_on_start",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"notify_on_success": {
"name": "notify_on_success",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"notify_on_warning": {
"name": "notify_on_warning",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"notify_on_failure": {
"name": "notify_on_failure",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {},
"foreignKeys": {
"backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table",
"columnsFrom": ["schedule_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk": {
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table",
"columnsFrom": ["destination_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": ["schedule_id", "destination_id"],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"backup_schedules_table": {
"name": "backup_schedules_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"short_id": {
"name": "short_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"volume_id": {
"name": "volume_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"repository_id": {
"name": "repository_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"cron_expression": {
"name": "cron_expression",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"retention_policy": {
"name": "retention_policy",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"exclude_patterns": {
"name": "exclude_patterns",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'[]'"
},
"exclude_if_present": {
"name": "exclude_if_present",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'[]'"
},
"include_patterns": {
"name": "include_patterns",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'[]'"
},
"last_backup_at": {
"name": "last_backup_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_backup_status": {
"name": "last_backup_status",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_backup_error": {
"name": "last_backup_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"next_backup_at": {
"name": "next_backup_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"one_file_system": {
"name": "one_file_system",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"sort_order": {
"name": "sort_order",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"backup_schedules_table_short_id_unique": {
"name": "backup_schedules_table_short_id_unique",
"columns": ["short_id"],
"isUnique": true
},
"backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique",
"columns": ["name"],
"isUnique": true
}
},
"foreignKeys": {
"backup_schedules_table_volume_id_volumes_table_id_fk": {
"name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table",
"tableTo": "volumes_table",
"columnsFrom": ["volume_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"backup_schedules_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table",
"tableTo": "repositories_table",
"columnsFrom": ["repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"notification_destinations_table": {
"name": "notification_destinations_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique",
"columns": ["name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"repositories_table": {
"name": "repositories_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"short_id": {
"name": "short_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"compression_mode": {
"name": "compression_mode",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'auto'"
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'unknown'"
},
"last_checked": {
"name": "last_checked",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_error": {
"name": "last_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique",
"columns": ["short_id"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"sessions_table": {
"name": "sessions_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {},
"foreignKeys": {
"sessions_table_user_id_users_table_id_fk": {
"name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table",
"tableTo": "users_table",
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users_table": {
"name": "users_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"password_hash": {
"name": "password_hash",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"has_downloaded_restic_password": {
"name": "has_downloaded_restic_password",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"users_table_username_unique": {
"name": "users_table_username_unique",
"columns": ["username"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"volumes_table": {
"name": "volumes_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"short_id": {
"name": "short_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'unmounted'"
},
"last_error": {
"name": "last_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_health_check": {
"name": "last_health_check",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"auto_remount": {
"name": "auto_remount",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
}
},
"indexes": {
"volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique",
"columns": ["short_id"],
"isUnique": true
},
"volumes_table_name_unique": {
"name": "volumes_table_name_unique",
"columns": ["name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View file

@ -0,0 +1,798 @@
{
"version": "6",
"dialect": "sqlite",
"id": "2837bed4-34fb-4d16-b331-7b6d483979bc",
"prevId": "94ebc8c3-f11f-48cb-9814-d8d550422d26",
"tables": {
"app_metadata": {
"name": "app_metadata",
"columns": {
"key": {
"name": "key",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"backup_schedule_mirrors_table": {
"name": "backup_schedule_mirrors_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"schedule_id": {
"name": "schedule_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"repository_id": {
"name": "repository_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"last_copy_at": {
"name": "last_copy_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_copy_status": {
"name": "last_copy_status",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_copy_error": {
"name": "last_copy_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"backup_schedule_mirrors_table_schedule_id_repository_id_unique": {
"name": "backup_schedule_mirrors_table_schedule_id_repository_id_unique",
"columns": ["schedule_id", "repository_id"],
"isUnique": true
}
},
"foreignKeys": {
"backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_mirrors_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table",
"tableTo": "backup_schedules_table",
"columnsFrom": ["schedule_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"backup_schedule_mirrors_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedule_mirrors_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedule_mirrors_table",
"tableTo": "repositories_table",
"columnsFrom": ["repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"backup_schedule_notifications_table": {
"name": "backup_schedule_notifications_table",
"columns": {
"schedule_id": {
"name": "schedule_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"destination_id": {
"name": "destination_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"notify_on_start": {
"name": "notify_on_start",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"notify_on_success": {
"name": "notify_on_success",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"notify_on_warning": {
"name": "notify_on_warning",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"notify_on_failure": {
"name": "notify_on_failure",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {},
"foreignKeys": {
"backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk": {
"name": "backup_schedule_notifications_table_schedule_id_backup_schedules_table_id_fk",
"tableFrom": "backup_schedule_notifications_table",
"tableTo": "backup_schedules_table",
"columnsFrom": ["schedule_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk": {
"name": "backup_schedule_notifications_table_destination_id_notification_destinations_table_id_fk",
"tableFrom": "backup_schedule_notifications_table",
"tableTo": "notification_destinations_table",
"columnsFrom": ["destination_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"backup_schedule_notifications_table_schedule_id_destination_id_pk": {
"columns": ["schedule_id", "destination_id"],
"name": "backup_schedule_notifications_table_schedule_id_destination_id_pk"
}
},
"uniqueConstraints": {},
"checkConstraints": {}
},
"backup_schedules_table": {
"name": "backup_schedules_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"short_id": {
"name": "short_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"volume_id": {
"name": "volume_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"repository_id": {
"name": "repository_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"cron_expression": {
"name": "cron_expression",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"retention_policy": {
"name": "retention_policy",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"exclude_patterns": {
"name": "exclude_patterns",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'[]'"
},
"exclude_if_present": {
"name": "exclude_if_present",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'[]'"
},
"include_patterns": {
"name": "include_patterns",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'[]'"
},
"last_backup_at": {
"name": "last_backup_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_backup_status": {
"name": "last_backup_status",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_backup_error": {
"name": "last_backup_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"next_backup_at": {
"name": "next_backup_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"one_file_system": {
"name": "one_file_system",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"sort_order": {
"name": "sort_order",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"backup_schedules_table_short_id_unique": {
"name": "backup_schedules_table_short_id_unique",
"columns": ["short_id"],
"isUnique": true
},
"backup_schedules_table_name_unique": {
"name": "backup_schedules_table_name_unique",
"columns": ["name"],
"isUnique": true
}
},
"foreignKeys": {
"backup_schedules_table_volume_id_volumes_table_id_fk": {
"name": "backup_schedules_table_volume_id_volumes_table_id_fk",
"tableFrom": "backup_schedules_table",
"tableTo": "volumes_table",
"columnsFrom": ["volume_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"backup_schedules_table_repository_id_repositories_table_id_fk": {
"name": "backup_schedules_table_repository_id_repositories_table_id_fk",
"tableFrom": "backup_schedules_table",
"tableTo": "repositories_table",
"columnsFrom": ["repository_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"notification_destinations_table": {
"name": "notification_destinations_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"notification_destinations_table_name_unique": {
"name": "notification_destinations_table_name_unique",
"columns": ["name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"repositories_table": {
"name": "repositories_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"short_id": {
"name": "short_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"compression_mode": {
"name": "compression_mode",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'auto'"
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false,
"default": "'unknown'"
},
"last_checked": {
"name": "last_checked",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_error": {
"name": "last_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"repositories_table_short_id_unique": {
"name": "repositories_table_short_id_unique",
"columns": ["short_id"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"sessions_table": {
"name": "sessions_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {},
"foreignKeys": {
"sessions_table_user_id_users_table_id_fk": {
"name": "sessions_table_user_id_users_table_id_fk",
"tableFrom": "sessions_table",
"tableTo": "users_table",
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users_table": {
"name": "users_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"password_hash": {
"name": "password_hash",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"has_downloaded_restic_password": {
"name": "has_downloaded_restic_password",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
}
},
"indexes": {
"users_table_username_unique": {
"name": "users_table_username_unique",
"columns": ["username"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"volumes_table": {
"name": "volumes_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"short_id": {
"name": "short_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'unmounted'"
},
"last_error": {
"name": "last_error",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"last_health_check": {
"name": "last_health_check",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(unixepoch() * 1000)"
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"auto_remount": {
"name": "auto_remount",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
}
},
"indexes": {
"volumes_table_short_id_unique": {
"name": "volumes_table_short_id_unique",
"columns": ["short_id"],
"isUnique": true
},
"volumes_table_name_unique": {
"name": "volumes_table_name_unique",
"columns": ["name"],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View file

@ -190,6 +190,20 @@
"when": 1766765013108, "when": 1766765013108,
"tag": "0026_migrate-local-repo-paths", "tag": "0026_migrate-local-repo-paths",
"breakpoints": true "breakpoints": true
},
{
"idx": 27,
"version": "6",
"when": 1766778073418,
"tag": "0027_careful_cammi",
"breakpoints": true
},
{
"idx": 28,
"version": "6",
"when": 1766778162985,
"tag": "0028_third_amazoness",
"breakpoints": true
} }
] ]
} }

View file

@ -6,4 +6,4 @@ export const RESTIC_PASS_FILE = "/var/lib/zerobyte/data/restic.pass";
export const DEFAULT_EXCLUDES = [DATABASE_URL, RESTIC_PASS_FILE, REPOSITORY_BASE]; export const DEFAULT_EXCLUDES = [DATABASE_URL, RESTIC_PASS_FILE, REPOSITORY_BASE];
export const REQUIRED_MIGRATIONS = ["v0.14.0"]; export const REQUIRED_MIGRATIONS = ["v0.21.0"];

View file

@ -69,6 +69,7 @@ export type RepositoryInsert = typeof repositoriesTable.$inferInsert;
*/ */
export const backupSchedulesTable = sqliteTable("backup_schedules_table", { export const backupSchedulesTable = sqliteTable("backup_schedules_table", {
id: int().primaryKey({ autoIncrement: true }), id: int().primaryKey({ autoIncrement: true }),
shortId: text("short_id").notNull().unique(),
name: text().notNull().unique(), name: text().notNull().unique(),
volumeId: int("volume_id") volumeId: int("volume_id")
.notNull() .notNull()

View file

@ -1,7 +1,7 @@
import { createHonoServer } from "react-router-hono-server/bun"; import { createHonoServer } from "react-router-hono-server/bun";
import { runDbMigrations } from "./db/db"; import { runDbMigrations } from "./db/db";
import { startup } from "./modules/lifecycle/startup"; import { startup } from "./modules/lifecycle/startup";
import { migrateToShortIds } from "./modules/lifecycle/migration"; import { retagSnapshots } from "./modules/lifecycle/migration";
import { logger } from "./utils/logger"; import { logger } from "./utils/logger";
import { shutdown } from "./modules/lifecycle/shutdown"; import { shutdown } from "./modules/lifecycle/shutdown";
import { REQUIRED_MIGRATIONS } from "./core/constants"; import { REQUIRED_MIGRATIONS } from "./core/constants";
@ -13,7 +13,7 @@ const app = createApp();
runDbMigrations(); runDbMigrations();
await migrateToShortIds(); await retagSnapshots();
await validateRequiredMigrations(REQUIRED_MIGRATIONS); await validateRequiredMigrations(REQUIRED_MIGRATIONS);
startup(); startup();

View file

@ -17,6 +17,7 @@ export type RetentionPolicy = typeof retentionPolicySchema.infer;
const backupScheduleSchema = type({ const backupScheduleSchema = type({
id: "number", id: "number",
shortId: "string",
name: "string", name: "string",
volumeId: "number", volumeId: "number",
repositoryId: "string", repositoryId: "string",

View file

@ -14,6 +14,7 @@ import { notificationsService } from "../notifications/notifications.service";
import { repoMutex } from "../../core/repository-mutex"; import { repoMutex } from "../../core/repository-mutex";
import { checkMirrorCompatibility, getIncompatibleMirrorError } from "~/server/utils/backend-compatibility"; import { checkMirrorCompatibility, getIncompatibleMirrorError } from "~/server/utils/backend-compatibility";
import path from "node:path"; import path from "node:path";
import { generateShortId } from "~/server/utils/id";
const runningBackups = new Map<number, AbortController>(); const runningBackups = new Map<number, AbortController>();
@ -126,6 +127,7 @@ const createSchedule = async (data: CreateBackupScheduleBody) => {
includePatterns: data.includePatterns ?? [], includePatterns: data.includePatterns ?? [],
oneFileSystem: data.oneFileSystem, oneFileSystem: data.oneFileSystem,
nextBackupAt: nextBackupAt, nextBackupAt: nextBackupAt,
shortId: generateShortId(),
}) })
.returning(); .returning();
@ -277,7 +279,7 @@ const executeBackup = async (scheduleId: number, manual = false) => {
oneFileSystem?: boolean; oneFileSystem?: boolean;
signal?: AbortSignal; signal?: AbortSignal;
} = { } = {
tags: [schedule.id.toString()], tags: [schedule.shortId],
oneFileSystem: schedule.oneFileSystem, oneFileSystem: schedule.oneFileSystem,
signal: abortController.signal, signal: abortController.signal,
}; };
@ -476,7 +478,7 @@ const runForget = async (scheduleId: number, repositoryId?: string) => {
logger.info(`running retention policy (forget) for schedule ${scheduleId}`); logger.info(`running retention policy (forget) for schedule ${scheduleId}`);
const releaseLock = await repoMutex.acquireExclusive(repository.id, `forget:${scheduleId}`); const releaseLock = await repoMutex.acquireExclusive(repository.id, `forget:${scheduleId}`);
try { try {
await restic.forget(repository.config, schedule.retentionPolicy, { tag: schedule.id.toString() }); await restic.forget(repository.config, schedule.retentionPolicy, { tag: schedule.shortId });
} finally { } finally {
releaseLock(); releaseLock();
} }
@ -570,6 +572,14 @@ const copyToMirrors = async (
sourceRepository: { id: string; config: (typeof repositoriesTable.$inferSelect)["config"] }, sourceRepository: { id: string; config: (typeof repositoriesTable.$inferSelect)["config"] },
retentionPolicy: (typeof backupSchedulesTable.$inferSelect)["retentionPolicy"], retentionPolicy: (typeof backupSchedulesTable.$inferSelect)["retentionPolicy"],
) => { ) => {
const schedule = await db.query.backupSchedulesTable.findFirst({
where: eq(backupSchedulesTable.id, scheduleId),
});
if (!schedule) {
throw new NotFoundError("Backup schedule not found");
}
const mirrors = await db.query.backupScheduleMirrorsTable.findMany({ const mirrors = await db.query.backupScheduleMirrorsTable.findMany({
where: eq(backupScheduleMirrorsTable.scheduleId, scheduleId), where: eq(backupScheduleMirrorsTable.scheduleId, scheduleId),
with: { repository: true }, with: { repository: true },
@ -599,7 +609,7 @@ const copyToMirrors = async (
const releaseMirror = await repoMutex.acquireShared(mirror.repository.id, `mirror:${scheduleId}`); const releaseMirror = await repoMutex.acquireShared(mirror.repository.id, `mirror:${scheduleId}`);
try { try {
await restic.copy(sourceRepository.config, mirror.repository.config, { tag: scheduleId.toString() }); await restic.copy(sourceRepository.config, mirror.repository.config, { tag: schedule.shortId });
} finally { } finally {
releaseSource(); releaseSource();
releaseMirror(); releaseMirror();

View file

@ -1,14 +1,13 @@
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { db } from "../../db/db"; import { db } from "../../db/db";
import { repositoriesTable } from "../../db/schema"; import { repositoriesTable } from "../../db/schema";
import { VOLUME_MOUNT_BASE, REPOSITORY_BASE } from "../../core/constants";
import { logger } from "../../utils/logger"; import { logger } from "../../utils/logger";
import { hasMigrationCheckpoint, recordMigrationCheckpoint } from "./checkpoint"; import { hasMigrationCheckpoint, recordMigrationCheckpoint } from "./checkpoint";
import type { RepositoryConfig } from "~/schemas/restic"; import { toMessage } from "~/server/utils/errors";
import { safeSpawn } from "~/server/utils/spawn";
import { addCommonArgs, buildEnv, buildRepoUrl, cleanupTemporaryKeys } from "~/server/utils/restic";
const MIGRATION_VERSION = "v0.14.0"; const MIGRATION_VERSION = "v0.21.0";
interface MigrationResult { interface MigrationResult {
success: boolean; success: boolean;
@ -28,19 +27,17 @@ export class MigrationError extends Error {
} }
} }
export const migrateToShortIds = async () => { export const retagSnapshots = async () => {
const alreadyMigrated = await hasMigrationCheckpoint(MIGRATION_VERSION); const alreadyMigrated = await hasMigrationCheckpoint(MIGRATION_VERSION);
if (alreadyMigrated) { if (alreadyMigrated) {
logger.debug(`Migration ${MIGRATION_VERSION} already completed, skipping.`); logger.debug(`Migration ${MIGRATION_VERSION} already completed, skipping.`);
return; return;
} }
logger.info(`Starting short ID migration (${MIGRATION_VERSION})...`); logger.info(`Starting snapshots retagging migration (${MIGRATION_VERSION})...`);
const volumeResult = await migrateVolumeFolders(); const result = await migrateSnapshotsToShortIdTag();
const repoResult = await migrateRepositoryFolders(); const allErrors = [...result.errors];
const allErrors = [...volumeResult.errors, ...repoResult.errors];
if (allErrors.length > 0) { if (allErrors.length > 0) {
for (const err of allErrors) { for (const err of allErrors) {
@ -51,148 +48,45 @@ export const migrateToShortIds = async () => {
await recordMigrationCheckpoint(MIGRATION_VERSION); await recordMigrationCheckpoint(MIGRATION_VERSION);
logger.info(`Short ID migration (${MIGRATION_VERSION}) complete.`); logger.info(`Snapshots retagging migration (${MIGRATION_VERSION}) complete.`);
}; };
const migrateVolumeFolders = async (): Promise<MigrationResult> => { const migrateSnapshotsToShortIdTag = async (): Promise<MigrationResult> => {
const errors: Array<{ name: string; error: string }> = []; const errors: Array<{ name: string; error: string }> = [];
const volumes = await db.query.volumesTable.findMany({}); const backupSchedules = await db.query.backupSchedulesTable.findMany({});
for (const volume of volumes) { for (const schedule of backupSchedules) {
if (volume.config.backend === "directory") { const oldTag = schedule.id.toString();
const newTag = schedule.shortId;
const repository = await db.query.repositoriesTable.findFirst({
where: eq(repositoriesTable.id, schedule.repositoryId),
});
if (!repository) {
errors.push({ name: `schedule:${schedule.name}`, error: `Associated repository not found` });
continue; continue;
} }
const oldPath = path.join(VOLUME_MOUNT_BASE, volume.name); const repoUrl = buildRepoUrl(repository.config);
const newPath = path.join(VOLUME_MOUNT_BASE, volume.shortId); const env = await buildEnv(repository.config);
const oldExists = await pathExists(oldPath); const args = ["--repo", repoUrl, "tag", "--tag", oldTag, "--add", newTag, "--remove", oldTag];
const newExists = await pathExists(newPath);
if (oldExists && !newExists) { addCommonArgs(args, env);
try {
logger.info(`Migrating volume folder: ${oldPath} -> ${newPath}`); logger.info(`Migrating snapshots for schedule '${schedule.name}' from tag '${oldTag}' to '${newTag}'`);
await fs.rename(oldPath, newPath); const res = await safeSpawn({ command: "restic", args, env });
logger.info(`Successfully migrated volume folder for "${volume.name}"`); await cleanupTemporaryKeys(repository.config, env);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error); if (res.exitCode !== 0) {
errors.push({ name: `volume:${volume.name}`, error: errorMessage }); logger.error(`Restic tag failed: ${res.stderr}`);
} errors.push({ name: `schedule:${schedule.name}`, error: `Restic tag command failed: ${toMessage(res.stderr)}` });
} else if (oldExists && newExists) { continue;
logger.warn(
`Both old (${oldPath}) and new (${newPath}) paths exist for volume "${volume.name}". Manual intervention may be required.`,
);
} }
logger.info(`Migrated snapshots for schedule '${schedule.name}' from tag '${oldTag}' to '${newTag}'`);
} }
return { success: errors.length === 0, errors }; return { success: errors.length === 0, errors };
}; };
const migrateRepositoryFolders = async (): Promise<MigrationResult> => {
const errors: Array<{ name: string; error: string }> = [];
const repositories = await db.query.repositoriesTable.findMany({});
for (const repo of repositories) {
if (repo.config.backend !== "local") {
continue;
}
const config = repo.config as Extract<RepositoryConfig, { backend: "local" }>;
if (config.isExistingRepository) {
logger.debug(`Skipping imported repository "${repo.name}" - folder path is user-defined`);
continue;
}
if (config.name === repo.shortId) {
continue;
}
const basePath = config.path || REPOSITORY_BASE;
const oldPath = path.join(basePath, config.name);
const newPath = path.join(basePath, repo.shortId);
const oldExists = await pathExists(oldPath);
const newExists = await pathExists(newPath);
if (oldExists && !newExists) {
try {
logger.info(`Migrating repository folder: ${oldPath} -> ${newPath}`);
await fs.rename(oldPath, newPath);
const updatedConfig: RepositoryConfig = {
...config,
name: repo.shortId,
};
await db
.update(repositoriesTable)
.set({
config: updatedConfig,
updatedAt: Date.now(),
})
.where(eq(repositoriesTable.id, repo.id));
logger.info(`Successfully migrated repository folder and config for "${repo.name}"`);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
errors.push({ name: `repository:${repo.name}`, error: errorMessage });
}
} else if (oldExists && newExists) {
logger.warn(
`Both old (${oldPath}) and new (${newPath}) paths exist for repository "${repo.name}". Manual intervention may be required.`,
);
} else if (!oldExists && !newExists) {
try {
logger.info(`Updating config.name for repository "${repo.name}" (no folder exists yet)`);
const updatedConfig: RepositoryConfig = {
...config,
name: repo.shortId,
};
await db
.update(repositoriesTable)
.set({
config: updatedConfig,
updatedAt: Date.now(),
})
.where(eq(repositoriesTable.id, repo.id));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
errors.push({ name: `repository:${repo.name}`, error: errorMessage });
}
} else if (newExists && !oldExists && config.name !== repo.shortId) {
try {
logger.info(`Folder already at new path, updating config.name for repository "${repo.name}"`);
const updatedConfig: RepositoryConfig = {
...config,
name: repo.shortId,
};
await db
.update(repositoriesTable)
.set({
config: updatedConfig,
updatedAt: Date.now(),
})
.where(eq(repositoriesTable.id, repo.id));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
errors.push({ name: `repository:${repo.name}`, error: errorMessage });
}
}
}
return { success: errors.length === 0, errors };
};
const pathExists = async (p: string): Promise<boolean> => {
try {
await fs.access(p);
return true;
} catch {
return false;
}
};

View file

@ -161,7 +161,7 @@ const listSnapshots = async (id: string, backupId?: string) => {
let snapshots = []; let snapshots = [];
if (backupId) { if (backupId) {
snapshots = await restic.snapshots(repository.config, { tags: [backupId.toString()] }); snapshots = await restic.snapshots(repository.config, { tags: [backupId] });
} else { } else {
snapshots = await restic.snapshots(repository.config); snapshots = await restic.snapshots(repository.config);
} }

View file

@ -1,6 +1,6 @@
import crypto from "node:crypto"; import crypto from "node:crypto";
export const generateShortId = (length = 5): string => { export const generateShortId = (length = 8): string => {
const bytesNeeded = Math.ceil((length * 3) / 4); const bytesNeeded = Math.ceil((length * 3) / 4);
return crypto.randomBytes(bytesNeeded).toString("base64url").slice(0, length).toLowerCase(); return crypto.randomBytes(bytesNeeded).toString("base64url").slice(0, length);
}; };

View file

@ -72,7 +72,7 @@ const ensurePassfile = async () => {
} }
}; };
const buildRepoUrl = (config: RepositoryConfig): string => { export const buildRepoUrl = (config: RepositoryConfig): string => {
switch (config.backend) { switch (config.backend) {
case "local": case "local":
if (config.isExistingRepository) { if (config.isExistingRepository) {
@ -105,7 +105,7 @@ const buildRepoUrl = (config: RepositoryConfig): string => {
} }
}; };
const buildEnv = async (config: RepositoryConfig) => { export const buildEnv = async (config: RepositoryConfig) => {
const env: Record<string, string> = { const env: Record<string, string> = {
RESTIC_CACHE_DIR: "/var/lib/zerobyte/restic/cache", RESTIC_CACHE_DIR: "/var/lib/zerobyte/restic/cache",
PATH: process.env.PATH || "/usr/local/bin:/usr/bin:/bin", PATH: process.env.PATH || "/usr/local/bin:/usr/bin:/bin",
@ -805,7 +805,7 @@ const copy = async (
}; };
}; };
const cleanupTemporaryKeys = async (config: RepositoryConfig, env: Record<string, string>) => { export const cleanupTemporaryKeys = async (config: RepositoryConfig, env: Record<string, string>) => {
if (config.backend === "sftp" && env._SFTP_KEY_PATH) { if (config.backend === "sftp" && env._SFTP_KEY_PATH) {
await fs.unlink(env._SFTP_KEY_PATH).catch(() => {}); await fs.unlink(env._SFTP_KEY_PATH).catch(() => {});
} else if (config.isExistingRepository && config.customPassword && env.RESTIC_PASSWORD_FILE) { } else if (config.isExistingRepository && config.customPassword && env.RESTIC_PASSWORD_FILE) {
@ -815,7 +815,7 @@ const cleanupTemporaryKeys = async (config: RepositoryConfig, env: Record<string
} }
}; };
const addCommonArgs = (args: string[], env: Record<string, string>) => { export const addCommonArgs = (args: string[], env: Record<string, string>) => {
args.push("--json"); args.push("--json");
if (env._SFTP_SSH_ARGS) { if (env._SFTP_SSH_ARGS) {

View file

@ -8,6 +8,7 @@ export const createTestBackupSchedule = async (overrides: Partial<BackupSchedule
cronExpression: "0 0 * * *", cronExpression: "0 0 * * *",
repositoryId: "repo_123", repositoryId: "repo_123",
volumeId: 1, volumeId: 1,
shortId: faker.string.uuid(),
...overrides, ...overrides,
}; };