diff --git a/packages/core/src/database/contexts/internalListContext.ts b/packages/core/src/database/contexts/internalListContext.ts index 67d1e520..a1de2f67 100644 --- a/packages/core/src/database/contexts/internalListContext.ts +++ b/packages/core/src/database/contexts/internalListContext.ts @@ -1,5 +1,5 @@ import { SubContext } from "./subContext"; -import { List, Medium, Uuid, MultiSingleNumber, MinList, StorageList, ListMedia } from "../../types"; +import { List, Medium, Uuid, MultiSingleNumber, MinList, StorageList, ListMedia, PromiseMultiSingle } from "../../types"; import { Errors, promiseMultiSingle, multiSingle } from "../../tools"; import { storeModifications } from "../sqlTools"; @@ -51,6 +51,14 @@ export class InternalListContext extends SubContext { return { list: lists, media: loadedMedia }; } + public async getShallowList(listId: T, uuid: Uuid): PromiseMultiSingle { + // TODO: 29.06.2019 replace with id IN (...) + return promiseMultiSingle(listId, async (id: number) => { + const result = await this.query("SELECT * FROM reading_list WHERE uuid = ? AND id = ?;", [uuid, id]); + return this.createShallowList(result[0]); + }); + } + /** * Recreates a list from storage. */ diff --git a/packages/core/src/database/contexts/mediumContext.ts b/packages/core/src/database/contexts/mediumContext.ts index 2bb7c60d..d4f47f2e 100644 --- a/packages/core/src/database/contexts/mediumContext.ts +++ b/packages/core/src/database/contexts/mediumContext.ts @@ -466,6 +466,16 @@ export class MediumContext extends SubContext { ) as Promise; } + public getTocs(tocIds: number[]): Promise { + return this.queryInList( + "SELECT id, medium_id as mediumId, link, " + + "countryOfOrigin, languageOfOrigin, author, title," + + "medium, artist, lang, stateOrigin, stateTL, series, universe " + + "FROM medium_toc WHERE id IN (??);", + [tocIds], + ) as Promise; + } + public async removeMediumToc(mediumId: number, link: string): Promise { const domainRegMatch = /https?:\/\/(.+?)(\/|$)/.exec(link); diff --git a/packages/core/src/database/contexts/partContext.ts b/packages/core/src/database/contexts/partContext.ts index 73b1d9a9..327d1efe 100644 --- a/packages/core/src/database/contexts/partContext.ts +++ b/packages/core/src/database/contexts/partContext.ts @@ -152,22 +152,25 @@ export class PartContext extends SubContext { /** * Returns all parts of an medium. */ - public async getParts(partId: T, uuid: Uuid): Promise { + public async getParts(partId: T, uuid: Uuid, full = true): Promise { const parts: Optional = await this.queryInList("SELECT * FROM part WHERE id IN (??);", [partId]); if (!parts || !parts.length) { return []; } const partIdMap = new Map(); - const episodesResult: Optional = await this.queryInList("SELECT id FROM episode WHERE part_id IN (??);", [ - parts.map((value) => { - partIdMap.set(value.id, value); - return value.id; - }), - ]); + const episodesResult: Optional = await this.queryInList( + "SELECT id, part_id FROM episode WHERE part_id IN (??);", + [ + parts.map((value) => { + partIdMap.set(value.id, value); + return value.id; + }), + ], + ); - const episodes = episodesResult || []; + const episodes: Array<{ id: number; part_id: number }> = episodesResult || []; - if (episodes) { + if (full) { const episodeIds = episodes.map((value) => value.id); const fullEpisodes = await this.parentContext.episodeContext.getEpisode(episodeIds, uuid); fullEpisodes.forEach((value) => { @@ -180,6 +183,11 @@ export class PartContext extends SubContext { } part.episodes.push(value); }); + } else { + episodes.forEach((value) => { + const part: Part = partIdMap.get(value.part_id); + (part.episodes as number[]).push(value.id); + }); } return parts.map((part) => { return { diff --git a/packages/core/src/database/contexts/queryContext.ts b/packages/core/src/database/contexts/queryContext.ts index e4870a03..b6b10ac5 100644 --- a/packages/core/src/database/contexts/queryContext.ts +++ b/packages/core/src/database/contexts/queryContext.ts @@ -14,6 +14,8 @@ import { Primitive, DataStats, NewData, + QueryItems, + QueryItemsResult, } from "../../types"; import { Errors, getElseSet, getElseSetObj, ignore, multiSingle, promiseMultiSingle, batch } from "../../tools"; import logger from "../../logger"; @@ -730,6 +732,48 @@ export class QueryContext implements ConnectionContext { }; } + public async queryItems(uuid: Uuid, query: QueryItems): Promise { + const [ + externalUser, + externalMediaLists, + mediaLists, + mediaTocs, + tocs, + media, + parts, + partReleases, + partEpisodes, + episodes, + episodeReleases, + ] = await Promise.all([ + this.externalUserContext.getExternalUser(query.externalUser), + Promise.all(query.externalMediaLists.map((id) => this.externalListContext.getExternalList(id))), + this.internalListContext.getShallowList(query.mediaLists, uuid), + this.mediumContext.getMediumTocs(query.mediaTocs), + this.mediumContext.getTocs(query.tocs), + this.mediumContext.getSimpleMedium(query.media), + this.partContext.getParts(query.parts, uuid, false), + this.partContext.getPartReleases(query.partReleases), + this.partContext.getPartItems(query.partEpisodes), + this.episodeContext.getEpisode(query.episodes, uuid), + this.episodeContext.getReleases(query.episodeReleases), + ]); + + return { + episodeReleases, // by episode id + episodes, + partEpisodes, // by part id + partReleases, // by part id + parts, + media, + tocs, // by toc id + mediaTocs, // by medium id + mediaLists, + externalMediaLists, + externalUser, + }; + } + private async _batchFunction( value: T[], query: string, diff --git a/packages/core/src/database/storages/storage.ts b/packages/core/src/database/storages/storage.ts index 39507b5d..f5da9164 100644 --- a/packages/core/src/database/storages/storage.ts +++ b/packages/core/src/database/storages/storage.ts @@ -13,6 +13,8 @@ import { Nullable, DataStats, NewData, + QueryItems, + QueryItemsResult, } from "../../types"; import logger from "../../logger"; import { databaseSchema } from "../databaseSchema"; @@ -341,6 +343,10 @@ export class Storage { return inContext((context) => context.getNew(uuid, date)); } + public queryItems(uuid: Uuid, query: QueryItems): Promise { + return inContext((context) => context.queryItems(uuid, query)); + } + /** * * @param result diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index a0637329..9598fa1f 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1871,3 +1871,31 @@ export interface CustomHook { hookState: HookState; comment: string; } + +export interface QueryItems { + episodeReleases: number[]; // by episode id + episodes: number[]; + partEpisodes: number[]; // by part id + partReleases: number[]; // by part id + parts: number[]; + media: number[]; + tocs: number[]; // by toc id + mediaTocs: number[]; // by medium id + mediaLists: number[]; + externalMediaLists: number[]; + externalUser: string[]; +} + +export interface QueryItemsResult { + episodeReleases: EpisodeRelease[]; // by episode id + episodes: Episode[]; + partEpisodes: Record; // by part id + partReleases: Record; // by part id + parts: Part[]; + media: SimpleMedium[]; + tocs: FullMediumToc[]; // by toc id + mediaTocs: FullMediumToc[]; // by medium id + mediaLists: List[]; + externalMediaLists: ExternalList[]; + externalUser: ExternalUser[]; +} diff --git a/packages/server/src/api/user.ts b/packages/server/src/api/user.ts index 53a098b9..5eb3d2cb 100644 --- a/packages/server/src/api/user.ts +++ b/packages/server/src/api/user.ts @@ -31,6 +31,9 @@ import { AppEventProgram, AppEventType, AppEvent, + QueryItems, + QueryItemsResult, + Uuid, } from "enterprise-core/dist/types"; import { Handler, Router } from "express"; import { extractQueryParam, createHandler } from "./apiTools"; @@ -386,6 +389,11 @@ const getStatus = createHandler(async (): Promise => { }; }); +const postLoad = createHandler(async (request): Promise => { + const { items, uuid }: { items: QueryItems; uuid: Uuid } = request.body; + return storage.queryItems(uuid, items); +}); + /** * Creates the User Api Router. * @@ -891,6 +899,7 @@ export function userRouter(): Router { */ router.get("/events", getAllAppEvents); router.get("/status", getStatus); + router.post("/load", postLoad); router.use("/medium", mediumRouter()); router.use("/jobs", jobsRouter());