Moving the arttags table to tags table part 2

This commit is contained in:
2026-02-02 13:48:49 +01:00
parent 7605ccb0aa
commit ed81662ae5
13 changed files with 195 additions and 245 deletions

View File

@ -13,7 +13,6 @@ export async function deleteArtwork(artworkId: string) {
colors: true,
metadata: true,
tags: true,
tagsV2: true,
categories: true,
},
});
@ -75,7 +74,6 @@ export async function deleteArtwork(artworkId: string) {
where: { id: artworkId },
data: {
tags: { set: [] },
tagsV2: { set: [] },
categories: { set: [] },
},
});

View File

@ -15,7 +15,7 @@ export async function getSingleArtwork(id: string) {
categories: true,
colors: { include: { color: true } },
// sortContexts: true,
tagsV2: true,
tags: true,
variants: true,
timelapse: true
}

View File

@ -22,7 +22,7 @@ function mapSortingToOrderBy(sorting: ArtworkTableInput["sorting"]) {
// relation counts: Prisma supports ordering by _count
albumsCount: (desc) => ({ albums: { _count: desc ? "desc" : "asc" } }),
categoriesCount: (desc) => ({ categories: { _count: desc ? "desc" : "asc" } }),
tagsCount: (desc) => ({ tagsV2: { _count: desc ? "desc" : "asc" } }),
tagsCount: (desc) => ({ tags: { _count: desc ? "desc" : "asc" } }),
};
const orderBy = sorting
@ -89,7 +89,7 @@ export async function getArtworksTablePage(input: unknown) {
gallery: { select: { id: true, name: true } },
albums: { select: { id: true, name: true } },
categories: { select: { id: true, name: true } },
_count: { select: { albums: true, categories: true, tagsV2: true } },
_count: { select: { albums: true, categories: true, tags: true } },
},
}),
]);
@ -109,7 +109,7 @@ export async function getArtworksTablePage(input: unknown) {
categories: a.categories,
albumsCount: a._count.albums,
categoriesCount: a._count.categories,
tagsCount: a._count.tagsV2,
tagsCount: a._count.tags,
}));
const out = { rows, total, pageIndex, pageSize };

View File

@ -47,7 +47,7 @@ export async function updateArtwork(
const tagsRelation =
tagIds || tagsToCreate.length
? {
tagsV2: {
tags: {
set: [], // replace entire relation
connect: (tagIds ?? []).map((tagId) => ({ id: tagId })),
connectOrCreate: tagsToCreate.map((tName) => ({

View File

@ -1,102 +1,5 @@
"use server";
import { prisma } from "@/lib/prisma";
import { revalidatePath } from "next/cache";
export async function migrateArtTags() {
const artTags = await prisma.artTag.findMany({
include: {
aliases: true,
categories: true,
artworks: { select: { id: true } },
},
orderBy: [{ sortIndex: "asc" }, { name: "asc" }],
});
const idMap = new Map<string, string>();
await prisma.$transaction(async (tx) => {
for (const artTag of artTags) {
const tag = await tx.tag.upsert({
where: { slug: artTag.slug },
update: {
name: artTag.name,
description: artTag.description,
isVisible: true,
},
create: {
name: artTag.name,
slug: artTag.slug,
description: artTag.description,
isVisible: true,
},
});
idMap.set(artTag.id, tag.id);
}
const aliasRows = artTags.flatMap((artTag) => {
const tagId = idMap.get(artTag.id);
if (!tagId) return [];
return artTag.aliases.map((a) => ({
tagId,
alias: a.alias,
}));
});
if (aliasRows.length > 0) {
await tx.tagAlias.createMany({
data: aliasRows,
skipDuplicates: true,
});
}
const categoryRows = artTags.flatMap((artTag) => {
const tagId = idMap.get(artTag.id);
if (!tagId) return [];
const parentTagId = artTag.parentId
? idMap.get(artTag.parentId) ?? null
: null;
return artTag.categories.map((category) => ({
tagId,
categoryId: category.id,
isParent: artTag.isParent,
showOnAnimalPage: artTag.showOnAnimalPage,
parentTagId,
}));
});
if (categoryRows.length > 0) {
await tx.tagCategory.createMany({
data: categoryRows,
skipDuplicates: true,
});
}
});
// Connect artwork relations outside the transaction to avoid timeouts.
for (const artTag of artTags) {
const tagId = idMap.get(artTag.id);
if (!tagId) continue;
for (const artwork of artTag.artworks) {
await prisma.artwork.update({
where: { id: artwork.id },
data: {
tagsV2: {
connect: { id: tagId },
},
},
});
}
}
const summary = {
tags: artTags.length,
aliases: artTags.reduce((sum, t) => sum + t.aliases.length, 0),
categoryLinks: artTags.reduce((sum, t) => sum + t.categories.length, 0),
};
revalidatePath("/tags");
return summary;
throw new Error("Migration disabled: ArtTag models removed.");
}

View File

@ -0,0 +1,75 @@
"use server";
import { prisma } from "@/lib/prisma";
import { revalidatePath } from "next/cache";
type JoinMigrationResult = {
ok: boolean;
copied: number;
oldExists: boolean;
newExists: boolean;
droppedOld: boolean;
message?: string;
};
export async function migrateArtworkTagJoin(
opts: { dropOld?: boolean } = {},
): Promise<JoinMigrationResult> {
const dropOld = Boolean(opts.dropOld);
const [oldRow, newRow] = await Promise.all([
prisma.$queryRaw<{ name: string | null }[]>`
select to_regclass('_ArtworkTagsV2')::text as name;
`,
prisma.$queryRaw<{ name: string | null }[]>`
select to_regclass('_ArtworkTags')::text as name;
`,
]);
const oldExists = Boolean(oldRow?.[0]?.name);
const newExists = Boolean(newRow?.[0]?.name);
if (!newExists) {
return {
ok: false,
copied: 0,
oldExists,
newExists,
droppedOld: false,
message: "New join table _ArtworkTags does not exist. Run the migration first.",
};
}
if (!oldExists) {
return {
ok: true,
copied: 0,
oldExists,
newExists,
droppedOld: false,
message: "Old join table _ArtworkTagsV2 not found. Nothing to copy.",
};
}
const copied = await prisma.$executeRawUnsafe(`
INSERT INTO "_ArtworkTags" ("A","B")
SELECT "A","B" FROM "_ArtworkTagsV2"
ON CONFLICT ("A","B") DO NOTHING;
`);
let droppedOld = false;
if (dropOld) {
await prisma.$executeRawUnsafe(`DROP TABLE "_ArtworkTagsV2";`);
droppedOld = true;
}
revalidatePath("/tags");
return {
ok: true,
copied: Number(copied ?? 0),
oldExists,
newExists,
droppedOld,
};
}