diff --git a/src/lib/graphql/fragments/CategoryFragments.ts b/src/lib/graphql/fragments/CategoryFragments.ts index 6e14a953..1ce79b7d 100644 --- a/src/lib/graphql/fragments/CategoryFragments.ts +++ b/src/lib/graphql/fragments/CategoryFragments.ts @@ -8,6 +8,14 @@ import gql from 'graphql-tag'; +export const CATEGORY_META_FIELDS = gql` + fragment CATEGORY_META_FIELDS on CategoryMetaType { + categoryId + key + value + } +`; + export const CATEGORY_BASE_FIELDS = gql` fragment CATEGORY_BASE_FIELDS on CategoryType { id @@ -20,14 +28,13 @@ export const CATEGORY_BASE_FIELDS = gql` export const CATEGORY_LIBRARY_FIELDS = gql` ${CATEGORY_BASE_FIELDS} + ${CATEGORY_META_FIELDS} fragment CATEGORY_LIBRARY_FIELDS on CategoryType { ...CATEGORY_BASE_FIELDS meta { - categoryId - key - value + ...CATEGORY_META_FIELDS } mangas { totalCount diff --git a/src/lib/graphql/fragments/ChapterFragments.ts b/src/lib/graphql/fragments/ChapterFragments.ts index b2acd4ac..5ce20cd6 100644 --- a/src/lib/graphql/fragments/ChapterFragments.ts +++ b/src/lib/graphql/fragments/ChapterFragments.ts @@ -9,6 +9,14 @@ import gql from 'graphql-tag'; import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; +export const CHAPTER_META_FIELDS = gql` + fragment CHAPTER_META_FIELDS on ChapterMetaType { + chapterId + key + value + } +`; + export const CHAPTER_BASE_FIELDS = gql` fragment CHAPTER_BASE_FIELDS on ChapterType { id diff --git a/src/lib/graphql/fragments/MangaFragments.ts b/src/lib/graphql/fragments/MangaFragments.ts index d49d15a8..faa3b5ae 100644 --- a/src/lib/graphql/fragments/MangaFragments.ts +++ b/src/lib/graphql/fragments/MangaFragments.ts @@ -8,6 +8,14 @@ import gql from 'graphql-tag'; +export const MANGA_META_FIELDS = gql` + fragment MANGA_META_FIELDS on MangaMetaType { + mangaId + key + value + } +`; + export const MANGA_BASE_FIELDS = gql` fragment MANGA_BASE_FIELDS on MangaType { id @@ -64,14 +72,13 @@ export const MANGA_CHAPTER_NODE_FIELDS = gql` export const MANGA_READER_FIELDS = gql` ${MANGA_BASE_FIELDS} + ${MANGA_META_FIELDS} fragment MANGA_READER_FIELDS on MangaType { ...MANGA_BASE_FIELDS meta { - mangaId - key - value + ...MANGA_META_FIELDS } chapters { diff --git a/src/lib/graphql/fragments/SourceFragments.ts b/src/lib/graphql/fragments/SourceFragments.ts index e8cd5424..da15fba6 100644 --- a/src/lib/graphql/fragments/SourceFragments.ts +++ b/src/lib/graphql/fragments/SourceFragments.ts @@ -8,6 +8,14 @@ import gql from 'graphql-tag'; +export const SOURCE_META_FIELDS = gql` + fragment SOURCE_META_FIELDS on SourceMetaType { + sourceId + key + value + } +`; + export const SOURCE_BASE_FIELDS = gql` fragment SOURCE_BASE_FIELDS on SourceType { id @@ -47,6 +55,7 @@ export const SOURCE_LIST_FIELDS = gql` export const SOURCE_BROWSE_FIELDS = gql` ${SOURCE_BASE_FIELDS} + ${SOURCE_META_FIELDS} fragment SOURCE_BROWSE_FIELDS on SourceType { ...SOURCE_BASE_FIELDS @@ -55,9 +64,7 @@ export const SOURCE_BROWSE_FIELDS = gql` supportsLatest meta { - sourceId - key - value + ...SOURCE_META_FIELDS } filters { diff --git a/src/lib/graphql/generated/graphql.ts b/src/lib/graphql/generated/graphql.ts index dab87c2f..d1723da4 100644 --- a/src/lib/graphql/generated/graphql.ts +++ b/src/lib/graphql/generated/graphql.ts @@ -2711,12 +2711,16 @@ export type WebUiUpdateStatus = { state: UpdateState; }; +export type CategoryMetaFieldsFragment = { __typename?: 'CategoryMetaType', categoryId: number, key: string, value: string }; + export type CategoryBaseFieldsFragment = { __typename?: 'CategoryType', id: number, name: string, default: boolean, order: number }; export type CategoryLibraryFieldsFragment = { __typename?: 'CategoryType', id: number, name: string, default: boolean, order: number, meta: Array<{ __typename?: 'CategoryMetaType', categoryId: number, key: string, value: string }>, mangas: { __typename?: 'MangaNodeList', totalCount: number } }; export type CategorySettingFieldsFragment = { __typename?: 'CategoryType', includeInUpdate: IncludeOrExclude, includeInDownload: IncludeOrExclude, id: number, name: string, default: boolean, order: number }; +export type ChapterMetaFieldsFragment = { __typename?: 'ChapterMetaType', chapterId: number, key: string, value: string }; + export type ChapterBaseFieldsFragment = { __typename?: 'ChapterType', id: number, name: string, mangaId: number, scanlator?: string | null, realUrl?: string | null, sourceOrder: number, chapterNumber: number }; export type ChapterStateFieldsFragment = { __typename?: 'ChapterType', id: number, isRead: boolean, isDownloaded: boolean, isBookmarked: boolean }; @@ -2743,6 +2747,8 @@ export type WebuiUpdateInfoFragment = { __typename?: 'WebUIUpdateInfo', channel: export type WebuiUpdateStatusFragment = { __typename?: 'WebUIUpdateStatus', progress: number, state: UpdateState, info: { __typename?: 'WebUIUpdateInfo', channel: string, tag: string } }; +export type MangaMetaFieldsFragment = { __typename?: 'MangaMetaType', mangaId: number, key: string, value: string }; + export type MangaBaseFieldsFragment = { __typename?: 'MangaType', id: number, title: string, thumbnailUrl?: string | null, thumbnailUrlLastFetched?: string | null, inLibrary: boolean, initialized: boolean, sourceId: string }; export type MangaChapterStatFieldsFragment = { __typename?: 'MangaType', id: number, unreadCount: number, downloadCount: number, bookmarkCount: number, hasDuplicateChapters: boolean, chapters: { __typename?: 'ChapterNodeList', totalCount: number } }; @@ -2759,6 +2765,8 @@ export type MangaLibraryDuplicateScreenFieldsFragment = { __typename?: 'MangaTyp export type ServerSettingsFragment = { __typename?: 'SettingsType', ip: string, port: number, socksProxyEnabled: boolean, socksProxyVersion: number, socksProxyHost: string, socksProxyPort: string, socksProxyUsername: string, socksProxyPassword: string, webUIFlavor: WebUiFlavor, initialOpenInBrowserEnabled: boolean, webUIInterface: WebUiInterface, electronPath: string, webUIChannel: WebUiChannel, webUIUpdateCheckInterval: number, downloadAsCbz: boolean, downloadsPath: string, autoDownloadNewChapters: boolean, excludeEntryWithUnreadChapters: boolean, autoDownloadNewChaptersLimit: number, autoDownloadIgnoreReUploads?: boolean | null, extensionRepos: Array, maxSourcesInParallel: number, excludeUnreadChapters: boolean, excludeNotStarted: boolean, excludeCompleted: boolean, globalUpdateInterval: number, updateMangas: boolean, basicAuthEnabled: boolean, basicAuthUsername: string, basicAuthPassword: string, debugLogsEnabled: boolean, gqlDebugLogsEnabled: boolean, systemTrayEnabled: boolean, maxLogFileSize: string, maxLogFiles: number, maxLogFolderSize: string, backupPath: string, backupTime: string, backupInterval: number, backupTTL: number, localSourcePath: string, flareSolverrEnabled: boolean, flareSolverrUrl: string, flareSolverrTimeout: number, flareSolverrSessionName: string, flareSolverrSessionTtl: number, flareSolverrAsResponseFallback: boolean }; +export type SourceMetaFieldsFragment = { __typename?: 'SourceMetaType', sourceId: string, key: string, value: string }; + export type SourceBaseFieldsFragment = { __typename?: 'SourceType', id: string, name: string, displayName: string }; export type SourceMigratableFieldsFragment = { __typename?: 'SourceType', lang: string, iconUrl: string, id: string, name: string, displayName: string }; diff --git a/src/lib/graphql/mutations/CategoryMutation.ts b/src/lib/graphql/mutations/CategoryMutation.ts index 85bec86e..6bb3ebb4 100644 --- a/src/lib/graphql/mutations/CategoryMutation.ts +++ b/src/lib/graphql/mutations/CategoryMutation.ts @@ -7,7 +7,7 @@ */ import gql from 'graphql-tag'; -import { CATEGORY_SETTING_FIELDS } from '@/lib/graphql/fragments/CategoryFragments.ts'; +import { CATEGORY_META_FIELDS, CATEGORY_SETTING_FIELDS } from '@/lib/graphql/fragments/CategoryFragments.ts'; export const CREATE_CATEGORY = gql` ${CATEGORY_SETTING_FIELDS} @@ -31,19 +31,17 @@ export const DELETE_CATEGORY = gql` `; export const DELETE_CATEGORY_METADATA = gql` + ${CATEGORY_META_FIELDS} + mutation DELETE_CATEGORY_METADATA($input: DeleteCategoryMetaInput!) { deleteCategoryMeta(input: $input) { meta { - categoryId - key - value + ...CATEGORY_META_FIELDS } category { id meta { - categoryId - key - value + ...CATEGORY_META_FIELDS } } } @@ -51,12 +49,12 @@ export const DELETE_CATEGORY_METADATA = gql` `; export const SET_CATEGORY_METADATA = gql` + ${CATEGORY_META_FIELDS} + mutation SET_CATEGORY_METADATA($input: SetCategoryMetaInput!) { setCategoryMeta(input: $input) { meta { - categoryId - key - value + ...CATEGORY_META_FIELDS } } } diff --git a/src/lib/graphql/mutations/ChapterMutation.ts b/src/lib/graphql/mutations/ChapterMutation.ts index e539a407..b4461401 100644 --- a/src/lib/graphql/mutations/ChapterMutation.ts +++ b/src/lib/graphql/mutations/ChapterMutation.ts @@ -7,24 +7,22 @@ */ import gql from 'graphql-tag'; -import { CHAPTER_LIST_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts'; +import { CHAPTER_LIST_FIELDS, CHAPTER_META_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts'; import { TRACK_RECORD_BIND_FIELDS } from '@/lib/graphql/fragments/TrackRecordFragments.ts'; import { MANGA_CHAPTER_NODE_FIELDS, MANGA_CHAPTER_STAT_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const DELETE_CHAPTER_METADATA = gql` + ${CHAPTER_META_FIELDS} + mutation DELETE_CHAPTER_METADATA($input: DeleteChapterMetaInput!) { deleteChapterMeta(input: $input) { meta { - chapterId - key - value + ...CHAPTER_META_FIELDS } chapter { id meta { - chapterId - key - value + ...CHAPTER_META_FIELDS } } } @@ -65,12 +63,12 @@ export const GET_MANGA_CHAPTERS_FETCH = gql` `; export const SET_CHAPTER_METADATA = gql` + ${CHAPTER_META_FIELDS} + mutation SET_CHAPTER_METADATA($input: SetChapterMetaInput!) { setChapterMeta(input: $input) { meta { - chapterId - key - value + ...CHAPTER_META_FIELDS } } } diff --git a/src/lib/graphql/mutations/MangaMutation.ts b/src/lib/graphql/mutations/MangaMutation.ts index 33a62e53..76a19fb6 100644 --- a/src/lib/graphql/mutations/MangaMutation.ts +++ b/src/lib/graphql/mutations/MangaMutation.ts @@ -7,22 +7,20 @@ */ import gql from 'graphql-tag'; -import { MANGA_SCREEN_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; +import { MANGA_META_FIELDS, MANGA_SCREEN_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const DELETE_MANGA_METADATA = gql` + ${MANGA_META_FIELDS} + mutation DELETE_MANGA_METADATA($input: DeleteMangaMetaInput!) { deleteMangaMeta(input: $input) { meta { - mangaId - key - value + ...MANGA_META_FIELDS } manga { id meta { - mangaId - key - value + ...MANGA_META_FIELDS } } } @@ -85,12 +83,12 @@ export const GET_MANGA_TO_MIGRATE_TO_FETCH = gql` `; export const SET_MANGA_METADATA = gql` + ${MANGA_META_FIELDS} + mutation SET_MANGA_METADATA($input: SetMangaMetaInput!) { setMangaMeta(input: $input) { meta { - mangaId - key - value + ...MANGA_META_FIELDS } } } diff --git a/src/lib/graphql/mutations/SourceMutation.ts b/src/lib/graphql/mutations/SourceMutation.ts index 58f706dd..46176f36 100644 --- a/src/lib/graphql/mutations/SourceMutation.ts +++ b/src/lib/graphql/mutations/SourceMutation.ts @@ -7,7 +7,7 @@ */ import gql from 'graphql-tag'; -import { SOURCE_SETTING_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; +import { SOURCE_META_FIELDS, SOURCE_SETTING_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; export const GET_SOURCE_MANGAS_FETCH = gql` @@ -36,12 +36,12 @@ export const UPDATE_SOURCE_PREFERENCES = gql` `; export const SET_SOURCE_METADATA = gql` + ${SOURCE_META_FIELDS} + mutation SET_SOURCE_METADATA($input: SetSourceMetaInput!) { setSourceMeta(input: $input) { meta { - sourceId - key - value + ...SOURCE_META_FIELDS } } } diff --git a/src/lib/requests/RequestManager.ts b/src/lib/requests/RequestManager.ts index 3de69a92..743ed471 100644 --- a/src/lib/requests/RequestManager.ts +++ b/src/lib/requests/RequestManager.ts @@ -25,8 +25,9 @@ import { useQuery, useSubscription, } from '@apollo/client'; -import { OperationVariables } from '@apollo/client/core'; +import { OperationVariables, Reference } from '@apollo/client/core'; import { useEffect, useMemo, useRef, useState } from 'react'; +import { ReadFieldFunction } from '@apollo/client/cache/core/types/common'; import { IRestClient, RestClient } from '@/lib/requests/client/RestClient.ts'; import { GraphQLClient } from '@/lib/requests/client/GraphQLClient.ts'; import { @@ -301,8 +302,12 @@ import { ControlledPromise } from '@/lib/ControlledPromise.ts'; import { MetadataMigrationSettings } from '@/typings.ts'; import { DOWNLOAD_STATUS_FIELDS } from '@/lib/graphql/fragments/DownloadFragments.ts'; import { EXTENSION_LIST_FIELDS } from '@/lib/graphql/fragments/ExtensionFragments.ts'; -import { MANGA_BASE_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; +import { MANGA_BASE_FIELDS, MANGA_META_FIELDS } from '@/lib/graphql/fragments/MangaFragments.ts'; import { MangaIdInfo } from '@/lib/data/Mangas.ts'; +import { GLOBAL_METADATA } from '@/lib/graphql/fragments/Fragments'; +import { CATEGORY_META_FIELDS } from '@/lib/graphql/fragments/CategoryFragments.ts'; +import { SOURCE_META_FIELDS } from '@/lib/graphql/fragments/SourceFragments.ts'; +import { CHAPTER_META_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts'; enum GQLMethod { QUERY = 'QUERY', @@ -403,6 +408,24 @@ export const SPECIAL_ED_SOURCES = { ], }; +const updateMetadata = ( + key: string, + existingMetas: Reference[] | undefined, + readField: ReadFieldFunction, + createMetaRef: () => Reference | undefined, +): (Reference | undefined)[] | undefined => { + if (!existingMetas) { + return existingMetas; + } + + const exists = existingMetas.some((metaRef: Reference) => readField('key', metaRef) === key); + if (exists) { + return existingMetas; + } + + return [...existingMetas, createMetaRef()]; +}; + // TODO - extract logic to reduce the size of this file... grew waaaaaaaaaaaaay too big peepoFat // TODO - correctly update cache after all mutations instead of refetching queries export class RequestManager { @@ -1083,6 +1106,21 @@ export class RequestManager { }, }, }, + update(cache, { data }) { + cache.modify({ + id: cache.identify({ __typename: 'GlobalMetaType', key }), + fields: { + meta(existingMetas, { readField }) { + return updateMetadata(key, existingMetas, readField, () => + cache.writeFragment({ + data: data!.setGlobalMeta!.meta, + fragment: GLOBAL_METADATA, + }), + ); + }, + }, + }); + }, ...options, }, ); @@ -1364,6 +1402,21 @@ export class RequestManager { }, }, }, + update(cache, { data }) { + cache.modify({ + id: cache.identify({ __typename: 'SourceType', id: sourceId }), + fields: { + meta(existingMetas, { readField }) { + return updateMetadata(key, existingMetas, readField, () => + cache.writeFragment({ + data: data!.setSourceMeta!.meta, + fragment: SOURCE_META_FIELDS, + }), + ); + }, + }, + }); + }, ...options, }, ); @@ -1843,6 +1896,21 @@ export class RequestManager { }, }, }, + update(cache, { data }) { + cache.modify({ + id: cache.identify({ __typename: 'MangaType', id: mangaId }), + fields: { + meta(existingMetas, { readField }) { + return updateMetadata(key, existingMetas, readField, () => + cache.writeFragment({ + data: data!.setMangaMeta!.meta, + fragment: MANGA_META_FIELDS, + }), + ); + }, + }, + }); + }, ...options, }, ); @@ -2026,6 +2094,21 @@ export class RequestManager { }, }, }, + update(cache, { data }) { + cache.modify({ + id: cache.identify({ __typename: 'ChapterType', id: chapterId }), + fields: { + meta(existingMetas, { readField }) { + return updateMetadata(key, existingMetas, readField, () => + cache.writeFragment({ + data: data!.setChapterMeta!.meta, + fragment: CHAPTER_META_FIELDS, + }), + ); + }, + }, + }); + }, ...options, }, ); @@ -2260,6 +2343,21 @@ export class RequestManager { }, }, }, + update(cache, { data }) { + cache.modify({ + id: cache.identify({ __typename: 'CategoryType', id: categoryId }), + fields: { + meta(existingMetas, { readField }) { + return updateMetadata(key, existingMetas, readField, () => + cache.writeFragment({ + data: data!.setCategoryMeta!.meta, + fragment: CATEGORY_META_FIELDS, + }), + ); + }, + }, + }); + }, ...options, }, );