import { PrismaClient } from '@prisma/client' import { FIXED_PROJECT_TYPE_TAGS, inferProjectTypeSlug, inferTagCategory, } from '../src/lib/tag-taxonomy' const prisma = new PrismaClient() async function ensureFixedProjectTypeTags() { const result = await Promise.all( FIXED_PROJECT_TYPE_TAGS.map((item) => prisma.tag.upsert({ where: { slug: item.slug }, update: { name: item.name, nameEn: item.nameEn, category: 'FIXED_PROJECT_TYPE', }, create: { name: item.name, nameEn: item.nameEn, slug: item.slug, category: 'FIXED_PROJECT_TYPE', }, }) ) ) return new Map(result.map((tag) => [tag.slug, tag.id])) } async function backfillTagCategories() { const tags = await prisma.tag.findMany() let updated = 0 for (const tag of tags) { const inferredCategory = inferTagCategory({ slug: tag.slug, name: tag.name, nameEn: tag.nameEn, }) if (tag.category !== inferredCategory) { await prisma.tag.update({ where: { id: tag.id }, data: { category: inferredCategory }, }) updated += 1 } } return updated } async function backfillProjectFixedTypes(fixedTypeIdMap: Map) { const projects = await prisma.project.findMany({ where: { status: 'ACTIVE' }, include: { tags: { include: { tag: true, }, }, }, }) const createData: Array<{ projectId: string; tagId: string }> = [] for (const project of projects) { const fixedTypeSlug = inferProjectTypeSlug({ name: project.name, nameEn: project.nameEn, description: project.description, descriptionEn: project.descriptionEn, tags: project.tags.map((tag) => ({ slug: tag.tag.slug, name: tag.tag.name, nameEn: tag.tag.nameEn, })), }) const fixedTypeTagId = fixedTypeIdMap.get(fixedTypeSlug) if (!fixedTypeTagId) { throw new Error(`Missing fixed project type tag: ${fixedTypeSlug}`) } createData.push({ projectId: project.id, tagId: fixedTypeTagId, }) } const removed = await prisma.projectTag.deleteMany({ where: { tag: { category: 'FIXED_PROJECT_TYPE', }, }, }) const inserted = await prisma.projectTag.createMany({ data: createData, skipDuplicates: true, }) return { projectCount: projects.length, inserted: inserted.count, removed: removed.count, } } async function main() { console.log('[taxonomy] start') const fixedTypeIdMap = await ensureFixedProjectTypeTags() const updatedTagCategoryCount = await backfillTagCategories() const projectResult = await backfillProjectFixedTypes(fixedTypeIdMap) console.log('[taxonomy] done', { updatedTagCategoryCount, projectCount: projectResult.projectCount, insertedProjectTypeLinks: projectResult.inserted, removedOldProjectTypeLinks: projectResult.removed, }) } main() .catch((error) => { console.error('[taxonomy] failed', error) process.exit(1) }) .finally(async () => { await prisma.$disconnect() })