Reduce source requests during bulk migration
During the search the destination entries are already freshly fetched. Thus, this is not necessary anymore during the actual migration
This commit is contained in:
@@ -126,7 +126,7 @@ export const MangaCard = memo((props: MangaCardProps) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
await MangaMigration.migrate(migrationSourceMangaId, id, options);
|
await MangaMigration.migrateByIdWithFetch(migrationSourceMangaId, id, options);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
makeToast(
|
makeToast(
|
||||||
t(MANGA_ACTION_TO_TRANSLATION['migrate'].error),
|
t(MANGA_ACTION_TO_TRANSLATION['migrate'].error),
|
||||||
|
|||||||
@@ -14,13 +14,28 @@ import type {
|
|||||||
} from '@/lib/graphql/generated/graphql.ts';
|
} from '@/lib/graphql/generated/graphql.ts';
|
||||||
import type { MangaIdInfo } from '@/features/manga/Manga.types.ts';
|
import type { MangaIdInfo } from '@/features/manga/Manga.types.ts';
|
||||||
import { Chapters } from '@/features/chapter/services/Chapters.ts';
|
import { Chapters } from '@/features/chapter/services/Chapters.ts';
|
||||||
import { getMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts';
|
|
||||||
import { ALL_APP_METADATA_KEY_PREFIXES } from '@/features/metadata/Metadata.constants.ts';
|
import { ALL_APP_METADATA_KEY_PREFIXES } from '@/features/metadata/Metadata.constants.ts';
|
||||||
import type { MigrateMode, MigrateOptions } from '@/features/migration/Migration.types.ts';
|
import type { MigrateMode, MigrateOptions } from '@/features/migration/Migration.types.ts';
|
||||||
|
import type {
|
||||||
|
ChapterBookmarkInfo,
|
||||||
|
ChapterDownloadInfo,
|
||||||
|
ChapterIdInfo,
|
||||||
|
ChapterNumberInfo,
|
||||||
|
ChapterReadInfo,
|
||||||
|
} from '@/features/chapter/Chapter.types.ts';
|
||||||
|
import type { GqlMetaHolder } from '@/features/metadata/Metadata.types.ts';
|
||||||
|
import { getMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts';
|
||||||
|
|
||||||
type MangaToMigrate = NonNullable<GetMangaToMigrateQuery['manga']>;
|
type MangaToMigrate = NonNullable<GetMangaToMigrateQuery['manga']>;
|
||||||
type MangaToMigrateTo = NonNullable<GetMangaToMigrateToFetchMutation['fetchManga']>['manga'];
|
type MangaToMigrateTo = NonNullable<GetMangaToMigrateToFetchMutation['fetchManga']>['manga'];
|
||||||
|
|
||||||
|
export type MigrationChapter = ChapterIdInfo &
|
||||||
|
ChapterReadInfo &
|
||||||
|
ChapterBookmarkInfo &
|
||||||
|
ChapterNumberInfo &
|
||||||
|
ChapterDownloadInfo &
|
||||||
|
GqlMetaHolder;
|
||||||
|
|
||||||
type MigrateAction = { copy: () => Promise<unknown>[]; cleanup: () => Promise<unknown>[] };
|
type MigrateAction = { copy: () => Promise<unknown>[]; cleanup: () => Promise<unknown>[] };
|
||||||
type MigrateActionCreator = () => MigrateAction;
|
type MigrateActionCreator = () => MigrateAction;
|
||||||
|
|
||||||
@@ -29,8 +44,9 @@ const performMigrationAction = async (migrateAction: keyof MigrateAction, ...act
|
|||||||
|
|
||||||
export class MangaMigration {
|
export class MangaMigration {
|
||||||
static async migrate(
|
static async migrate(
|
||||||
mangaId: MangaIdInfo['id'],
|
mangaToMigrate: MangaToMigrate | null | undefined,
|
||||||
mangaIdToMigrateTo: number,
|
mangaToMigrateTo: MangaToMigrateTo | null | undefined,
|
||||||
|
chaptersToMigrateTo: MigrationChapter[] | null | undefined,
|
||||||
{
|
{
|
||||||
mode,
|
mode,
|
||||||
migrateChapters,
|
migrateChapters,
|
||||||
@@ -39,37 +55,16 @@ export class MangaMigration {
|
|||||||
deleteChapters,
|
deleteChapters,
|
||||||
migrateMetadata,
|
migrateMetadata,
|
||||||
}: Omit<MigrateOptions, 'mangaIdToMigrateTo'>,
|
}: Omit<MigrateOptions, 'mangaIdToMigrateTo'>,
|
||||||
|
removeMangaFromCategories: boolean,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const [{ data: mangaToMigrateData }, { data: mangaToMigrateToData }, { removeMangaFromCategories }] =
|
if (!mangaToMigrate || !mangaToMigrateTo) {
|
||||||
await Promise.all([
|
|
||||||
requestManager.getMangaToMigrate(mangaId, {
|
|
||||||
migrateChapters,
|
|
||||||
migrateCategories,
|
|
||||||
migrateTracking,
|
|
||||||
deleteChapters,
|
|
||||||
migrateMetadata,
|
|
||||||
}).response,
|
|
||||||
requestManager.getMangaToMigrateToFetch(mangaIdToMigrateTo, {
|
|
||||||
migrateChapters,
|
|
||||||
migrateCategories,
|
|
||||||
migrateTracking,
|
|
||||||
apolloOptions: { errorPolicy: 'all' },
|
|
||||||
}).response,
|
|
||||||
getMetadataServerSettings(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!mangaToMigrateData?.manga || !mangaToMigrateToData?.fetchManga?.manga) {
|
|
||||||
throw new Error('MangaMigration::migrate: missing manga data');
|
throw new Error('MangaMigration::migrate: missing manga data');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (migrateChapters && !mangaToMigrateData.manga.chapters) {
|
if (migrateChapters && !mangaToMigrate.chapters) {
|
||||||
throw new Error('MangaMigration::migrate: missing chapters data');
|
throw new Error('MangaMigration::migrate: missing chapters data');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mangaToMigrateToData.fetchChapters?.chapters) {
|
|
||||||
mangaToMigrateToData.fetchChapters = { chapters: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
const performMigrationActions = async (...actionCreators: [boolean | undefined, MigrateActionCreator][]) => {
|
const performMigrationActions = async (...actionCreators: [boolean | undefined, MigrateActionCreator][]) => {
|
||||||
const migrationActions: TupleUnion<keyof MigrateAction> = ['copy', 'cleanup'];
|
const migrationActions: TupleUnion<keyof MigrateAction> = ['copy', 'cleanup'];
|
||||||
|
|
||||||
@@ -92,28 +87,20 @@ export class MangaMigration {
|
|||||||
() =>
|
() =>
|
||||||
MangaMigration.migrateChapters(
|
MangaMigration.migrateChapters(
|
||||||
mode,
|
mode,
|
||||||
mangaToMigrateData.manga,
|
mangaToMigrate.chapters?.nodes,
|
||||||
mangaToMigrateToData,
|
chaptersToMigrateTo,
|
||||||
!!deleteChapters,
|
!!deleteChapters,
|
||||||
!!migrateMetadata,
|
!!migrateMetadata,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[
|
[migrateTracking, () => MangaMigration.migrateTracking(mode, mangaToMigrate, mangaToMigrateTo)],
|
||||||
migrateTracking,
|
|
||||||
() =>
|
|
||||||
MangaMigration.migrateTracking(
|
|
||||||
mode,
|
|
||||||
mangaToMigrateData.manga,
|
|
||||||
mangaToMigrateToData.fetchManga!.manga,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
true,
|
true,
|
||||||
() =>
|
() =>
|
||||||
MangaMigration.migrateManga(
|
MangaMigration.migrateManga(
|
||||||
mode,
|
mode,
|
||||||
mangaToMigrateData.manga,
|
mangaToMigrate,
|
||||||
mangaToMigrateToData.fetchManga!.manga,
|
mangaToMigrateTo,
|
||||||
!!migrateCategories,
|
!!migrateCategories,
|
||||||
removeMangaFromCategories,
|
removeMangaFromCategories,
|
||||||
!!migrateMetadata,
|
!!migrateMetadata,
|
||||||
@@ -122,20 +109,86 @@ export class MangaMigration {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async migrateByIdWithQuery(
|
||||||
|
mangaId: MangaIdInfo['id'],
|
||||||
|
mangaIdToMigrateTo: number,
|
||||||
|
options: Omit<MigrateOptions, 'mangaIdToMigrateTo'>,
|
||||||
|
): Promise<void> {
|
||||||
|
const { migrateChapters, migrateCategories, migrateTracking, deleteChapters, migrateMetadata } = options;
|
||||||
|
|
||||||
|
const [{ data: mangaToMigrateData }, { data: mangaToMigrateToData }, { removeMangaFromCategories }] =
|
||||||
|
await Promise.all([
|
||||||
|
requestManager.getMangaToMigrate(mangaId, {
|
||||||
|
migrateChapters,
|
||||||
|
migrateCategories,
|
||||||
|
migrateTracking,
|
||||||
|
deleteChapters,
|
||||||
|
migrateMetadata,
|
||||||
|
}).response,
|
||||||
|
requestManager.getMangaToMigrate(mangaIdToMigrateTo, {
|
||||||
|
migrateChapters,
|
||||||
|
migrateCategories,
|
||||||
|
migrateTracking,
|
||||||
|
deleteChapters,
|
||||||
|
migrateMetadata,
|
||||||
|
}).response,
|
||||||
|
getMetadataServerSettings(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await MangaMigration.migrate(
|
||||||
|
mangaToMigrateData?.manga,
|
||||||
|
mangaToMigrateToData?.manga,
|
||||||
|
mangaToMigrateToData?.manga?.chapters?.nodes,
|
||||||
|
options,
|
||||||
|
removeMangaFromCategories,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async migrateByIdWithFetch(
|
||||||
|
mangaId: MangaIdInfo['id'],
|
||||||
|
mangaIdToMigrateTo: number,
|
||||||
|
options: Omit<MigrateOptions, 'mangaIdToMigrateTo'>,
|
||||||
|
): Promise<void> {
|
||||||
|
const { migrateChapters, migrateCategories, migrateTracking, deleteChapters, migrateMetadata } = options;
|
||||||
|
|
||||||
|
const [{ data: mangaToMigrateData }, { data: mangaToMigrateToData }, { removeMangaFromCategories }] =
|
||||||
|
await Promise.all([
|
||||||
|
requestManager.getMangaToMigrate(mangaId, {
|
||||||
|
migrateChapters,
|
||||||
|
migrateCategories,
|
||||||
|
migrateTracking,
|
||||||
|
deleteChapters,
|
||||||
|
migrateMetadata,
|
||||||
|
}).response,
|
||||||
|
requestManager.getMangaToMigrateToFetch(mangaIdToMigrateTo, {
|
||||||
|
migrateChapters,
|
||||||
|
migrateCategories,
|
||||||
|
migrateTracking,
|
||||||
|
apolloOptions: { errorPolicy: 'all' },
|
||||||
|
}).response,
|
||||||
|
getMetadataServerSettings(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await MangaMigration.migrate(
|
||||||
|
mangaToMigrateData?.manga,
|
||||||
|
mangaToMigrateToData?.fetchManga?.manga,
|
||||||
|
mangaToMigrateToData?.fetchChapters?.chapters,
|
||||||
|
options,
|
||||||
|
removeMangaFromCategories,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private static migrateChapters(
|
private static migrateChapters(
|
||||||
mode: MigrateMode,
|
mode: MigrateMode,
|
||||||
mangaToMigrate: GetMangaToMigrateQuery['manga'],
|
chaptersToMigrate: MigrationChapter[] | null | undefined,
|
||||||
mangaToMigrateToInfo: GetMangaToMigrateToFetchMutation,
|
chaptersToMigrateTo: MigrationChapter[] | null | undefined,
|
||||||
deleteChapters: boolean,
|
deleteChapters: boolean,
|
||||||
migrateMetadata: boolean,
|
migrateMetadata: boolean,
|
||||||
): MigrateAction {
|
): MigrateAction {
|
||||||
if (!mangaToMigrate.chapters || !mangaToMigrateToInfo.fetchChapters?.chapters) {
|
if (!chaptersToMigrate || !chaptersToMigrateTo) {
|
||||||
throw new Error('Chapters are missing');
|
throw new Error('Chapters are missing');
|
||||||
}
|
}
|
||||||
|
|
||||||
const chaptersToMigrate = mangaToMigrate.chapters.nodes;
|
|
||||||
|
|
||||||
const chaptersToMigrateTo = mangaToMigrateToInfo.fetchChapters?.chapters;
|
|
||||||
const migratableChapters = Chapters.getMatchingChapterNumberChapters(chaptersToMigrate, chaptersToMigrateTo);
|
const migratableChapters = Chapters.getMatchingChapterNumberChapters(chaptersToMigrate, chaptersToMigrateTo);
|
||||||
|
|
||||||
const highestReadChapterNumber = chaptersToMigrate.reduce((chapterNumber, chapterToMigrate) => {
|
const highestReadChapterNumber = chaptersToMigrate.reduce((chapterNumber, chapterToMigrate) => {
|
||||||
@@ -197,7 +250,7 @@ export class MangaMigration {
|
|||||||
? [
|
? [
|
||||||
deleteChapters
|
deleteChapters
|
||||||
? requestManager.deleteDownloadedChapters(
|
? requestManager.deleteDownloadedChapters(
|
||||||
Chapters.getIds(Chapters.getDownloaded(mangaToMigrate.chapters?.nodes ?? [])),
|
Chapters.getIds(Chapters.getDownloaded(chaptersToMigrate)),
|
||||||
).response
|
).response
|
||||||
: Promise.resolve(),
|
: Promise.resolve(),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -963,7 +963,8 @@ export class MigrationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertIsDefined(entry.selectedMatchMangaId);
|
assertIsDefined(entry.selectedMatchMangaId);
|
||||||
await MangaMigration.migrate(mangaId, entry.selectedMatchMangaId, options);
|
|
||||||
|
await MangaMigration.migrateByIdWithQuery(mangaId, entry.selectedMatchMangaId, options);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user