REFACTORED - migrate the data layer from Prisma to Drizzle (unify the stack)
- Add lib/db (Drizzle schema: 7 tables + 6 enums + relations, postgres.js client), drizzle.config.ts, lib/db/enums.ts (Prisma-compatible enum objects) - Rewrite all 14 app consumers + 4 admin components to Drizzle - Move the test DB layer to Drizzle + in-process PGlite; convert all 8 integration test files + factories (371 tests green) - Remove Prisma: deps, prisma/ schema+migrations, lib/prisma.ts, Dockerfile prisma generate; wire db:generate/migrate/push/studio to drizzle-kit; update Makefile - Preserve the old seed as scripts/legacy-prisma-seed.cjs (needs a Drizzle rewrite)
This commit is contained in:
@@ -0,0 +1,605 @@
|
||||
const { PrismaPg } = require("@prisma/adapter-pg");
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
const { Pool } = require("pg");
|
||||
|
||||
const connectionString =
|
||||
process.env.DATABASE_URL ||
|
||||
"postgresql://postgres:postgres@localhost:5432/moh_sass?schema=public";
|
||||
|
||||
const pool = new Pool({ connectionString });
|
||||
const prisma = new PrismaClient({ adapter: new PrismaPg(pool) });
|
||||
|
||||
async function upsertMediaAsset(input) {
|
||||
const existing = await prisma.mediaAsset.findFirst({
|
||||
where: {
|
||||
label: input.label,
|
||||
url: input.url,
|
||||
},
|
||||
});
|
||||
|
||||
if (existing) {
|
||||
return prisma.mediaAsset.update({
|
||||
where: { id: existing.id },
|
||||
data: input,
|
||||
});
|
||||
}
|
||||
|
||||
return prisma.mediaAsset.create({
|
||||
data: input,
|
||||
});
|
||||
}
|
||||
|
||||
async function syncProjectContent(projectId, sections, assets) {
|
||||
await prisma.portfolioSection.deleteMany({
|
||||
where: { projectId },
|
||||
});
|
||||
|
||||
await prisma.portfolioAsset.deleteMany({
|
||||
where: { projectId },
|
||||
});
|
||||
|
||||
const createdSections = [];
|
||||
|
||||
for (const section of sections) {
|
||||
const createdSection = await prisma.portfolioSection.create({
|
||||
data: {
|
||||
projectId,
|
||||
...section,
|
||||
},
|
||||
});
|
||||
|
||||
createdSections.push(createdSection);
|
||||
}
|
||||
|
||||
const createdAssets = [];
|
||||
|
||||
for (const asset of assets) {
|
||||
const createdAsset = await prisma.portfolioAsset.create({
|
||||
data: {
|
||||
projectId,
|
||||
...asset,
|
||||
},
|
||||
});
|
||||
|
||||
createdAssets.push(createdAsset);
|
||||
}
|
||||
|
||||
return { createdSections, createdAssets };
|
||||
}
|
||||
|
||||
async function syncProjectMediaUsages(projectId, mediaMap) {
|
||||
await prisma.mediaUsage.deleteMany({
|
||||
where: {
|
||||
entityType: "portfolio-project",
|
||||
entityId: projectId,
|
||||
},
|
||||
});
|
||||
|
||||
const usages = [];
|
||||
|
||||
if (mediaMap.coverAssetId) {
|
||||
usages.push({
|
||||
assetId: mediaMap.coverAssetId,
|
||||
usageType: "PORTFOLIO_COVER",
|
||||
entityType: "portfolio-project",
|
||||
entityId: projectId,
|
||||
fieldKey: "cover",
|
||||
});
|
||||
}
|
||||
|
||||
for (const sectionUsage of mediaMap.sectionUsages) {
|
||||
usages.push({
|
||||
assetId: sectionUsage.assetId,
|
||||
usageType: "PORTFOLIO_SECTION",
|
||||
entityType: "portfolio-project",
|
||||
entityId: projectId,
|
||||
fieldKey: sectionUsage.fieldKey,
|
||||
});
|
||||
}
|
||||
|
||||
for (const assetUsage of mediaMap.assetUsages) {
|
||||
usages.push({
|
||||
assetId: assetUsage.assetId,
|
||||
usageType: "PORTFOLIO_ASSET",
|
||||
entityType: "portfolio-project",
|
||||
entityId: projectId,
|
||||
fieldKey: assetUsage.fieldKey,
|
||||
});
|
||||
}
|
||||
|
||||
if (usages.length > 0) {
|
||||
await prisma.mediaUsage.createMany({ data: usages });
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await prisma.mediaUsage.deleteMany({
|
||||
where: {
|
||||
entityType: "portfolio-project",
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.portfolioSection.deleteMany();
|
||||
await prisma.portfolioAsset.deleteMany();
|
||||
await prisma.portfolioProject.deleteMany();
|
||||
await prisma.category.deleteMany();
|
||||
|
||||
await prisma.appConfig.upsert({
|
||||
where: { key: "siteName" },
|
||||
update: { value: "moh-sass" },
|
||||
create: { key: "siteName", value: "moh-sass" },
|
||||
});
|
||||
|
||||
await prisma.appConfig.upsert({
|
||||
where: { key: "site_settings" },
|
||||
update: {
|
||||
value: JSON.stringify({
|
||||
titleTemplate: "{pageTitle} | moh-sass",
|
||||
locales: {
|
||||
ar: {
|
||||
siteName: "moh-sass",
|
||||
titleTemplate: "{pageTitle} | {siteName}",
|
||||
siteDescription: "Multilingual Next.js base project",
|
||||
subhead: "",
|
||||
},
|
||||
en: {
|
||||
siteName: "moh-sass",
|
||||
titleTemplate: "{pageTitle} | {siteName}",
|
||||
siteDescription: "Multilingual Next.js base project",
|
||||
subhead: "",
|
||||
},
|
||||
de: {
|
||||
siteName: "moh-sass",
|
||||
titleTemplate: "{pageTitle} | {siteName}",
|
||||
siteDescription: "Multilingual Next.js base project",
|
||||
subhead: "",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
create: {
|
||||
key: "site_settings",
|
||||
value: JSON.stringify({
|
||||
titleTemplate: "{pageTitle} | moh-sass",
|
||||
locales: {
|
||||
ar: {
|
||||
siteName: "moh-sass",
|
||||
titleTemplate: "{pageTitle} | {siteName}",
|
||||
siteDescription: "Multilingual Next.js base project",
|
||||
subhead: "",
|
||||
},
|
||||
en: {
|
||||
siteName: "moh-sass",
|
||||
titleTemplate: "{pageTitle} | {siteName}",
|
||||
siteDescription: "Multilingual Next.js base project",
|
||||
subhead: "",
|
||||
},
|
||||
de: {
|
||||
siteName: "moh-sass",
|
||||
titleTemplate: "{pageTitle} | {siteName}",
|
||||
siteDescription: "Multilingual Next.js base project",
|
||||
subhead: "",
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const brandCategory = await prisma.category.upsert({
|
||||
where: { slug: "branding" },
|
||||
update: {
|
||||
nameAr: "الهوية البصرية",
|
||||
nameEn: "Branding",
|
||||
nameDe: "Branding",
|
||||
descriptionAr: "مشاريع هوية بصرية وشعارات وأنظمة علامة.",
|
||||
descriptionEn: "Brand identity, logo, and design system work.",
|
||||
descriptionDe: "Branding, Logos und visuelle Systeme.",
|
||||
sortOrder: 1,
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
slug: "branding",
|
||||
nameAr: "الهوية البصرية",
|
||||
nameEn: "Branding",
|
||||
nameDe: "Branding",
|
||||
descriptionAr: "مشاريع هوية بصرية وشعارات وأنظمة علامة.",
|
||||
descriptionEn: "Brand identity, logo, and design system work.",
|
||||
descriptionDe: "Branding, Logos und visuelle Systeme.",
|
||||
sortOrder: 1,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const webCategory = await prisma.category.upsert({
|
||||
where: { slug: "web-experiences" },
|
||||
update: {
|
||||
nameAr: "تجارب الويب",
|
||||
nameEn: "Web Experiences",
|
||||
nameDe: "Web Experiences",
|
||||
descriptionAr: "مواقع وصفحات هبوط وتجارب رقمية سريعة.",
|
||||
descriptionEn: "Websites, landing pages, and digital experiences.",
|
||||
descriptionDe: "Webseiten, Landingpages und digitale Erlebnisse.",
|
||||
sortOrder: 2,
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
slug: "web-experiences",
|
||||
nameAr: "تجارب الويب",
|
||||
nameEn: "Web Experiences",
|
||||
nameDe: "Web Experiences",
|
||||
descriptionAr: "مواقع وصفحات هبوط وتجارب رقمية سريعة.",
|
||||
descriptionEn: "Websites, landing pages, and digital experiences.",
|
||||
descriptionDe: "Webseiten, Landingpages und digitale Erlebnisse.",
|
||||
sortOrder: 2,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const commerceCategory = await prisma.category.upsert({
|
||||
where: { slug: "commerce" },
|
||||
update: {
|
||||
nameAr: "التجارة الرقمية",
|
||||
nameEn: "Commerce",
|
||||
nameDe: "Commerce",
|
||||
descriptionAr: "متاجر وتجارب شراء رقمية مع تركيز على الوضوح والتحويل.",
|
||||
descriptionEn: "Commerce experiences with a focus on clarity and conversion.",
|
||||
descriptionDe: "Commerce-Projekte mit Fokus auf Klarheit und Conversion.",
|
||||
sortOrder: 3,
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
slug: "commerce",
|
||||
nameAr: "التجارة الرقمية",
|
||||
nameEn: "Commerce",
|
||||
nameDe: "Commerce",
|
||||
descriptionAr: "متاجر وتجارب شراء رقمية مع تركيز على الوضوح والتحويل.",
|
||||
descriptionEn: "Commerce experiences with a focus on clarity and conversion.",
|
||||
descriptionDe: "Commerce-Projekte mit Fokus auf Klarheit und Conversion.",
|
||||
sortOrder: 3,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const gridCover = await upsertMediaAsset({
|
||||
source: "UPLOAD",
|
||||
kind: "IMAGE",
|
||||
url: "/uploads/portfolio/demo-cover.svg",
|
||||
fileName: "demo-cover.svg",
|
||||
label: "Portfolio Grid Cover",
|
||||
altText: "Portfolio Grid Cover",
|
||||
mimeType: "image/svg+xml",
|
||||
size: 1024,
|
||||
});
|
||||
|
||||
const storyCover = await upsertMediaAsset({
|
||||
source: "UPLOAD",
|
||||
kind: "IMAGE",
|
||||
url: "/uploads/portfolio/demo-cover.svg",
|
||||
fileName: "demo-cover.svg",
|
||||
label: "Portfolio Story Cover",
|
||||
altText: "Portfolio Story Cover",
|
||||
mimeType: "image/svg+xml",
|
||||
size: 1024,
|
||||
});
|
||||
|
||||
const caseStudyCover = await upsertMediaAsset({
|
||||
source: "UPLOAD",
|
||||
kind: "IMAGE",
|
||||
url: "/uploads/portfolio/demo-cover.svg",
|
||||
fileName: "demo-cover.svg",
|
||||
label: "Portfolio Case Study Cover",
|
||||
altText: "Portfolio Case Study Cover",
|
||||
mimeType: "image/svg+xml",
|
||||
size: 1024,
|
||||
});
|
||||
|
||||
const projects = [
|
||||
{
|
||||
slug: "grid-product-launch",
|
||||
categoryId: commerceCategory.id,
|
||||
viewMode: "GRID",
|
||||
titleAr: "إطلاق منتج رقمي",
|
||||
titleEn: "Grid Product Launch",
|
||||
titleDe: "Grid Product Launch",
|
||||
summaryAr: "مثال عرض شبكي لمشروع سريع مع أقسام قصيرة وأصول داعمة.",
|
||||
summaryEn: "Grid view example for a fast product launch page.",
|
||||
summaryDe: "Grid-Ansicht als Beispiel fuer einen schnellen Produktlaunch.",
|
||||
clientName: "Launch Studio",
|
||||
projectYear: 2026,
|
||||
serviceLabelAr: "تجربة إطلاق",
|
||||
serviceLabelEn: "Launch Experience",
|
||||
serviceLabelDe: "Launch Experience",
|
||||
previewUrl: "https://example.com/preview/grid-product-launch",
|
||||
coverImagePath: gridCover.url,
|
||||
isFeatured: true,
|
||||
isPublished: true,
|
||||
publishedAt: new Date("2026-01-12T09:00:00.000Z"),
|
||||
sortOrder: 1,
|
||||
coverAssetId: gridCover.id,
|
||||
sections: [
|
||||
{
|
||||
type: "RICH_TEXT",
|
||||
titleAr: "الفكرة",
|
||||
titleEn: "Concept",
|
||||
titleDe: "Konzept",
|
||||
bodyAr: "واجهة سريعة لعرض المنتج والتركيز على الرسالة الأساسية.",
|
||||
bodyEn: "A fast modular presentation focused on the main launch message.",
|
||||
bodyDe: "Eine schnelle modulare Darstellung mit Fokus auf die Hauptbotschaft.",
|
||||
imagePath: null,
|
||||
linkUrl: null,
|
||||
sortOrder: 0,
|
||||
mediaAssetId: null,
|
||||
},
|
||||
{
|
||||
type: "GALLERY",
|
||||
titleAr: "الصورة الرئيسية",
|
||||
titleEn: "Hero Visual",
|
||||
titleDe: "Hero Visual",
|
||||
bodyAr: "",
|
||||
bodyEn: "",
|
||||
bodyDe: "",
|
||||
imagePath: gridCover.url,
|
||||
linkUrl: null,
|
||||
sortOrder: 1,
|
||||
mediaAssetId: gridCover.id,
|
||||
},
|
||||
],
|
||||
assets: [
|
||||
{
|
||||
kind: "IMAGE",
|
||||
filePath: gridCover.url,
|
||||
altAr: "غلاف مشروع Grid",
|
||||
altEn: "Grid project cover",
|
||||
altDe: "Grid Projekt Cover",
|
||||
sortOrder: 0,
|
||||
mediaAssetId: gridCover.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: "campaign-site",
|
||||
categoryId: webCategory.id,
|
||||
viewMode: "STORY",
|
||||
titleAr: "موقع حملة",
|
||||
titleEn: "Campaign Site",
|
||||
titleDe: "Campaign Site",
|
||||
summaryAr: "مثال عرض قصصي لمشروع ويب مع تسلسل سردي أوضح.",
|
||||
summaryEn: "Story view example for a launch campaign website.",
|
||||
summaryDe: "Story-Ansicht als Beispiel fuer eine Kampagnenseite.",
|
||||
clientName: "Launch Client",
|
||||
projectYear: 2024,
|
||||
serviceLabelAr: "موقع تسويقي",
|
||||
serviceLabelEn: "Marketing Website",
|
||||
serviceLabelDe: "Marketing Website",
|
||||
previewUrl: "https://example.com/preview/campaign-site",
|
||||
coverImagePath: storyCover.url,
|
||||
isFeatured: false,
|
||||
isPublished: true,
|
||||
publishedAt: new Date("2024-09-05T09:00:00.000Z"),
|
||||
sortOrder: 2,
|
||||
coverAssetId: storyCover.id,
|
||||
sections: [
|
||||
{
|
||||
type: "RICH_TEXT",
|
||||
titleAr: "السياق",
|
||||
titleEn: "Context",
|
||||
titleDe: "Kontext",
|
||||
bodyAr: "الحملة احتاجت صفحة مرنة وسريعة تتبدل بين أكثر من مرحلة.",
|
||||
bodyEn: "The campaign needed a flexible page that could adapt across phases.",
|
||||
bodyDe: "Die Kampagne brauchte eine flexible Seite fuer mehrere Phasen.",
|
||||
imagePath: null,
|
||||
linkUrl: null,
|
||||
sortOrder: 0,
|
||||
mediaAssetId: null,
|
||||
},
|
||||
{
|
||||
type: "GALLERY",
|
||||
titleAr: "العرض البصري",
|
||||
titleEn: "Visual Flow",
|
||||
titleDe: "Visueller Ablauf",
|
||||
bodyAr: "",
|
||||
bodyEn: "",
|
||||
bodyDe: "",
|
||||
imagePath: storyCover.url,
|
||||
linkUrl: null,
|
||||
sortOrder: 1,
|
||||
mediaAssetId: storyCover.id,
|
||||
},
|
||||
{
|
||||
type: "LINK",
|
||||
titleAr: "المعاينة",
|
||||
titleEn: "Preview",
|
||||
titleDe: "Vorschau",
|
||||
bodyAr: "رابط العرض المباشر.",
|
||||
bodyEn: "Direct preview link.",
|
||||
bodyDe: "Direkter Vorschau-Link.",
|
||||
imagePath: null,
|
||||
linkUrl: "https://example.com/preview/campaign-site",
|
||||
sortOrder: 2,
|
||||
mediaAssetId: null,
|
||||
},
|
||||
],
|
||||
assets: [
|
||||
{
|
||||
kind: "IMAGE",
|
||||
filePath: storyCover.url,
|
||||
altAr: "غلاف مشروع Story",
|
||||
altEn: "Story project cover",
|
||||
altDe: "Story Projekt Cover",
|
||||
sortOrder: 0,
|
||||
mediaAssetId: storyCover.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: "brand-redesign",
|
||||
categoryId: brandCategory.id,
|
||||
viewMode: "CASE_STUDY",
|
||||
titleAr: "إعادة تصميم الهوية",
|
||||
titleEn: "Brand Redesign",
|
||||
titleDe: "Brand Redesign",
|
||||
summaryAr: "مثال عرض دراسة حالة يركز على التحدي والحل والنتيجة.",
|
||||
summaryEn: "Case study example focused on challenge, solution, and outcome.",
|
||||
summaryDe: "Case-Study-Ansicht mit Fokus auf Herausforderung, Loesung und Ergebnis.",
|
||||
clientName: "Studio Client",
|
||||
projectYear: 2025,
|
||||
serviceLabelAr: "هوية بصرية",
|
||||
serviceLabelEn: "Brand Identity",
|
||||
serviceLabelDe: "Brand Identity",
|
||||
previewUrl: "https://example.com/preview/brand-redesign",
|
||||
coverImagePath: caseStudyCover.url,
|
||||
isFeatured: true,
|
||||
isPublished: true,
|
||||
publishedAt: new Date("2025-01-10T09:00:00.000Z"),
|
||||
sortOrder: 3,
|
||||
coverAssetId: caseStudyCover.id,
|
||||
sections: [
|
||||
{
|
||||
type: "RICH_TEXT",
|
||||
titleAr: "التحدي",
|
||||
titleEn: "Challenge",
|
||||
titleDe: "Herausforderung",
|
||||
bodyAr: "كان المطلوب تحديث الهوية بدون خسارة التعرف البصري الحالي.",
|
||||
bodyEn: "The brief required a refreshed identity without losing recognition.",
|
||||
bodyDe: "Die Marke sollte modernisiert werden, ohne die Wiedererkennbarkeit zu verlieren.",
|
||||
imagePath: null,
|
||||
linkUrl: null,
|
||||
sortOrder: 0,
|
||||
mediaAssetId: null,
|
||||
},
|
||||
{
|
||||
type: "RICH_TEXT",
|
||||
titleAr: "الحل",
|
||||
titleEn: "Solution",
|
||||
titleDe: "Loesung",
|
||||
bodyAr: "تم بناء نظام مرئي أوضح مع قواعد استخدام قابلة للتوسع.",
|
||||
bodyEn: "A clearer visual system with scalable usage rules was created.",
|
||||
bodyDe: "Es wurde ein klareres visuelles System mit skalierbaren Regeln aufgebaut.",
|
||||
imagePath: null,
|
||||
linkUrl: null,
|
||||
sortOrder: 1,
|
||||
mediaAssetId: null,
|
||||
},
|
||||
{
|
||||
type: "GALLERY",
|
||||
titleAr: "التنفيذ البصري",
|
||||
titleEn: "Visual Execution",
|
||||
titleDe: "Visuelle Umsetzung",
|
||||
bodyAr: "",
|
||||
bodyEn: "",
|
||||
bodyDe: "",
|
||||
imagePath: caseStudyCover.url,
|
||||
linkUrl: null,
|
||||
sortOrder: 2,
|
||||
mediaAssetId: caseStudyCover.id,
|
||||
},
|
||||
],
|
||||
assets: [
|
||||
{
|
||||
kind: "IMAGE",
|
||||
filePath: caseStudyCover.url,
|
||||
altAr: "غلاف مشروع Case Study",
|
||||
altEn: "Case study project cover",
|
||||
altDe: "Case Study Projekt Cover",
|
||||
sortOrder: 0,
|
||||
mediaAssetId: caseStudyCover.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
for (const projectConfig of projects) {
|
||||
const project = await prisma.portfolioProject.upsert({
|
||||
where: { slug: projectConfig.slug },
|
||||
update: {
|
||||
categoryId: projectConfig.categoryId,
|
||||
viewMode: projectConfig.viewMode,
|
||||
titleAr: projectConfig.titleAr,
|
||||
titleEn: projectConfig.titleEn,
|
||||
titleDe: projectConfig.titleDe,
|
||||
summaryAr: projectConfig.summaryAr,
|
||||
summaryEn: projectConfig.summaryEn,
|
||||
summaryDe: projectConfig.summaryDe,
|
||||
clientName: projectConfig.clientName,
|
||||
projectYear: projectConfig.projectYear,
|
||||
serviceLabelAr: projectConfig.serviceLabelAr,
|
||||
serviceLabelEn: projectConfig.serviceLabelEn,
|
||||
serviceLabelDe: projectConfig.serviceLabelDe,
|
||||
previewUrl: projectConfig.previewUrl,
|
||||
coverImagePath: projectConfig.coverImagePath,
|
||||
isFeatured: projectConfig.isFeatured,
|
||||
isPublished: projectConfig.isPublished,
|
||||
publishedAt: projectConfig.publishedAt,
|
||||
sortOrder: projectConfig.sortOrder,
|
||||
},
|
||||
create: {
|
||||
slug: projectConfig.slug,
|
||||
categoryId: projectConfig.categoryId,
|
||||
viewMode: projectConfig.viewMode,
|
||||
titleAr: projectConfig.titleAr,
|
||||
titleEn: projectConfig.titleEn,
|
||||
titleDe: projectConfig.titleDe,
|
||||
summaryAr: projectConfig.summaryAr,
|
||||
summaryEn: projectConfig.summaryEn,
|
||||
summaryDe: projectConfig.summaryDe,
|
||||
clientName: projectConfig.clientName,
|
||||
projectYear: projectConfig.projectYear,
|
||||
serviceLabelAr: projectConfig.serviceLabelAr,
|
||||
serviceLabelEn: projectConfig.serviceLabelEn,
|
||||
serviceLabelDe: projectConfig.serviceLabelDe,
|
||||
previewUrl: projectConfig.previewUrl,
|
||||
coverImagePath: projectConfig.coverImagePath,
|
||||
isFeatured: projectConfig.isFeatured,
|
||||
isPublished: projectConfig.isPublished,
|
||||
publishedAt: projectConfig.publishedAt,
|
||||
sortOrder: projectConfig.sortOrder,
|
||||
},
|
||||
});
|
||||
|
||||
const created = await syncProjectContent(project.id, projectConfig.sections.map((section) => ({
|
||||
type: section.type,
|
||||
titleAr: section.titleAr,
|
||||
titleEn: section.titleEn,
|
||||
titleDe: section.titleDe,
|
||||
bodyAr: section.bodyAr,
|
||||
bodyEn: section.bodyEn,
|
||||
bodyDe: section.bodyDe,
|
||||
imagePath: section.imagePath,
|
||||
linkUrl: section.linkUrl,
|
||||
sortOrder: section.sortOrder,
|
||||
})), projectConfig.assets.map((asset) => ({
|
||||
kind: asset.kind,
|
||||
filePath: asset.filePath,
|
||||
altAr: asset.altAr,
|
||||
altEn: asset.altEn,
|
||||
altDe: asset.altDe,
|
||||
sortOrder: asset.sortOrder,
|
||||
})));
|
||||
|
||||
await syncProjectMediaUsages(project.id, {
|
||||
coverAssetId: projectConfig.coverAssetId,
|
||||
sectionUsages: created.createdSections
|
||||
.map((sectionRow, index) => ({
|
||||
fieldKey: sectionRow.id,
|
||||
assetId: projectConfig.sections[index]?.mediaAssetId,
|
||||
}))
|
||||
.filter((entry) => entry.assetId),
|
||||
assetUsages: created.createdAssets
|
||||
.map((assetRow, index) => ({
|
||||
fieldKey: assetRow.id,
|
||||
assetId: projectConfig.assets[index]?.mediaAssetId,
|
||||
}))
|
||||
.filter((entry) => entry.assetId),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((error) => {
|
||||
console.error("Seed failed:", error);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
await pool.end();
|
||||
});
|
||||
Reference in New Issue
Block a user