refactor: local repo path concat as a code migration
This commit is contained in:
parent
9a68d1039f
commit
c1c8138197
4 changed files with 99 additions and 2178 deletions
|
|
@ -1,23 +0,0 @@
|
|||
UPDATE `repositories_table`
|
||||
SET
|
||||
`config` = json_set(
|
||||
`config`,
|
||||
'$.path',
|
||||
CASE
|
||||
WHEN json_extract(`config`, '$.path') IS NULL OR trim(json_extract(`config`, '$.path')) = ''
|
||||
THEN '/var/lib/zerobyte/repositories/' || json_extract(`config`, '$.name')
|
||||
ELSE rtrim(json_extract(`config`, '$.path'), '/') || '/' || json_extract(`config`, '$.name')
|
||||
END
|
||||
),
|
||||
`updated_at` = (unixepoch() * 1000)
|
||||
WHERE `type` = 'local'
|
||||
AND json_extract(`config`, '$.name') IS NOT NULL
|
||||
AND trim(json_extract(`config`, '$.name')) <> ''
|
||||
AND (
|
||||
json_extract(`config`, '$.path') IS NULL
|
||||
OR trim(json_extract(`config`, '$.path')) = ''
|
||||
OR substr(
|
||||
rtrim(json_extract(`config`, '$.path'), '/'),
|
||||
-length('/' || json_extract(`config`, '$.name'))
|
||||
) != '/' || json_extract(`config`, '$.name')
|
||||
);
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,6 +2,7 @@ import { logger } from "../../utils/logger";
|
|||
import { v00001 } from "./migrations/00001-retag-snapshots";
|
||||
import { v00002 } from "./migrations/00002-isolate-restic-passwords";
|
||||
import { v00003 } from "./migrations/00003-assign-organization";
|
||||
import { v00004 } from "./migrations/00004-concat-path-name";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { appMetadataTable, usersTable } from "../../db/schema";
|
||||
import { db } from "../../db/db";
|
||||
|
|
@ -36,7 +37,7 @@ type MigrationEntity = {
|
|||
dependsOn?: string[];
|
||||
};
|
||||
|
||||
const registry: MigrationEntity[] = [v00001, v00002, v00003];
|
||||
const registry: MigrationEntity[] = [v00001, v00002, v00003, v00004];
|
||||
|
||||
export const runMigrations = async () => {
|
||||
const userCount = await db.select({ count: sql<number>`count(*)` }).from(usersTable);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
import { and, eq } from "drizzle-orm";
|
||||
import { db } from "../../../db/db";
|
||||
import { repositoriesTable } from "../../../db/schema";
|
||||
import { logger } from "../../../utils/logger";
|
||||
import { toMessage } from "~/server/utils/errors";
|
||||
|
||||
const DEFAULT_LOCAL_REPOSITORY_ROOT = "/var/lib/zerobyte/repositories";
|
||||
|
||||
type MigrationError = { name: string; error: string };
|
||||
|
||||
const asString = (value: unknown): string | null => {
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
const hasValue = (value: string | null): value is string => {
|
||||
return value !== null && value.trim() !== "";
|
||||
};
|
||||
|
||||
const trimTrailingSlashes = (value: string): string => {
|
||||
return value.replace(/\/+$/, "");
|
||||
};
|
||||
|
||||
const isPathAlreadyMigrated = (path: string, name: string): boolean => {
|
||||
const normalizedPath = trimTrailingSlashes(path);
|
||||
return normalizedPath.endsWith(`/${name}`);
|
||||
};
|
||||
|
||||
const buildPath = (path: string | null, name: string): string => {
|
||||
if (path === null || path.trim() === "") {
|
||||
return `${DEFAULT_LOCAL_REPOSITORY_ROOT}/${name}`;
|
||||
}
|
||||
|
||||
return `${trimTrailingSlashes(path)}/${name}`;
|
||||
};
|
||||
|
||||
const execute = async () => {
|
||||
const errors: MigrationError[] = [];
|
||||
const localRepositories = await db.query.repositoriesTable.findMany({ where: { type: "local" } });
|
||||
let migratedCount = 0;
|
||||
|
||||
for (const repository of localRepositories) {
|
||||
try {
|
||||
const configValue = repository.config as unknown;
|
||||
|
||||
if (typeof configValue !== "object" || configValue === null || Array.isArray(configValue)) {
|
||||
errors.push({
|
||||
name: `repository:${repository.id}`,
|
||||
error: "Repository config is not a valid JSON object",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const config = { ...(configValue as Record<string, unknown>) };
|
||||
const localRepositoryName = asString(config.name);
|
||||
|
||||
if (!hasValue(localRepositoryName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const currentPath = asString(config.path);
|
||||
if (hasValue(currentPath) && isPathAlreadyMigrated(currentPath, localRepositoryName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
config.path = buildPath(currentPath, localRepositoryName);
|
||||
|
||||
await db
|
||||
.update(repositoriesTable)
|
||||
.set({
|
||||
config: config as typeof repository.config,
|
||||
updatedAt: Date.now(),
|
||||
})
|
||||
.where(and(eq(repositoriesTable.id, repository.id), eq(repositoriesTable.type, "local")));
|
||||
|
||||
migratedCount += 1;
|
||||
} catch (err) {
|
||||
errors.push({
|
||||
name: `repository:${repository.id}`,
|
||||
error: toMessage(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`Migration 00004-concat-path-name updated ${migratedCount} local repositories.`);
|
||||
|
||||
return { success: errors.length === 0, errors };
|
||||
};
|
||||
|
||||
export const v00004 = {
|
||||
execute,
|
||||
id: "00004-concat-path-name",
|
||||
type: "maintenance" as const,
|
||||
};
|
||||
Loading…
Reference in a new issue