feat: create bulk insert for episode endpoint

This commit is contained in:
Rafi Arrafif
2026-01-29 13:00:19 +07:00
parent 1485971cb7
commit 5c7e82cd52
14 changed files with 169 additions and 20 deletions

View File

@ -1,6 +1,6 @@
import { Context } from "elysia";
import { mainErrorHandler } from "../../../helpers/error/handler";
import { bulkInsertAnimeService } from "../services/bulkInsertAnime.service";
import { bulkInsertAnimeService } from "../services/http/bulkInsertAnime.service";
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
import { bulkInsertCharWithVAService } from "../services/internal/bulkInsertCharWithVA.service";

View File

@ -0,0 +1,24 @@
import { Context } from "elysia";
import { mainErrorHandler } from "../../../helpers/error/handler";
import { bulkInsertEpisodeService } from "../services/http/bulkInsertEpisode.service";
import { returnWriteResponse } from "../../../helpers/callback/httpResponse";
// add pagination query
export const bulkInsertEpisodeController = async (
ctx: Context & { body: { media_mal_id: number }; query: { page?: number } },
) => {
try {
const bulkInsertResult = await bulkInsertEpisodeService(
ctx.body.media_mal_id,
ctx.query.page,
);
return returnWriteResponse(
ctx.set,
201,
"Success bulk insert for episode",
bulkInsertResult,
);
} catch (err) {
return mainErrorHandler(ctx.set, err);
}
};

View File

@ -1,7 +1,7 @@
import Elysia from "elysia";
import { bulkInsertAnimeController } from "./controllers/bulkInsertAnime.controller";
import { bulkInsertEpisodeController } from "./controllers/bulkInsertEpisode.controller";
export const internalModule = new Elysia({ prefix: "/internal" }).post(
"/media/bulk-insert",
bulkInsertAnimeController,
);
export const internalModule = new Elysia({ prefix: "/internal" })
.post("/media/bulk-insert", bulkInsertAnimeController)
.post("/episode/bulk-insert", bulkInsertEpisodeController);

View File

@ -0,0 +1,26 @@
import { Prisma } from "@prisma/client";
import { AppError } from "../../../helpers/error/instances/app";
import { prisma } from "../../../utils/databases/prisma/connection";
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
export const bulkInsertEpisodesRepository = async (
payload: Omit<Prisma.EpisodeUncheckedCreateInput, "id">,
) => {
try {
return await prisma.episode.upsert({
where: {
mediaId_episode: {
mediaId: payload.mediaId as string,
episode: payload.episode as number,
},
},
update: payload,
create: {
id: generateUUIDv7(),
...payload,
},
});
} catch (err) {
throw new AppError(500, "Failed to bulk insert episodes", err);
}
};

View File

@ -1,7 +1,6 @@
import { Prisma } from "@prisma/client";
import { AppError } from "../../../helpers/error/instances/app";
import { prisma } from "../../../utils/databases/prisma/connection";
import { MediaFullInfoResponse } from "../types/mediaFullInfo.type";
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
/**

View File

@ -1,14 +1,14 @@
import { Prisma } from "@prisma/client";
import { getContentReferenceAPI } from "../../../config/apis/media.reference";
import { ErrorForwarder } from "../../../helpers/error/instances/forwarder";
import { bulkInsertGenresRepository } from "../repositories/bulkInsertGenres.repository";
import { InsertMediaRepository } from "../repositories/bulkinsertMedia.repository";
import { bulkInsertStudiosRepository } from "../repositories/bulkInsertStudios.repository";
import { MediaFullInfoResponse } from "../types/mediaFullInfo.type";
import { generateSlug } from "../../../helpers/characters/generateSlug";
import { bulkInsertCharWithVAService } from "./internal/bulkInsertCharWithVA.service";
import { generateUUIDv7 } from "../../../helpers/databases/uuidv7";
import { SystemAccountId } from "../../../config/account/system";
import { getContentReferenceAPI } from "../../../../config/apis/media.reference";
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
import { bulkInsertGenresRepository } from "../../repositories/bulkInsertGenres.repository";
import { InsertMediaRepository } from "../../repositories/bulkinsertMedia.repository";
import { bulkInsertStudiosRepository } from "../../repositories/bulkInsertStudios.repository";
import { MediaFullInfoResponse } from "../../types/mediaFullInfo.type";
import { generateSlug } from "../../../../helpers/characters/generateSlug";
import { bulkInsertCharWithVAService } from "../internal/bulkInsertCharWithVA.service";
import { generateUUIDv7 } from "../../../../helpers/databases/uuidv7";
import { SystemAccountId } from "../../../../config/account/system";
export const bulkInsertAnimeService = async (malId: number) => {
try {

View File

@ -0,0 +1,43 @@
import { Prisma } from "@prisma/client";
import { getEpisodeReferenceAPI } from "../../../../config/apis/episode.reference";
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
import { MediaEpisodeInfoResponse } from "../../types/mediaEpisodeInfo.type";
import { getMediaByMalIdRepository } from "../../../media/repositories/GET/getMediaByMalId.repository";
import { AppError } from "../../../../helpers/error/instances/app";
import { SystemAccountId } from "../../../../config/account/system";
import { bulkInsertEpisodesRepository } from "../../repositories/bulkInsertEpisodes.repository";
export const bulkInsertEpisodeService = async (
mal_id: number,
page: number = 1,
) => {
try {
const episodeAPI = getEpisodeReferenceAPI(mal_id);
const episodeData: MediaEpisodeInfoResponse = await fetch(
`${episodeAPI.baseURL}${episodeAPI.getEpisodeList}?page=${page}`,
).then((res) => res.json());
const mediaData = await getMediaByMalIdRepository(mal_id);
if (!mediaData)
throw new AppError(
404,
`Media with Mal ID ${mal_id} not found in database`,
);
const insertedEpisodeData = [];
episodeData.data.forEach(async (episode) => {
insertedEpisodeData.push(
await bulkInsertEpisodesRepository({
mediaId: mediaData.id!,
episode: episode.mal_id,
name: episode.title,
score: episode.score,
uploadedBy: SystemAccountId,
}),
);
});
return episodeData;
} catch (err) {
ErrorForwarder(err);
}
};

View File

@ -0,0 +1,22 @@
export interface MediaEpisodeInfoResponse {
pagination: Pagination;
data: Datum[];
}
export interface Datum {
mal_id: number;
url: string;
title: string;
title_japanese: string;
title_romanji: string;
aired: Date;
score: number;
filler: boolean;
recap: boolean;
forum_url: string;
}
export interface Pagination {
last_visible_page: number;
has_next_page: boolean;
}