✨ feat: create bulk insertion for characters
This commit is contained in:
@ -90,6 +90,7 @@ Table characters {
|
|||||||
deletedAt DateTime
|
deletedAt DateTime
|
||||||
createdAt DateTime [default: `now()`, not null]
|
createdAt DateTime [default: `now()`, not null]
|
||||||
updatedAt DateTime [default: `now()`, not null]
|
updatedAt DateTime [default: `now()`, not null]
|
||||||
|
voice_actors lang_va_char [not null]
|
||||||
}
|
}
|
||||||
|
|
||||||
Table voice_actors {
|
Table voice_actors {
|
||||||
@ -106,6 +107,24 @@ Table voice_actors {
|
|||||||
deletedAt DateTime
|
deletedAt DateTime
|
||||||
createdAt DateTime [default: `now()`, not null]
|
createdAt DateTime [default: `now()`, not null]
|
||||||
updatedAt DateTime [default: `now()`, not null]
|
updatedAt DateTime [default: `now()`, not null]
|
||||||
|
characters lang_va_char [not null]
|
||||||
|
}
|
||||||
|
|
||||||
|
Table lang_va_char {
|
||||||
|
id String [pk]
|
||||||
|
language String [not null]
|
||||||
|
voiceActor voice_actors [not null]
|
||||||
|
vaId String [not null]
|
||||||
|
character characters [not null]
|
||||||
|
charId String [not null]
|
||||||
|
createdBy users [not null]
|
||||||
|
creatorId String [not null]
|
||||||
|
createdAt DateTime [default: `now()`, not null]
|
||||||
|
updatedAt DateTime [default: `now()`, not null]
|
||||||
|
|
||||||
|
indexes {
|
||||||
|
(language, vaId, charId) [unique]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Table episodes {
|
Table episodes {
|
||||||
@ -205,6 +224,7 @@ Table users {
|
|||||||
studios studios [not null]
|
studios studios [not null]
|
||||||
characters characters [not null]
|
characters characters [not null]
|
||||||
voice_actor voice_actors [not null]
|
voice_actor voice_actors [not null]
|
||||||
|
lang_va_char lang_va_char [not null]
|
||||||
episodes episodes [not null]
|
episodes episodes [not null]
|
||||||
episode_likes episode_likes [not null]
|
episode_likes episode_likes [not null]
|
||||||
videos videos [not null]
|
videos videos [not null]
|
||||||
@ -647,6 +667,12 @@ Ref: characters.creatorId > users.id
|
|||||||
|
|
||||||
Ref: voice_actors.creatorId > users.id
|
Ref: voice_actors.creatorId > users.id
|
||||||
|
|
||||||
|
Ref: lang_va_char.vaId > voice_actors.id
|
||||||
|
|
||||||
|
Ref: lang_va_char.charId > characters.id
|
||||||
|
|
||||||
|
Ref: lang_va_char.creatorId > users.id
|
||||||
|
|
||||||
Ref: episodes.mediaId > medias.id
|
Ref: episodes.mediaId > medias.id
|
||||||
|
|
||||||
Ref: episodes.uploadedBy > users.id
|
Ref: episodes.uploadedBy > users.id
|
||||||
|
|||||||
@ -124,6 +124,7 @@ model Character {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
|
voice_actors LangVAChar[] @relation("CharVALanguage")
|
||||||
@@map("characters")
|
@@map("characters")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +143,26 @@ model VoiceActor {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
|
characters LangVAChar[] @relation("VACharLanguage")
|
||||||
@@map("voice_actors")
|
@@map("voice_actors")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model LangVAChar {
|
||||||
|
id String @id @default(uuid()) @db.Uuid
|
||||||
|
language String
|
||||||
|
voiceActor VoiceActor @relation("VACharLanguage", fields: [vaId], references: [id])
|
||||||
|
vaId String @db.Uuid
|
||||||
|
character Character @relation("CharVALanguage", fields: [charId], references: [id])
|
||||||
|
charId String @db.Uuid
|
||||||
|
createdBy User @relation("UserCreatedLangVAChar", fields: [creatorId], references: [id])
|
||||||
|
creatorId String
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
|
|
||||||
|
@@unique([language, vaId, charId])
|
||||||
|
@@map("lang_va_char")
|
||||||
|
}
|
||||||
|
|
||||||
model Episode {
|
model Episode {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
media Media @relation("MediaEpisodes", fields: [mediaId], references: [id])
|
media Media @relation("MediaEpisodes", fields: [mediaId], references: [id])
|
||||||
@ -249,6 +267,7 @@ model User {
|
|||||||
studios Studio[] @relation("UserCreatedStudios")
|
studios Studio[] @relation("UserCreatedStudios")
|
||||||
characters Character[] @relation("UserCreatedCharacters")
|
characters Character[] @relation("UserCreatedCharacters")
|
||||||
voice_actor VoiceActor[] @relation("UserCreatedVoiceActors")
|
voice_actor VoiceActor[] @relation("UserCreatedVoiceActors")
|
||||||
|
lang_va_char LangVAChar[] @relation("UserCreatedLangVAChar")
|
||||||
episodes Episode[] @relation("UserEpisodes")
|
episodes Episode[] @relation("UserEpisodes")
|
||||||
episode_likes EpisodeLike[] @relation("UserEpisodeLikes")
|
episode_likes EpisodeLike[] @relation("UserEpisodeLikes")
|
||||||
videos Video[] @relation("UserVideos")
|
videos Video[] @relation("UserVideos")
|
||||||
|
|||||||
1
src/config/account/system.ts
Normal file
1
src/config/account/system.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const SystemAccountId = "b734b9bc-b4ea-408f-a80e-0a837ce884da";
|
||||||
1
src/config/apis/baseUrl.ts
Normal file
1
src/config/apis/baseUrl.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const baseURL = "https://api.jikan.moe/v4";
|
||||||
@ -1,6 +1,8 @@
|
|||||||
|
import { baseURL } from "./baseUrl";
|
||||||
|
|
||||||
export const getContentReferenceAPI = (malId: number) => {
|
export const getContentReferenceAPI = (malId: number) => {
|
||||||
return {
|
return {
|
||||||
baseURL: "https://api.jikan.moe/v4",
|
baseURL,
|
||||||
getMediaFullInfo: `/anime/${malId}/full`,
|
getMediaFullInfo: `/anime/${malId}/full`,
|
||||||
getMediaCharactersWithVA: `/anime/${malId}/characters`,
|
getMediaCharactersWithVA: `/anime/${malId}/characters`,
|
||||||
};
|
};
|
||||||
|
|||||||
8
src/config/apis/people.reference.ts
Normal file
8
src/config/apis/people.reference.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { baseURL } from "./baseUrl";
|
||||||
|
|
||||||
|
export const getPeopleAPI = (malId: number) => {
|
||||||
|
return {
|
||||||
|
baseURL,
|
||||||
|
getPeopleInfo: `/people/${malId}`,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { AppError } from "../../../helpers/error/instances/app";
|
||||||
|
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||||
|
|
||||||
|
export const bulkInsertCharactersRepository = async (
|
||||||
|
payload: Prisma.CharacterUpsertArgs["create"],
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
return await prisma.character.upsert({
|
||||||
|
where: { malId: payload.malId },
|
||||||
|
create: payload,
|
||||||
|
update: payload,
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(500, "Failed to bulk insert characters", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
import { AppError } from "../../../helpers/error/instances/app";
|
||||||
|
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||||
|
|
||||||
|
export const bulkInsertLangVARepository = async (
|
||||||
|
payload: Prisma.LangVACharUpsertArgs["create"],
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const insertedVA = await prisma.langVAChar.upsert({
|
||||||
|
where: {
|
||||||
|
language_vaId_charId: {
|
||||||
|
language: payload.language,
|
||||||
|
vaId: payload.vaId!,
|
||||||
|
charId: payload.charId!,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
create: payload,
|
||||||
|
update: {},
|
||||||
|
});
|
||||||
|
return insertedVA.id;
|
||||||
|
} catch (error) {
|
||||||
|
throw new AppError(500, "Failed to bulk insert VAs", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -2,18 +2,17 @@ import { Prisma } from "@prisma/client";
|
|||||||
import { AppError } from "../../../helpers/error/instances/app";
|
import { AppError } from "../../../helpers/error/instances/app";
|
||||||
import { prisma } from "../../../utils/databases/prisma/connection";
|
import { prisma } from "../../../utils/databases/prisma/connection";
|
||||||
|
|
||||||
export const bulkInsertVARepository = async (
|
export const bulkInsertVoiceActorRepository = async (
|
||||||
payload: Prisma.VoiceActorUpsertArgs["create"],
|
payload: Prisma.VoiceActorUpsertArgs["create"],
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const insertedVA = await prisma.voiceActor.upsert({
|
return await prisma.voiceActor.upsert({
|
||||||
where: { malId: payload.malId },
|
where: { malId: payload.malId },
|
||||||
create: payload,
|
create: payload,
|
||||||
update: payload,
|
update: payload,
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
});
|
});
|
||||||
return insertedVA.id;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new AppError(500, "Failed to bulk insert VAs", error);
|
throw new AppError(500, "Failed to bulk insert voice actor", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1,6 +1,10 @@
|
|||||||
|
import { SystemAccountId } from "../../../../config/account/system";
|
||||||
import { getContentReferenceAPI } from "../../../../config/apis/media.reference";
|
import { getContentReferenceAPI } from "../../../../config/apis/media.reference";
|
||||||
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
|
import { bulkInsertCharactersRepository } from "../../repositories/bulkInsertCharacters.repository";
|
||||||
|
import { bulkInsertLangVARepository } from "../../repositories/bulkInsertLangVA.repository";
|
||||||
import { MediaCharWithVAInfo } from "../../types/mediaCharWithVAInfo";
|
import { MediaCharWithVAInfo } from "../../types/mediaCharWithVAInfo";
|
||||||
|
import { bulkInsertStaffOrPeopleService } from "./bulkInsertStaffOrPeople.service";
|
||||||
|
|
||||||
export const bulkInsertCharWithVAService = async (malId: number) => {
|
export const bulkInsertCharWithVAService = async (malId: number) => {
|
||||||
try {
|
try {
|
||||||
@ -9,7 +13,45 @@ export const bulkInsertCharWithVAService = async (malId: number) => {
|
|||||||
`${baseURL}${getMediaCharactersWithVA}`,
|
`${baseURL}${getMediaCharactersWithVA}`,
|
||||||
).then((res) => res.json())) as MediaCharWithVAInfo;
|
).then((res) => res.json())) as MediaCharWithVAInfo;
|
||||||
|
|
||||||
return;
|
const insertedCharacters = [];
|
||||||
|
for (const charEntry of charactersWithVAData.data) {
|
||||||
|
// Insert character if not exists
|
||||||
|
const characterInsertedId = await bulkInsertCharactersRepository({
|
||||||
|
malId: charEntry.character.mal_id,
|
||||||
|
name: charEntry.character.name,
|
||||||
|
role: charEntry.role,
|
||||||
|
favorites: charEntry.favorites,
|
||||||
|
imageUrl: charEntry.character.images.webp.image_url,
|
||||||
|
smallImageUrl: charEntry.character.images.webp.small_image_url,
|
||||||
|
creatorId: SystemAccountId,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Insert character voice actors if not exists
|
||||||
|
const insertedVAs: { staffId: string; lang: string }[] = [];
|
||||||
|
for (const VAEntries of charEntry.voice_actors) {
|
||||||
|
const insertedVAId = await bulkInsertStaffOrPeopleService(
|
||||||
|
VAEntries.person.mal_id,
|
||||||
|
);
|
||||||
|
insertedVAs.push({
|
||||||
|
staffId: insertedVAId.id,
|
||||||
|
lang: VAEntries.language,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link character with inserted VAs
|
||||||
|
for (const langVA of insertedVAs) {
|
||||||
|
await bulkInsertLangVARepository({
|
||||||
|
language: langVA.lang,
|
||||||
|
vaId: langVA.staffId,
|
||||||
|
charId: characterInsertedId.id,
|
||||||
|
creatorId: SystemAccountId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
insertedCharacters.push(characterInsertedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return insertedCharacters;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ErrorForwarder(error);
|
ErrorForwarder(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { SystemAccountId } from "../../../../config/account/system";
|
||||||
|
import { getPeopleAPI } from "../../../../config/apis/people.reference";
|
||||||
|
import { ErrorForwarder } from "../../../../helpers/error/instances/forwarder";
|
||||||
|
import { bulkInsertVoiceActorRepository } from "../../repositories/bulkInsertVoiceActor.repository";
|
||||||
|
import { PeopleInfoResponse } from "../../types/peopleInfo";
|
||||||
|
|
||||||
|
export const bulkInsertStaffOrPeopleService = async (malId: number) => {
|
||||||
|
try {
|
||||||
|
const { baseURL, getPeopleInfo } = getPeopleAPI(malId);
|
||||||
|
const peopleData = (await fetch(baseURL + getPeopleInfo).then((res) =>
|
||||||
|
res.json(),
|
||||||
|
)) as PeopleInfoResponse;
|
||||||
|
|
||||||
|
return await bulkInsertVoiceActorRepository({
|
||||||
|
malId: peopleData.data.mal_id,
|
||||||
|
name: peopleData.data.name,
|
||||||
|
birthday: peopleData.data.birthday,
|
||||||
|
description: peopleData.data.about,
|
||||||
|
aboutUrl: peopleData.data.url,
|
||||||
|
imageUrl: peopleData.data.images.jpg.image_url,
|
||||||
|
websiteUrl: peopleData.data.website_url,
|
||||||
|
creatorId: SystemAccountId,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
ErrorForwarder(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
25
src/modules/internal/types/peopleInfo.ts
Normal file
25
src/modules/internal/types/peopleInfo.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
export interface PeopleInfoResponse {
|
||||||
|
data: Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
mal_id: number;
|
||||||
|
url: string;
|
||||||
|
website_url: null;
|
||||||
|
images: Images;
|
||||||
|
name: string;
|
||||||
|
given_name: null;
|
||||||
|
family_name: null;
|
||||||
|
alternate_names: any[];
|
||||||
|
birthday: Date;
|
||||||
|
favorites: number;
|
||||||
|
about: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Images {
|
||||||
|
jpg: Jpg;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Jpg {
|
||||||
|
image_url: string;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user