Add new single multipurpose metadata update mutation

This commit is contained in:
schroda
2026-01-25 20:32:56 +01:00
parent 474b98abb5
commit 64df9a9489
14 changed files with 830 additions and 213 deletions

View File

@@ -104,3 +104,32 @@ export const UPDATE_CATEGORY_ORDER = gql`
}
}
`;
export const UPDATE_CATEGORY_METADATA = gql`
${CATEGORY_META_FIELDS}
mutation UPDATE_CATEGORY_METADATA(
$updateInput: SetCategoryMetasInput!
$hasUpdates: Boolean!
$deleteInput: DeleteCategoryMetasInput!
$hasDeletions: Boolean!
$migrateInput: SetCategoryMetasInput!
$isMigration: Boolean!
) {
updatedMeta: setCategoryMetas(input: $updateInput) @include(if: $hasUpdates) {
metas {
...CATEGORY_META_FIELDS
}
}
deletedMeta: deleteCategoryMetas(input: $deleteInput) @include(if: $hasDeletions) {
metas {
...CATEGORY_META_FIELDS
}
}
migrationMeta: setCategoryMetas(input: $migrateInput) @include(if: $isMigration) {
metas {
...CATEGORY_META_FIELDS
}
}
}
`;

View File

@@ -181,3 +181,32 @@ export const UPDATE_CHAPTERS = gql`
}
}
`;
export const UPDATE_CHAPTER_METADATA = gql`
${CHAPTER_META_FIELDS}
mutation UPDATE_CHAPTER_METADATA(
$updateInput: SetChapterMetasInput!
$hasUpdates: Boolean!
$deleteInput: DeleteChapterMetasInput!
$hasDeletions: Boolean!
$migrateInput: SetChapterMetasInput!
$isMigration: Boolean!
) {
updatedMeta: setChapterMetas(input: $updateInput) @include(if: $hasUpdates) {
metas {
...CHAPTER_META_FIELDS
}
}
deletedMeta: deleteChapterMetas(input: $deleteInput) @include(if: $hasDeletions) {
metas {
...CHAPTER_META_FIELDS
}
}
migrationMeta: setChapterMetas(input: $migrateInput) @include(if: $isMigration) {
metas {
...CHAPTER_META_FIELDS
}
}
}
`;

View File

@@ -3552,6 +3552,18 @@ export type UpdateCategoryOrderMutationVariables = Exact<{
export type UpdateCategoryOrderMutation = { __typename?: 'Mutation', updateCategoryOrder?: { __typename?: 'UpdateCategoryOrderPayload', categories: Array<{ __typename?: 'CategoryType', id: number, order: number }> } | null };
export type UpdateCategoryMetadataMutationVariables = Exact<{
updateInput: SetCategoryMetasInput;
hasUpdates: Scalars['Boolean']['input'];
deleteInput: DeleteCategoryMetasInput;
hasDeletions: Scalars['Boolean']['input'];
migrateInput: SetCategoryMetasInput;
isMigration: Scalars['Boolean']['input'];
}>;
export type UpdateCategoryMetadataMutation = { __typename?: 'Mutation', updatedMeta?: { __typename?: 'SetCategoryMetasPayload', metas: Array<{ __typename?: 'CategoryMetaType', categoryId: number, key: string, value: string }> } | null, deletedMeta?: { __typename?: 'DeleteCategoryMetasPayload', metas: Array<{ __typename?: 'CategoryMetaType', categoryId: number, key: string, value: string }> } | null, migrationMeta?: { __typename?: 'SetCategoryMetasPayload', metas: Array<{ __typename?: 'CategoryMetaType', categoryId: number, key: string, value: string }> } | null };
export type GetCategoriesBaseQueryVariables = Exact<{
after?: InputMaybe<Scalars['Cursor']['input']>;
before?: InputMaybe<Scalars['Cursor']['input']>;
@@ -3671,6 +3683,18 @@ export type UpdateChaptersMutationVariables = Exact<{
export type UpdateChaptersMutation = { __typename?: 'Mutation', updateChapters?: { __typename?: 'UpdateChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, isBookmarked?: boolean, isRead?: boolean, lastReadAt?: string, lastPageRead?: number, manga?: { __typename?: 'MangaType', id: number, unreadCount: number, bookmarkCount: number, lastReadChapter?: { __typename?: 'ChapterType', id: number } | null, latestReadChapter?: { __typename?: 'ChapterType', id: number } | null, firstUnreadChapter?: { __typename?: 'ChapterType', id: number } | null } }> } | null, deleteDownloadedChapters?: { __typename?: 'DeleteDownloadedChaptersPayload', chapters: Array<{ __typename?: 'ChapterType', id: number, isDownloaded: boolean, manga: { __typename?: 'MangaType', id: number, downloadCount: number } }> } | null, trackProgress?: { __typename?: 'TrackProgressPayload', trackRecords: Array<{ __typename?: 'TrackRecordType', id: number, remoteId: string, trackerId: number, remoteUrl: string, title: string, status: number, lastChapterRead: number, totalChapters: number, score: number, displayScore: string, startDate: string, finishDate: string, private: boolean }> } | null };
export type UpdateChapterMetadataMutationVariables = Exact<{
updateInput: SetChapterMetasInput;
hasUpdates: Scalars['Boolean']['input'];
deleteInput: DeleteChapterMetasInput;
hasDeletions: Scalars['Boolean']['input'];
migrateInput: SetChapterMetasInput;
isMigration: Scalars['Boolean']['input'];
}>;
export type UpdateChapterMetadataMutation = { __typename?: 'Mutation', updatedMeta?: { __typename?: 'SetChapterMetasPayload', metas: Array<{ __typename?: 'ChapterMetaType', chapterId: number, key: string, value: string }> } | null, deletedMeta?: { __typename?: 'DeleteChapterMetasPayload', metas: Array<{ __typename?: 'ChapterMetaType', chapterId: number, key: string, value: string }> } | null, migrationMeta?: { __typename?: 'SetChapterMetasPayload', metas: Array<{ __typename?: 'ChapterMetaType', chapterId: number, key: string, value: string }> } | null };
export type GetChaptersReaderQueryVariables = Exact<{
after?: InputMaybe<Scalars['Cursor']['input']>;
before?: InputMaybe<Scalars['Cursor']['input']>;
@@ -3987,6 +4011,18 @@ export type UpdateMangasCategoriesMutationVariables = Exact<{
export type UpdateMangasCategoriesMutation = { __typename?: 'Mutation', updateMangasCategories?: { __typename?: 'UpdateMangasCategoriesPayload', mangas: Array<{ __typename?: 'MangaType', id: number, categories: { __typename?: 'CategoryNodeList', totalCount: number, nodes: Array<{ __typename?: 'CategoryType', id: number, mangas: { __typename?: 'MangaNodeList', totalCount: number } }> } }> } | null };
export type UpdateMangaMetadataMutationVariables = Exact<{
updateInput: SetMangaMetasInput;
hasUpdates: Scalars['Boolean']['input'];
deleteInput: DeleteMangaMetasInput;
hasDeletions: Scalars['Boolean']['input'];
migrateInput: SetMangaMetasInput;
isMigration: Scalars['Boolean']['input'];
}>;
export type UpdateMangaMetadataMutation = { __typename?: 'Mutation', updatedMeta?: { __typename?: 'SetMangaMetasPayload', metas: Array<{ __typename?: 'MangaMetaType', mangaId: number, key: string, value: string }> } | null, deletedMeta?: { __typename?: 'DeleteMangaMetasPayload', metas: Array<{ __typename?: 'MangaMetaType', mangaId: number, key: string, value: string }> } | null, migrationMeta?: { __typename?: 'SetMangaMetasPayload', metas: Array<{ __typename?: 'MangaMetaType', mangaId: number, key: string, value: string }> } | null };
export type GetMangaScreenQueryVariables = Exact<{
id: Scalars['Int']['input'];
}>;
@@ -4093,6 +4129,18 @@ export type SetGlobalMetadataMutationVariables = Exact<{
export type SetGlobalMetadataMutation = { __typename?: 'Mutation', setGlobalMetas?: { __typename?: 'SetGlobalMetasPayload', metas: Array<{ __typename?: 'GlobalMetaType', key: string, value: string }> } | null };
export type UpdateGlobalMetadataMutationVariables = Exact<{
updateInput: SetGlobalMetasInput;
hasUpdates: Scalars['Boolean']['input'];
deleteInput: DeleteGlobalMetasInput;
hasDeletions: Scalars['Boolean']['input'];
migrateInput: SetGlobalMetasInput;
isMigration: Scalars['Boolean']['input'];
}>;
export type UpdateGlobalMetadataMutation = { __typename?: 'Mutation', updatedMeta?: { __typename?: 'SetGlobalMetasPayload', metas: Array<{ __typename?: 'GlobalMetaType', key: string, value: string }> } | null, deletedMeta?: { __typename?: 'DeleteGlobalMetasPayload', metas: Array<{ __typename?: 'GlobalMetaType', key: string, value: string }> } | null, migrationMeta?: { __typename?: 'SetGlobalMetasPayload', metas: Array<{ __typename?: 'GlobalMetaType', key: string, value: string }> } | null };
export type GetGlobalMetadataQueryVariables = Exact<{
key: Scalars['String']['input'];
}>;
@@ -4220,6 +4268,18 @@ export type DeleteSourceMetadataMutationVariables = Exact<{
export type DeleteSourceMetadataMutation = { __typename?: 'Mutation', deleteSourceMetas?: { __typename?: 'DeleteSourceMetasPayload', metas: Array<{ __typename?: 'SourceMetaType', sourceId: string, key: string, value: string }> } | null };
export type UpdateSourceMetadataMutationVariables = Exact<{
updateInput: SetSourceMetasInput;
hasUpdates: Scalars['Boolean']['input'];
deleteInput: DeleteSourceMetasInput;
hasDeletions: Scalars['Boolean']['input'];
migrateInput: SetSourceMetasInput;
isMigration: Scalars['Boolean']['input'];
}>;
export type UpdateSourceMetadataMutation = { __typename?: 'Mutation', updatedMeta?: { __typename?: 'SetSourceMetasPayload', metas: Array<{ __typename?: 'SourceMetaType', sourceId: string, key: string, value: string }> } | null, deletedMeta?: { __typename?: 'DeleteSourceMetasPayload', metas: Array<{ __typename?: 'SourceMetaType', sourceId: string, key: string, value: string }> } | null, migrationMeta?: { __typename?: 'SetSourceMetasPayload', metas: Array<{ __typename?: 'SourceMetaType', sourceId: string, key: string, value: string }> } | null };
export type GetSourceBrowseQueryVariables = Exact<{
id: Scalars['LongString']['input'];
}>;

View File

@@ -194,3 +194,32 @@ export const UPDATE_MANGAS_CATEGORIES = gql`
}
}
`;
export const UPDATE_MANGA_METADATA = gql`
${MANGA_META_FIELDS}
mutation UPDATE_MANGA_METADATA(
$updateInput: SetMangaMetasInput!
$hasUpdates: Boolean!
$deleteInput: DeleteMangaMetasInput!
$hasDeletions: Boolean!
$migrateInput: SetMangaMetasInput!
$isMigration: Boolean!
) {
updatedMeta: setMangaMetas(input: $updateInput) @include(if: $hasUpdates) {
metas {
...MANGA_META_FIELDS
}
}
deletedMeta: deleteMangaMetas(input: $deleteInput) @include(if: $hasDeletions) {
metas {
...MANGA_META_FIELDS
}
}
migrationMeta: setMangaMetas(input: $migrateInput) @include(if: $isMigration) {
metas {
...MANGA_META_FIELDS
}
}
}
`;

View File

@@ -30,3 +30,31 @@ export const SET_GLOBAL_METADATA = gql`
}
}
`;
export const UPDATE_GLOBAL_METADATA = gql`
${GLOBAL_METADATA}
mutation UPDATE_GLOBAL_METADATA(
$updateInput: SetGlobalMetasInput!
$hasUpdates: Boolean!
$deleteInput: DeleteGlobalMetasInput!
$hasDeletions: Boolean!
$migrateInput: SetGlobalMetasInput!
$isMigration: Boolean!
) {
updatedMeta: setGlobalMetas(input: $updateInput) @include(if: $hasUpdates) {
metas {
...GLOBAL_METADATA
}
}
deletedMeta: deleteGlobalMetas(input: $deleteInput) @include(if: $hasDeletions) {
metas {
...GLOBAL_METADATA
}
}
migrationMeta: setGlobalMetas(input: $migrateInput) @include(if: $isMigration) {
metas {
...GLOBAL_METADATA
}
}
}
`;

View File

@@ -58,3 +58,32 @@ export const DELETE_SOURCE_METADATA = gql`
}
}
`;
export const UPDATE_SOURCE_METADATA = gql`
${SOURCE_META_FIELDS}
mutation UPDATE_SOURCE_METADATA(
$updateInput: SetSourceMetasInput!
$hasUpdates: Boolean!
$deleteInput: DeleteSourceMetasInput!
$hasDeletions: Boolean!
$migrateInput: SetSourceMetasInput!
$isMigration: Boolean!
) {
updatedMeta: setSourceMetas(input: $updateInput) @include(if: $hasUpdates) {
metas {
...SOURCE_META_FIELDS
}
}
deletedMeta: deleteSourceMetas(input: $deleteInput) @include(if: $hasDeletions) {
metas {
...SOURCE_META_FIELDS
}
}
migrationMeta: setSourceMetas(input: $migrateInput) @include(if: $isMigration) {
metas {
...SOURCE_META_FIELDS
}
}
}
`;

View File

@@ -238,9 +238,31 @@ import {
KoSyncLogoutMutationVariables,
GetKoSyncStatusQuery,
GetKoSyncStatusQueryVariables,
UpdateGlobalMetadataMutation,
UpdateGlobalMetadataMutationVariables,
UpdateMangaMetadataMutation,
UpdateMangaMetadataMutationVariables,
UpdateChapterMetadataMutation,
UpdateChapterMetadataMutationVariables,
UpdateCategoryMetadataMutation,
UpdateCategoryMetadataMutationVariables,
UpdateSourceMetadataMutation,
UpdateSourceMetadataMutationVariables,
SetCategoryMetasItemInput,
DeleteCategoryMetasItemInput,
SetSourceMetasItemInput,
DeleteSourceMetasItemInput,
SetMangaMetasItemInput,
DeleteMangaMetasItemInput,
SetChapterMetasItemInput,
DeleteChapterMetasItemInput,
} from '@/lib/graphql/generated/graphql.ts';
import { GET_GLOBAL_METADATAS } from '@/lib/graphql/metadata/GlobalMetadataQuery.ts';
import { DELETE_GLOBAL_METADATA, SET_GLOBAL_METADATA } from '@/lib/graphql/metadata/GlobalMetadataMutation.ts';
import {
DELETE_GLOBAL_METADATA,
SET_GLOBAL_METADATA,
UPDATE_GLOBAL_METADATA,
} from '@/lib/graphql/metadata/GlobalMetadataMutation.ts';
import {
CHECK_FOR_SERVER_UPDATES,
CHECK_FOR_WEBUI_UPDATE,
@@ -262,6 +284,7 @@ import {
SET_MANGA_METADATA,
UPDATE_MANGA,
UPDATE_MANGA_CATEGORIES,
UPDATE_MANGA_METADATA,
UPDATE_MANGAS,
UPDATE_MANGAS_CATEGORIES,
} from '@/lib/graphql/manga/MangaMutation.ts';
@@ -281,6 +304,7 @@ import {
DELETE_SOURCE_METADATA,
GET_SOURCE_MANGAS_FETCH,
SET_SOURCE_METADATA,
UPDATE_SOURCE_METADATA,
UPDATE_SOURCE_PREFERENCES,
} from '@/lib/graphql/source/SourceMutation.ts';
import {
@@ -307,6 +331,7 @@ import {
GET_MANGA_CHAPTERS_FETCH,
SET_CHAPTER_METADATA,
UPDATE_CHAPTER,
UPDATE_CHAPTER_METADATA,
UPDATE_CHAPTERS,
} from '@/lib/graphql/chapter/ChapterMutation.ts';
import {
@@ -315,6 +340,7 @@ import {
DELETE_CATEGORY_METADATA,
SET_CATEGORY_METADATA,
UPDATE_CATEGORY,
UPDATE_CATEGORY_METADATA,
UPDATE_CATEGORY_ORDER,
} from '@/lib/graphql/category/CategoryMutation.ts';
import { STOP_UPDATER, UPDATE_LIBRARY } from '@/lib/graphql/updater/UpdaterMutation.ts';
@@ -353,6 +379,8 @@ import { SOURCE_META_FIELDS } from '@/lib/graphql/source/SourceFragments.ts';
import { CHAPTER_META_FIELDS } from '@/lib/graphql/chapter/ChapterFragments.ts';
import { MetadataMigrationSettings } from '@/features/migration/Migration.types.ts';
import { MangaIdInfo } from '@/features/manga/Manga.types.ts';
import { ChapterIdInfo } from '@/features/chapter/Chapter.types.ts';
import { CategoryIdInfo } from '@/features/category/Category.types.ts';
import { updateMetadataList } from '@/features/metadata/services/MetadataApolloCacheHandler.ts';
import { USER_LOGIN, USER_REFRESH } from '@/lib/graphql/user/UserMutation.ts';
import { AuthManager } from '@/features/authentication/AuthManager.ts';
@@ -361,6 +389,7 @@ import { KO_SYNC_LOGIN, KO_SYNC_LOGOUT } from '@/lib/graphql/koreader/KoreaderSy
import { GET_KO_SYNC_STATUS } from '@/lib/graphql/koreader/KoreaderSyncQuery.ts';
import { ImageCache } from '@/lib/service-worker/ImageCache.ts';
import { Sources } from '@/features/source/services/Sources.ts';
import { SourceIdInfo } from '@/features/source/Source.types.ts';
enum GQLMethod {
QUERY = 'QUERY',
@@ -1386,6 +1415,103 @@ export class RequestManager {
);
}
public updateGlobalMeta(
{
updateInput = { metas: [] },
deleteInput = { keys: [] },
migrateInput = { metas: [] },
}: {
updateInput?: SetGlobalMetasInput;
deleteInput?: DeleteGlobalMetasInput;
migrateInput?: SetGlobalMetasInput;
},
options?: MutationOptions<UpdateGlobalMetadataMutation, UpdateGlobalMetadataMutationVariables>,
): AbortableApolloMutationResponse<UpdateGlobalMetadataMutation> {
return this.doRequest<UpdateGlobalMetadataMutation, UpdateGlobalMetadataMutationVariables>(
GQLMethod.MUTATION,
UPDATE_GLOBAL_METADATA,
{
updateInput,
hasUpdates: !!updateInput.metas.length,
deleteInput,
hasDeletions: !!deleteInput.keys?.length || !!deleteInput.prefixes?.length,
migrateInput,
isMigration: !!migrateInput.metas.length,
},
{
optimisticResponse: {
__typename: 'Mutation',
updatedMeta: {
__typename: 'SetGlobalMetasPayload',
metas: (updateInput?.metas ?? []).map((meta) => ({
__typename: 'GlobalMetaType',
key: meta.key,
value: meta.value,
})),
},
deletedMeta: {
__typename: 'DeleteGlobalMetasPayload',
metas: (deleteInput?.keys ?? []).map((key) => ({
__typename: 'GlobalMetaType' as const,
key,
value: '',
})),
},
migrationMeta: {
__typename: 'SetGlobalMetasPayload',
metas: (migrateInput?.metas ?? []).map((meta) => ({
__typename: 'GlobalMetaType',
key: meta.key,
value: meta.value,
})),
},
},
update(cache, { data }) {
deleteInput?.keys?.forEach((key) => {
cache.evict({ id: cache.identify({ __typename: 'GlobalMetaType', key }) });
});
cache.modify({
fields: {
metas(existingMetas, { readField }) {
if (!existingMetas) {
return existingMetas;
}
if (!data?.updatedMeta && !data?.migrationMeta) {
return existingMetas;
}
const updatedMeta = [
...(data?.updatedMeta?.metas ?? []),
...(data?.migrationMeta?.metas ?? []),
];
const newMetas = updatedMeta.filter((meta) =>
existingMetas.nodes.every(
(existingMeta: Reference) => readField('key', existingMeta) !== meta.key,
),
);
const newMetaRefs = newMetas.map((meta) =>
cache.writeFragment({
data: meta,
fragment: GLOBAL_METADATA,
}),
);
return {
...existingMetas,
nodes: [...existingMetas.nodes, ...newMetaRefs],
};
},
},
});
},
...options,
},
);
}
public useGetAbout(
options?: QueryHookOptions<GetAboutQuery, GetAboutQueryVariables>,
): AbortableApolloUseQueryResponse<GetAboutQuery, GetAboutQueryVariables> {
@@ -1810,6 +1936,104 @@ export class RequestManager {
);
}
public updateSourceMeta(
sourceIds: SourceIdInfo['id'][],
{
updateInput = { metas: [] },
deleteInput = { keys: [] },
migrateInput = { metas: [] },
}: {
updateInput?: Omit<SetSourceMetasItemInput, 'sourceIds'>;
deleteInput?: Omit<DeleteSourceMetasItemInput, 'sourceIds'>;
migrateInput?: Omit<SetSourceMetasItemInput, 'sourceIds'>;
},
options?: MutationOptions<UpdateSourceMetadataMutation, UpdateSourceMetadataMutationVariables>,
): AbortableApolloMutationResponse<UpdateSourceMetadataMutation> {
return this.doRequest<UpdateSourceMetadataMutation, UpdateSourceMetadataMutationVariables>(
GQLMethod.MUTATION,
UPDATE_SOURCE_METADATA,
{
updateInput: { items: [{ ...updateInput, sourceIds }] },
hasUpdates: !!updateInput.metas.length,
deleteInput: { items: [{ ...deleteInput, sourceIds }] },
hasDeletions: !!deleteInput.keys?.length || !!deleteInput.prefixes?.length,
migrateInput: { items: [{ ...migrateInput, sourceIds }] },
isMigration: !!migrateInput.metas.length,
},
{
optimisticResponse: {
__typename: 'Mutation',
updatedMeta: {
__typename: 'SetSourceMetasPayload',
metas: sourceIds.flatMap((sourceId) =>
(updateInput?.metas ?? []).map((meta) => ({
__typename: 'SourceMetaType' as const,
sourceId,
key: meta.key,
value: meta.value,
})),
),
},
deletedMeta: {
__typename: 'DeleteSourceMetasPayload',
metas: sourceIds.flatMap((sourceId) =>
(deleteInput?.keys ?? []).map((key) => ({
__typename: 'SourceMetaType' as const,
sourceId,
key,
value: '',
})),
),
},
migrationMeta: {
__typename: 'SetSourceMetasPayload',
metas: sourceIds.flatMap((sourceId) =>
(migrateInput?.metas ?? []).map((meta) => ({
__typename: 'SourceMetaType' as const,
sourceId,
key: meta.key,
value: meta.value,
})),
),
},
},
update(cache, { data }) {
sourceIds?.forEach((sourceId) => {
deleteInput?.keys?.forEach((key) => {
cache.evict({ id: cache.identify({ __typename: 'SourceMetaType', sourceId, key }) });
});
});
if (!data?.updatedMeta && !data?.migrationMeta) {
return;
}
sourceIds.forEach((sourceId) => {
cache.modify({
id: cache.identify({ __typename: 'SourceType', id: sourceId }),
fields: {
meta(existingMetas, { readField }) {
const updatedMeta = [
...(data?.updatedMeta?.metas ?? []),
...(data?.migrationMeta?.metas ?? []),
];
return updateMetadataList(updatedMeta, existingMetas, readField, (meta) =>
cache.writeFragment({
data: meta,
fragment: SOURCE_META_FIELDS,
}),
);
},
},
});
});
},
...options,
},
);
}
public useGetSourceMangas(
input: FetchSourceMangaInput,
initialPages: number = 1,
@@ -2355,6 +2579,104 @@ export class RequestManager {
);
}
public updateMangaMeta(
mangaIds: MangaIdInfo['id'][],
{
updateInput = { metas: [] },
deleteInput = { keys: [] },
migrateInput = { metas: [] },
}: {
updateInput?: Omit<SetMangaMetasItemInput, 'mangaIds'>;
deleteInput?: Omit<DeleteMangaMetasItemInput, 'mangaIds'>;
migrateInput?: Omit<SetMangaMetasItemInput, 'mangaIds'>;
},
options?: MutationOptions<UpdateMangaMetadataMutation, UpdateMangaMetadataMutationVariables>,
): AbortableApolloMutationResponse<UpdateMangaMetadataMutation> {
return this.doRequest<UpdateMangaMetadataMutation, UpdateMangaMetadataMutationVariables>(
GQLMethod.MUTATION,
UPDATE_MANGA_METADATA,
{
updateInput: { items: [{ ...updateInput, mangaIds }] },
hasUpdates: !!updateInput.metas.length,
deleteInput: { items: [{ ...deleteInput, mangaIds }] },
hasDeletions: !!deleteInput.keys?.length || !!deleteInput.prefixes?.length,
migrateInput: { items: [{ ...migrateInput, mangaIds }] },
isMigration: !!migrateInput.metas.length,
},
{
optimisticResponse: {
__typename: 'Mutation',
updatedMeta: {
__typename: 'SetMangaMetasPayload',
metas: mangaIds.flatMap((mangaId) =>
(updateInput?.metas ?? []).map((meta) => ({
__typename: 'MangaMetaType' as const,
mangaId,
key: meta.key,
value: meta.value,
})),
),
},
deletedMeta: {
__typename: 'DeleteMangaMetasPayload',
metas: mangaIds.flatMap((mangaId) =>
(deleteInput?.keys ?? []).map((key) => ({
__typename: 'MangaMetaType' as const,
mangaId,
key,
value: '',
})),
),
},
migrationMeta: {
__typename: 'SetMangaMetasPayload',
metas: mangaIds.flatMap((mangaId) =>
(migrateInput?.metas ?? []).map((meta) => ({
__typename: 'MangaMetaType' as const,
mangaId,
key: meta.key,
value: meta.value,
})),
),
},
},
update(cache, { data }) {
mangaIds.forEach((mangaId) => {
deleteInput?.keys?.forEach((key) => {
cache.evict({ id: cache.identify({ __typename: 'MangaMetaType', mangaId, key }) });
});
});
if (!data?.updatedMeta && !data?.migrationMeta) {
return;
}
mangaIds.forEach((mangaId) => {
cache.modify({
id: cache.identify({ __typename: 'MangaType', id: mangaId }),
fields: {
meta(existingMetas, { readField }) {
const updatedMeta = [
...(data?.updatedMeta?.metas ?? []),
...(data?.migrationMeta?.metas ?? []),
];
return updateMetadataList(updatedMeta, existingMetas, readField, (meta) =>
cache.writeFragment({
data: meta,
fragment: MANGA_META_FIELDS,
}),
);
},
},
});
});
},
...options,
},
);
}
public useGetChapters<Data, Variables extends OperationVariables>(
document: DocumentNode | TypedDocumentNode<Data, Variables>,
variables: Variables,
@@ -2606,6 +2928,104 @@ export class RequestManager {
);
}
public updateChapterMeta(
chapterIds: ChapterIdInfo['id'][],
{
updateInput = { metas: [] },
deleteInput = { keys: [] },
migrateInput = { metas: [] },
}: {
updateInput?: Omit<SetChapterMetasItemInput, 'chapterIds'>;
deleteInput?: Omit<DeleteChapterMetasItemInput, 'chapterIds'>;
migrateInput?: Omit<SetChapterMetasItemInput, 'chapterIds'>;
},
options?: MutationOptions<UpdateChapterMetadataMutation, UpdateChapterMetadataMutationVariables>,
): AbortableApolloMutationResponse<UpdateChapterMetadataMutation> {
return this.doRequest<UpdateChapterMetadataMutation, UpdateChapterMetadataMutationVariables>(
GQLMethod.MUTATION,
UPDATE_CHAPTER_METADATA,
{
updateInput: { items: [{ ...updateInput, chapterIds }] },
hasUpdates: !!updateInput.metas.length,
deleteInput: { items: [{ ...deleteInput, chapterIds }] },
hasDeletions: !!deleteInput.keys?.length || !!deleteInput.prefixes?.length,
migrateInput: { items: [{ ...migrateInput, chapterIds }] },
isMigration: !!migrateInput.metas.length,
},
{
optimisticResponse: {
__typename: 'Mutation',
updatedMeta: {
__typename: 'SetChapterMetasPayload',
metas: chapterIds.flatMap((chapterId) =>
(updateInput?.metas ?? []).map((meta) => ({
__typename: 'ChapterMetaType' as const,
chapterId,
key: meta.key,
value: meta.value,
})),
),
},
deletedMeta: {
__typename: 'DeleteChapterMetasPayload',
metas: chapterIds.flatMap((chapterId) =>
(deleteInput?.keys ?? []).map((key) => ({
__typename: 'ChapterMetaType' as const,
chapterId,
key,
value: '',
})),
),
},
migrationMeta: {
__typename: 'SetChapterMetasPayload',
metas: chapterIds.flatMap((chapterId) =>
(migrateInput?.metas ?? []).map((meta) => ({
__typename: 'ChapterMetaType' as const,
chapterId,
key: meta.key,
value: meta.value,
})),
),
},
},
update(cache, { data }) {
chapterIds.forEach((chapterId) => {
deleteInput?.keys?.forEach((key) => {
cache.evict({ id: cache.identify({ __typename: 'ChapterMetaType', chapterId, key }) });
});
});
if (!data?.updatedMeta && !data?.migrationMeta) {
return;
}
chapterIds.forEach((chapterId) => {
cache.modify({
id: cache.identify({ __typename: 'ChapterType', id: chapterId }),
fields: {
meta(existingMetas, { readField }) {
const updatedMeta = [
...(data?.updatedMeta?.metas ?? []),
...(data?.migrationMeta?.metas ?? []),
];
return updateMetadataList(updatedMeta, existingMetas, readField, (meta) =>
cache.writeFragment({
data: meta,
fragment: CHAPTER_META_FIELDS,
}),
);
},
},
});
});
},
...options,
},
);
}
public getChapterPageUrl(mangaId: number | string, chapterIndex: number | string, page: number): string {
return this.getValidImgUrlFor(
`manga/${mangaId}/chapter/${chapterIndex}/page/${page}`,
@@ -2910,6 +3330,104 @@ export class RequestManager {
);
}
public updateCategoryMeta(
categoryIds: CategoryIdInfo['id'][],
{
updateInput = { metas: [] },
deleteInput = { keys: [] },
migrateInput = { metas: [] },
}: {
updateInput?: Omit<SetCategoryMetasItemInput, 'categoryIds'>;
deleteInput?: Omit<DeleteCategoryMetasItemInput, 'categoryIds'>;
migrateInput?: Omit<SetCategoryMetasItemInput, 'categoryIds'>;
},
options?: MutationOptions<UpdateCategoryMetadataMutation, UpdateCategoryMetadataMutationVariables>,
): AbortableApolloMutationResponse<UpdateCategoryMetadataMutation> {
return this.doRequest<UpdateCategoryMetadataMutation, UpdateCategoryMetadataMutationVariables>(
GQLMethod.MUTATION,
UPDATE_CATEGORY_METADATA,
{
updateInput: { items: [{ ...updateInput, categoryIds }] },
hasUpdates: !!updateInput.metas.length,
deleteInput: { items: [{ ...deleteInput, categoryIds }] },
hasDeletions: !!deleteInput.keys?.length || !!deleteInput.prefixes?.length,
migrateInput: { items: [{ ...migrateInput, categoryIds }] },
isMigration: !!migrateInput.metas.length,
},
{
optimisticResponse: {
__typename: 'Mutation',
updatedMeta: {
__typename: 'SetCategoryMetasPayload',
metas: categoryIds.flatMap((categoryId) =>
(updateInput?.metas ?? []).map((meta) => ({
__typename: 'CategoryMetaType' as const,
categoryId,
key: meta.key,
value: meta.value,
})),
),
},
deletedMeta: {
__typename: 'DeleteCategoryMetasPayload',
metas: categoryIds.flatMap((categoryId) =>
(deleteInput?.keys ?? []).map((key) => ({
__typename: 'CategoryMetaType' as const,
categoryId,
key,
value: '',
})),
),
},
migrationMeta: {
__typename: 'SetCategoryMetasPayload',
metas: categoryIds.flatMap((categoryId) =>
(migrateInput?.metas ?? []).map((meta) => ({
__typename: 'CategoryMetaType' as const,
categoryId,
key: meta.key,
value: meta.value,
})),
),
},
},
update(cache, { data }) {
categoryIds.forEach((categoryId) => {
deleteInput?.keys?.forEach((key) => {
cache.evict({ id: cache.identify({ __typename: 'CategoryMetaType', categoryId, key }) });
});
});
if (!data?.updatedMeta && !data?.migrationMeta) {
return;
}
categoryIds.forEach((categoryId) => {
cache.modify({
id: cache.identify({ __typename: 'CategoryType', id: categoryId }),
fields: {
meta(existingMetas, { readField }) {
const updatedMeta = [
...(data?.updatedMeta?.metas ?? []),
...(data?.migrationMeta?.metas ?? []),
];
return updateMetadataList(updatedMeta, existingMetas, readField, (meta) =>
cache.writeFragment({
data: meta,
fragment: CATEGORY_META_FIELDS,
}),
);
},
},
});
});
},
...options,
},
);
}
public createBackupFile(
input: CreateBackupInput,
options?: MutationOptions<CreateBackupMutation, CreateBackupMutationVariables>,