diff --git a/src/modules/internal/repositories/bulkInsertMediaProducerStudioLicensor.repository.ts b/src/modules/internal/repositories/bulkInsertMediaProducerStudioLicensor.repository.ts new file mode 100644 index 0000000..5951343 --- /dev/null +++ b/src/modules/internal/repositories/bulkInsertMediaProducerStudioLicensor.repository.ts @@ -0,0 +1,74 @@ +import { Prisma } from "@prisma/client"; +import { GenreOrProducer, MediaFullInfoResponse } from "../types/mediaFullInfo.type"; +import { SystemAccountId } from "../../../config/account/system"; +import { status } from "elysia"; + +export const bulkInsertMediaProducerStudioLicensorRepository = async ( + tx: Prisma.TransactionClient, + media_id: string, + payload: (GenreOrProducer & { status: "producer" | "licensor" | "studio" })[], +) => { + await tx.producer.createMany({ + data: payload.map((p) => ({ + mal_id: p.mal_id, + type: p.type, + name: p.name, + url: p.url, + created_by_id: SystemAccountId, + })), + skipDuplicates: true, + }); + + const insertedProducers = ( + await tx.producer.findMany({ + where: { + mal_id: { + in: payload.map((p) => p.mal_id), + }, + }, + select: { + id: true, + mal_id: true, + }, + }) + ).map((producer) => { + const statusProducer = payload.find((p) => p.mal_id === producer.mal_id)?.status; + return { + id: producer.id, + mal_id: producer.mal_id, + status: statusProducer, + }; + }); + + await tx.mediaProducer.createMany({ + data: insertedProducers + .filter((p) => p.status === "producer") + .map((producer) => ({ + media_id, + producer_id: producer.id, + })), + skipDuplicates: true, + }); + + await tx.mediaLicensor.createMany({ + data: insertedProducers + .filter((p) => p.status === "licensor") + .map((producer) => ({ + media_id, + licensor_id: producer.id, + })), + skipDuplicates: true, + }); + + await tx.mediaStudio.createMany({ + data: insertedProducers + .filter((p) => p.status === "studio") + .map((producer) => ({ + media_id, + studio_id: producer.id, + })), + skipDuplicates: true, + }); + + return insertedProducers; +}; diff --git a/src/modules/internal/repositories/bulkInsertStudios.repository.ts b/src/modules/internal/repositories/bulkInsertStudios.repository.ts deleted file mode 100644 index 573559a..0000000 --- a/src/modules/internal/repositories/bulkInsertStudios.repository.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { SystemAccountId } from "../../../config/account/system"; -import { generateSlug } from "../../../helpers/characters/generateSlug"; -import { generateUUIDv7 } from "../../../helpers/databases/uuidv7"; -import { AppError } from "../../../helpers/error/instances/app"; -import { prisma } from "../../../utils/databases/prisma/connection"; -import { MediaFullInfoResponse } from "../types/mediaFullInfo.type"; - -/** - * Studios Insertion - * - * This section manages the insertion of studios associated with the media. - * It processes each studio listed in the media data, generating a slug for - * each and performing an upsert operation to either create or update the - * studio record in the database. The IDs of the inserted or updated studios - * are collected for later association with the media. - * - * @param data - The full media data containing studios information. - * @returns An array of IDs of the inserted or updated studios. - */ -export const bulkInsertStudiosRepository = async ( - data: MediaFullInfoResponse, -) => { - try { - const studioIds: string[] = []; - for (const studio of data.data.studios) { - const slug = (await generateSlug(studio.name)) as string; - const studioPayload = { - name: studio.name, - malId: studio.mal_id, - linkAbout: studio.url, - createdBy: SystemAccountId, - slug, - }; - const insertedStudio = await prisma.studio.upsert({ - where: { slug }, - create: { - id: generateUUIDv7(), - ...studioPayload, - }, - update: studioPayload, - select: { id: true }, - }); - studioIds.push(insertedStudio.id); - } - for (const studio of data.data.producers) { - const slug = (await generateSlug(studio.name)) as string; - const studioPayload = { - name: studio.name, - malId: studio.mal_id, - linkAbout: studio.url, - createdBy: SystemAccountId, - slug, - }; - const insertedStudio = await prisma.studio.upsert({ - where: { slug }, - create: { - id: generateUUIDv7(), - ...studioPayload, - }, - update: studioPayload, - select: { id: true }, - }); - studioIds.push(insertedStudio.id); - } - return studioIds; - } catch (error) { - throw new AppError(500, "Failed to insert studios", error); - } -}; diff --git a/src/modules/internal/repositories/bulkinsertMedia.repository.ts b/src/modules/internal/repositories/bulkinsertMedia.repository.ts index 5fe7b54..76ccbfa 100644 --- a/src/modules/internal/repositories/bulkinsertMedia.repository.ts +++ b/src/modules/internal/repositories/bulkinsertMedia.repository.ts @@ -4,6 +4,7 @@ import { prisma } from "../../../utils/databases/prisma/connection"; import { generateUUIDv7 } from "../../../helpers/databases/uuidv7"; import { MediaFullInfoResponse } from "../types/mediaFullInfo.type"; import { SystemAccountId } from "../../../config/account/system"; +import { bulkInsertMediaProducerStudioLicensorRepository } from "./bulkInsertMediaProducerStudioLicensor.repository"; /** * Media Payload Construction and Upsert @@ -109,10 +110,41 @@ export const InsertMediaRepository = async ({ payload }: { payload: MediaFullInf broadcast_day: payload.broadcast.day, }; - return await prisma.media.upsert({ - where: { mal_id: payload.mal_id }, - create: constructMediaPayload, - update: constructMediaPayload, + const producerPayload = [ + ...payload.producers.map((producer) => ({ + mal_id: producer.mal_id, + type: producer.type, + name: producer.name, + url: producer.url, + status: "producer" as const, + })), + ...payload.licensors.map((licensor) => ({ + mal_id: licensor.mal_id, + type: licensor.type, + name: licensor.name, + url: licensor.url, + status: "licensor" as const, + })), + ...payload.studios.map((studio) => ({ + mal_id: studio.mal_id, + type: studio.type, + name: studio.name, + url: studio.url, + status: "studio" as const, + })), + ]; + + prisma.$transaction(async (tx) => { + const media = await tx.media.upsert({ + where: { mal_id: payload.mal_id }, + create: constructMediaPayload, + update: constructMediaPayload, + select: { + id: true, + }, + }); + + await bulkInsertMediaProducerStudioLicensorRepository(tx, media.id, producerPayload); }); } catch (error) { throw new AppError(500, "Failed to insert media", error); diff --git a/src/modules/internal/types/mediaFullInfo.type.ts b/src/modules/internal/types/mediaFullInfo.type.ts index 0725a14..f5bef70 100644 --- a/src/modules/internal/types/mediaFullInfo.type.ts +++ b/src/modules/internal/types/mediaFullInfo.type.ts @@ -33,13 +33,13 @@ interface Data { season: media_season; year: number; broadcast: Broadcast; - producers: Genre[]; - licensors: unknown[]; - studios: Genre[]; - genres: Genre[]; - explicit_genres: unknown[]; - themes: Genre[]; - demographics: unknown[]; + producers: GenreOrProducer[]; + licensors: GenreOrProducer[]; + studios: GenreOrProducer[]; + genres: GenreOrProducer[]; + explicit_genres: GenreOrProducer[]; + themes: GenreOrProducer[]; + demographics: GenreOrProducer[]; relations: Relation[]; theme: Theme; external: External[]; @@ -76,18 +76,13 @@ interface External { url: string; } -interface Genre { +export interface GenreOrProducer { mal_id: number; - type: Type; + type: string; name: string; url: string; } -enum Type { - Anime = "anime", - Manga = "manga", -} - interface Image { image_url: string; small_image_url: string; @@ -96,7 +91,7 @@ interface Image { interface Relation { relation: string; - entry: Genre[]; + entry: GenreOrProducer[]; } interface Theme {