import { ApolloCache, DocumentNode, FetchResult, useQuery, } from "@apollo/client"; import { Modifiers } from "@apollo/client/cache"; import { isField, getQueryDefinition, StoreObject, } from "@apollo/client/utilities"; import { ListFilterModel } from "../models/list-filter/filter"; import * as GQL from "./generated-graphql"; import { createClient } from "./createClient"; const { client } = createClient(); export const getClient = () => client; // Evicts cached results for the given queries. // Will also call a cache GC afterwards. export function evictQueries( cache: ApolloCache, queries: DocumentNode[] ) { const fields: Modifiers = {}; for (const query of queries) { const { selections } = getQueryDefinition(query).selectionSet; for (const field of selections) { if (!isField(field)) continue; const keyName = field.name.value; fields[keyName] = (_value, { DELETE }) => DELETE; } } cache.modify({ fields }); // evictQueries is usually called at the end of // an update function - so call a GC here cache.gc(); } /** * Evicts fields from all objects of a given type. * * @param input a map from typename -> list of field names to evict * @param ignore optionally specify a cache id to ignore and not modify */ function evictTypeFields( cache: ApolloCache>, input: Record, ignore?: string ) { const data = cache.extract(); for (const key in data) { if (ignore?.includes(key)) continue; const obj = data[key]; const typename = obj.__typename; if (typename && input[typename]) { const modifiers: Modifiers = {}; for (const field of input[typename]) { modifiers[field] = (_value, { DELETE }) => DELETE; } cache.modify({ id: key, fields: modifiers, }); } } } // Appends obj to the cached result of the given query. // Use to append objects to "All*" queries in "Create" mutations. function appendObject( cache: ApolloCache, obj: StoreObject, query: DocumentNode ) { const field = getQueryDefinition(query).selectionSet.selections[0]; if (!isField(field)) return; const keyName = field.name.value; cache.modify({ fields: { [keyName]: (value, { toReference }) => { return [...value, toReference(obj)]; }, }, }); } // Deletes obj from the cache, and sets the // cached result of the given query to null. // Use with "Destroy" mutations. function deleteObject( cache: ApolloCache, obj: StoreObject, query: DocumentNode ) { const field = getQueryDefinition(query).selectionSet.selections[0]; if (!isField(field)) return; const keyName = field.name.value; cache.writeQuery({ query, variables: { id: obj.id }, data: { [keyName]: null }, }); cache.evict({ id: cache.identify(obj) }); } /// Object queries export const useFindScene = (id: string) => { const skip = id === "new" || id === ""; return GQL.useFindSceneQuery({ variables: { id }, skip }); }; export const useSceneStreams = (id: string) => GQL.useSceneStreamsQuery({ variables: { id } }); export const useFindScenes = (filter?: ListFilterModel) => GQL.useFindScenesQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), scene_filter: filter?.makeFilter(), }, }); export const queryFindScenes = (filter: ListFilterModel) => client.query({ query: GQL.FindScenesDocument, variables: { filter: filter.makeFindFilter(), scene_filter: filter.makeFilter(), }, }); export const queryFindScenesByID = (sceneIDs: number[]) => client.query({ query: GQL.FindScenesDocument, variables: { scene_ids: sceneIDs, }, }); export const querySceneByPathRegex = (filter: GQL.FindFilterType) => client.query({ query: GQL.FindScenesByPathRegexDocument, variables: { filter }, }); export const useFindImage = (id: string) => GQL.useFindImageQuery({ variables: { id } }); export const useFindImages = (filter?: ListFilterModel) => GQL.useFindImagesQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), image_filter: filter?.makeFilter(), }, }); export const queryFindImages = (filter: ListFilterModel) => client.query({ query: GQL.FindImagesDocument, variables: { filter: filter.makeFindFilter(), image_filter: filter.makeFilter(), }, }); export const useFindMovie = (id: string) => { const skip = id === "new" || id === ""; return GQL.useFindMovieQuery({ variables: { id }, skip }); }; export const useFindMovies = (filter?: ListFilterModel) => GQL.useFindMoviesQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), movie_filter: filter?.makeFilter(), }, }); export const queryFindMovies = (filter: ListFilterModel) => client.query({ query: GQL.FindMoviesDocument, variables: { filter: filter.makeFindFilter(), movie_filter: filter.makeFilter(), }, }); export const useAllMoviesForFilter = () => GQL.useAllMoviesForFilterQuery(); export const useFindSceneMarkers = (filter?: ListFilterModel) => GQL.useFindSceneMarkersQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), scene_marker_filter: filter?.makeFilter(), }, }); export const queryFindSceneMarkers = (filter: ListFilterModel) => client.query({ query: GQL.FindSceneMarkersDocument, variables: { filter: filter.makeFindFilter(), scene_marker_filter: filter.makeFilter(), }, }); export const useMarkerStrings = () => GQL.useMarkerStringsQuery(); export const useFindGallery = (id: string) => { const skip = id === "new" || id === ""; return GQL.useFindGalleryQuery({ variables: { id }, skip }); }; export const useFindGalleries = (filter?: ListFilterModel) => GQL.useFindGalleriesQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), gallery_filter: filter?.makeFilter(), }, }); export const queryFindGalleries = (filter: ListFilterModel) => client.query({ query: GQL.FindGalleriesDocument, variables: { filter: filter.makeFindFilter(), gallery_filter: filter.makeFilter(), }, }); export const useFindPerformer = (id: string) => { const skip = id === "new" || id === ""; return GQL.useFindPerformerQuery({ variables: { id }, skip }); }; export const queryFindPerformer = (id: string) => client.query({ query: GQL.FindPerformerDocument, variables: { id }, }); export const useFindPerformers = (filter?: ListFilterModel) => GQL.useFindPerformersQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), performer_filter: filter?.makeFilter(), }, }); export const queryFindPerformers = (filter: ListFilterModel) => client.query({ query: GQL.FindPerformersDocument, variables: { filter: filter.makeFindFilter(), performer_filter: filter.makeFilter(), }, }); export const queryFindPerformersByIDForSelect = (performerIDs: number[]) => client.query({ query: GQL.FindPerformersForSelectDocument, variables: { performer_ids: performerIDs, }, }); export const queryFindPerformersForSelect = (filter: ListFilterModel) => client.query({ query: GQL.FindPerformersForSelectDocument, variables: { filter: filter.makeFindFilter(), performer_filter: filter.makeFilter(), }, }); export const useFindStudio = (id: string) => { const skip = id === "new" || id === ""; return GQL.useFindStudioQuery({ variables: { id }, skip }); }; export const queryFindStudio = (id: string) => client.query({ query: GQL.FindStudioDocument, variables: { id }, }); export const useFindStudios = (filter?: ListFilterModel) => GQL.useFindStudiosQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), studio_filter: filter?.makeFilter(), }, }); export const queryFindStudios = (filter: ListFilterModel) => client.query({ query: GQL.FindStudiosDocument, variables: { filter: filter.makeFindFilter(), studio_filter: filter.makeFilter(), }, }); export const useAllStudiosForFilter = () => GQL.useAllStudiosForFilterQuery(); export const useFindTag = (id: string) => { const skip = id === "new" || id === ""; return GQL.useFindTagQuery({ variables: { id }, skip }); }; export const useFindTags = (filter?: ListFilterModel) => GQL.useFindTagsQuery({ skip: filter === undefined, variables: { filter: filter?.makeFindFilter(), tag_filter: filter?.makeFilter(), }, }); export const queryFindTags = (filter: ListFilterModel) => client.query({ query: GQL.FindTagsDocument, variables: { filter: filter.makeFindFilter(), tag_filter: filter.makeFilter(), }, }); export const useAllTagsForFilter = () => GQL.useAllTagsForFilterQuery(); export const useFindSavedFilter = (id: string) => GQL.useFindSavedFilterQuery({ variables: { id }, }); export const useFindSavedFilters = (mode?: GQL.FilterMode) => GQL.useFindSavedFiltersQuery({ variables: { mode }, }); export const useFindDefaultFilter = (mode: GQL.FilterMode) => GQL.useFindDefaultFilterQuery({ variables: { mode }, }); /// Object Mutations // Increases/decreases the given field of the Stats query by diff function updateStats(cache: ApolloCache, field: string, diff: number) { cache.modify({ fields: { stats(value) { return { ...value, [field]: value[field] + diff, }; }, }, }); } function updateO( cache: ApolloCache, typename: string, id: string, updatedOCount: number ) { cache.modify({ id: cache.identify({ __typename: typename, id }), fields: { o_counter() { return updatedOCount; }, }, }); } const sceneMutationImpactedTypeFields = { Movie: ["scenes", "scene_count"], Gallery: ["scenes"], Performer: [ "scenes", "scene_count", "movies", "movie_count", "performer_count", ], Studio: ["scene_count", "performer_count"], Tag: ["scene_count"], }; const sceneMutationImpactedQueries = [ GQL.FindScenesDocument, // various filters GQL.FindMoviesDocument, // is missing scenes GQL.FindGalleriesDocument, // is missing scenes GQL.FindPerformersDocument, // filter by scene count GQL.FindStudiosDocument, // filter by scene count GQL.FindTagsDocument, // filter by scene count ]; export const mutateCreateScene = (input: GQL.SceneCreateInput) => client.mutate({ mutation: GQL.SceneCreateDocument, variables: { input }, update(cache, result) { const scene = result.data?.sceneCreate; if (!scene) return; // update stats updateStats(cache, "scene_count", 1); // if we're reassigning files, refetch files from other scenes if (input.file_ids?.length) { const obj = { __typename: "Scene", id: scene.id }; evictTypeFields( cache, { ...sceneMutationImpactedTypeFields, Scene: ["files"], }, cache.identify(obj) // don't evict this scene ); } else { evictTypeFields(cache, sceneMutationImpactedTypeFields); } evictQueries(cache, sceneMutationImpactedQueries); }, }); export const useSceneUpdate = () => GQL.useSceneUpdateMutation({ update(cache, result) { if (!result.data?.sceneUpdate) return; evictTypeFields(cache, sceneMutationImpactedTypeFields); evictQueries(cache, sceneMutationImpactedQueries); }, }); export const useBulkSceneUpdate = (input: GQL.BulkSceneUpdateInput) => GQL.useBulkSceneUpdateMutation({ variables: { input }, update(cache, result) { if (!result.data?.bulkSceneUpdate) return; evictTypeFields(cache, sceneMutationImpactedTypeFields); evictQueries(cache, sceneMutationImpactedQueries); }, }); export const useScenesUpdate = (input: GQL.SceneUpdateInput[]) => GQL.useScenesUpdateMutation({ variables: { input }, update(cache, result) { if (!result.data?.scenesUpdate) return; evictTypeFields(cache, sceneMutationImpactedTypeFields); evictQueries(cache, sceneMutationImpactedQueries); }, }); export const useSceneDestroy = (input: GQL.SceneDestroyInput) => GQL.useSceneDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.sceneDestroy) return; const obj = { __typename: "Scene", id: input.id }; deleteObject(cache, obj, GQL.FindSceneDocument); evictTypeFields(cache, sceneMutationImpactedTypeFields); evictQueries(cache, [ ...sceneMutationImpactedQueries, GQL.FindSceneMarkersDocument, // filter by scene tags GQL.StatsDocument, // scenes size, scene count, etc ]); }, }); export const useScenesDestroy = (input: GQL.ScenesDestroyInput) => GQL.useScenesDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.scenesDestroy) return; for (const id of input.ids) { const obj = { __typename: "Scene", id }; deleteObject(cache, obj, GQL.FindSceneDocument); } evictTypeFields(cache, sceneMutationImpactedTypeFields); evictQueries(cache, [ ...sceneMutationImpactedQueries, GQL.FindSceneMarkersDocument, // filter by scene tags GQL.StatsDocument, // scenes size, scene count, etc ]); }, }); export const useSceneIncrementO = (id: string) => GQL.useSceneIncrementOMutation({ variables: { id }, update(cache, result) { const updatedOCount = result.data?.sceneIncrementO; if (updatedOCount === undefined) return; const scene = cache.readFragment({ id: cache.identify({ __typename: "Scene", id }), fragment: GQL.SlimSceneDataFragmentDoc, fragmentName: "SlimSceneData", }); if (scene) { // if we have the scene, update performer o_counters manually for (const performer of scene.performers) { cache.modify({ id: cache.identify(performer), fields: { o_counter(value) { return value + 1; }, }, }); } } else { // else refresh all performer o_counters evictTypeFields(cache, { Performer: ["o_counter"], }); } updateStats(cache, "total_o_count", 1); updateO(cache, "Scene", id, updatedOCount); evictQueries(cache, [ GQL.FindScenesDocument, // filter by o_counter GQL.FindPerformersDocument, // filter by o_counter ]); }, }); export const useSceneDecrementO = (id: string) => GQL.useSceneDecrementOMutation({ variables: { id }, update(cache, result) { const updatedOCount = result.data?.sceneDecrementO; if (updatedOCount === undefined) return; const scene = cache.readFragment({ id: cache.identify({ __typename: "Scene", id }), fragment: GQL.SlimSceneDataFragmentDoc, fragmentName: "SlimSceneData", }); if (scene) { // if we have the scene, update performer o_counters manually for (const performer of scene.performers) { cache.modify({ id: cache.identify(performer), fields: { o_counter(value) { return value - 1; }, }, }); } } else { // else refresh all performer o_counters evictTypeFields(cache, { Performer: ["o_counter"], }); } updateStats(cache, "total_o_count", -1); updateO(cache, "Scene", id, updatedOCount); evictQueries(cache, [ GQL.FindScenesDocument, // filter by o_counter GQL.FindPerformersDocument, // filter by o_counter ]); }, }); export const useSceneResetO = (id: string) => GQL.useSceneResetOMutation({ variables: { id }, update(cache, result) { const updatedOCount = result.data?.sceneResetO; if (updatedOCount === undefined) return; const scene = cache.readFragment({ id: cache.identify({ __typename: "Scene", id }), fragment: GQL.SlimSceneDataFragmentDoc, fragmentName: "SlimSceneData", }); if (scene) { // if we have the scene, update performer o_counters manually const old_count = scene.o_counter ?? 0; for (const performer of scene.performers) { cache.modify({ id: cache.identify(performer), fields: { o_counter(value) { return value - old_count; }, }, }); } updateStats(cache, "total_o_count", -old_count); } else { // else refresh all performer o_counters evictTypeFields(cache, { Performer: ["o_counter"], }); // also refresh stats total_o_count cache.modify({ fields: { stats: (value) => ({ ...value, total_o_count: undefined, }), }, }); } updateO(cache, "Scene", id, updatedOCount); evictQueries(cache, [ GQL.FindScenesDocument, // filter by o_counter GQL.FindPerformersDocument, // filter by o_counter ]); }, }); export const useSceneGenerateScreenshot = () => GQL.useSceneGenerateScreenshotMutation(); export const mutateSceneSetPrimaryFile = (id: string, fileID: string) => client.mutate({ mutation: GQL.SceneUpdateDocument, variables: { input: { id, primary_file_id: fileID, }, }, update(cache, result) { if (!result.data?.sceneUpdate) return; evictQueries(cache, [ GQL.FindScenesDocument, // sort by primary basename when missing title ]); }, }); export const mutateSceneAssignFile = (sceneID: string, fileID: string) => client.mutate({ mutation: GQL.SceneAssignFileDocument, variables: { input: { scene_id: sceneID, file_id: fileID, }, }, update(cache, result) { if (!result.data?.sceneAssignFile) return; // refetch target scene cache.evict({ id: cache.identify({ __typename: "Scene", id: sceneID }), }); // refetch files of the scene the file was previously assigned to evictTypeFields(cache, { Scene: ["files"] }); evictQueries(cache, [ GQL.FindScenesDocument, // filter by file count ]); }, }); export const mutateSceneMerge = ( destination: string, source: string[], values: GQL.SceneUpdateInput ) => client.mutate({ mutation: GQL.SceneMergeDocument, variables: { input: { source, destination, values, }, }, update(cache, result) { if (!result.data?.sceneMerge) return; for (const id of source) { const obj = { __typename: "Scene", id }; deleteObject(cache, obj, GQL.FindSceneDocument); } evictTypeFields(cache, sceneMutationImpactedTypeFields); evictQueries(cache, [ ...sceneMutationImpactedQueries, GQL.StatsDocument, // scenes size, scene count, etc ]); }, }); export const useSceneSaveActivity = () => GQL.useSceneSaveActivityMutation({ update(cache, result, { variables }) { if (!result.data?.sceneSaveActivity || !variables) return; const { id, playDuration, resume_time: resumeTime } = variables; cache.modify({ id: cache.identify({ __typename: "Scene", id }), fields: { resume_time() { return resumeTime; }, play_duration(value) { return value + playDuration; }, }, }); if (playDuration) { updateStats(cache, "total_play_duration", playDuration); } evictQueries(cache, [ GQL.FindScenesDocument, // filter by play duration ]); }, }); export const useSceneIncrementPlayCount = () => GQL.useSceneIncrementPlayCountMutation({ update(cache, result, { variables }) { if (!result.data?.sceneIncrementPlayCount || !variables) return; let lastPlayCount = 0; cache.modify({ id: cache.identify({ __typename: "Scene", id: variables.id }), fields: { play_count(value) { lastPlayCount = value; return value + 1; }, last_played_at() { // this is not perfectly accurate, the time is set server-side // it isn't even displayed anywhere in the UI anyway return new Date().toISOString(); }, }, }); updateStats(cache, "total_play_count", 1); if (lastPlayCount === 0) { updateStats(cache, "scenes_played", 1); } evictQueries(cache, [ GQL.FindScenesDocument, // filter by play count ]); }, }); const imageMutationImpactedTypeFields = { Gallery: ["images", "image_count"], Performer: ["image_count", "performer_count"], Studio: ["image_count", "performer_count"], Tag: ["image_count"], }; const imageMutationImpactedQueries = [ GQL.FindImagesDocument, // various filters GQL.FindGalleriesDocument, // filter by image count GQL.FindPerformersDocument, // filter by image count GQL.FindStudiosDocument, // filter by image count GQL.FindTagsDocument, // filter by image count ]; export const useImageUpdate = () => GQL.useImageUpdateMutation({ update(cache, result) { if (!result.data?.imageUpdate) return; evictTypeFields(cache, imageMutationImpactedTypeFields); evictQueries(cache, imageMutationImpactedQueries); }, }); export const useBulkImageUpdate = () => GQL.useBulkImageUpdateMutation({ update(cache, result) { if (!result.data?.bulkImageUpdate) return; evictTypeFields(cache, imageMutationImpactedTypeFields); evictQueries(cache, imageMutationImpactedQueries); }, }); export const useImagesDestroy = (input: GQL.ImagesDestroyInput) => GQL.useImagesDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.imagesDestroy) return; for (const id of input.ids) { const obj = { __typename: "Image", id }; deleteObject(cache, obj, GQL.FindImageDocument); } evictTypeFields(cache, imageMutationImpactedTypeFields); evictQueries(cache, [ ...imageMutationImpactedQueries, GQL.StatsDocument, // images size, images count ]); }, }); function updateImageIncrementO(id: string) { return ( cache: ApolloCache>, result: FetchResult ) => { const updatedOCount = result.data?.imageIncrementO; if (updatedOCount === undefined) return; const image = cache.readFragment({ id: cache.identify({ __typename: "Image", id }), fragment: GQL.SlimImageDataFragmentDoc, fragmentName: "SlimImageData", }); if (image) { // if we have the image, update performer o_counters manually for (const performer of image.performers) { cache.modify({ id: cache.identify(performer), fields: { o_counter(value) { return value + 1; }, }, }); } } else { // else refresh all performer o_counters evictTypeFields(cache, { Performer: ["o_counter"], }); } updateStats(cache, "total_o_count", 1); updateO(cache, "Image", id, updatedOCount); evictQueries(cache, [ GQL.FindImagesDocument, // filter by o_counter GQL.FindPerformersDocument, // filter by o_counter ]); }; } export const useImageIncrementO = (id: string) => GQL.useImageIncrementOMutation({ variables: { id }, update: updateImageIncrementO(id), }); export const mutateImageIncrementO = (id: string) => client.mutate({ mutation: GQL.ImageIncrementODocument, variables: { id }, update: updateImageIncrementO(id), }); function updateImageDecrementO(id: string) { return ( cache: ApolloCache>, result: FetchResult ) => { const updatedOCount = result.data?.imageDecrementO; if (updatedOCount === undefined) return; const image = cache.readFragment({ id: cache.identify({ __typename: "Image", id }), fragment: GQL.SlimImageDataFragmentDoc, fragmentName: "SlimImageData", }); if (image) { // if we have the image, update performer o_counters manually for (const performer of image.performers) { cache.modify({ id: cache.identify(performer), fields: { o_counter(value) { return value - 1; }, }, }); } } else { // else refresh all performer o_counters evictTypeFields(cache, { Performer: ["o_counter"], }); } updateStats(cache, "total_o_count", -1); updateO(cache, "Image", id, updatedOCount); evictQueries(cache, [ GQL.FindImagesDocument, // filter by o_counter GQL.FindPerformersDocument, // filter by o_counter ]); }; } export const useImageDecrementO = (id: string) => GQL.useImageDecrementOMutation({ variables: { id }, update: updateImageDecrementO(id), }); export const mutateImageDecrementO = (id: string) => client.mutate({ mutation: GQL.ImageDecrementODocument, variables: { id }, update: updateImageDecrementO(id), }); function updateImageResetO(id: string) { return ( cache: ApolloCache>, result: FetchResult ) => { const updatedOCount = result.data?.imageResetO; if (updatedOCount === undefined) return; const image = cache.readFragment({ id: cache.identify({ __typename: "Image", id }), fragment: GQL.SlimImageDataFragmentDoc, fragmentName: "SlimImageData", }); if (image) { // if we have the image, update performer o_counters manually const old_count = image.o_counter ?? 0; for (const performer of image.performers) { cache.modify({ id: cache.identify(performer), fields: { o_counter(value) { return value - old_count; }, }, }); } updateStats(cache, "total_o_count", -old_count); } else { // else refresh all performer o_counters evictTypeFields(cache, { Performer: ["o_counter"], }); // also refresh stats total_o_count cache.modify({ fields: { stats: (value) => ({ ...value, total_o_count: undefined, }), }, }); } updateO(cache, "Image", id, updatedOCount); evictQueries(cache, [ GQL.FindImagesDocument, // filter by o_counter GQL.FindPerformersDocument, // filter by o_counter ]); }; } export const useImageResetO = (id: string) => GQL.useImageResetOMutation({ variables: { id }, update: updateImageResetO(id), }); export const mutateImageResetO = (id: string) => client.mutate({ mutation: GQL.ImageResetODocument, variables: { id }, update: updateImageResetO(id), }); export const mutateImageSetPrimaryFile = (id: string, fileID: string) => client.mutate({ mutation: GQL.ImageUpdateDocument, variables: { input: { id, primary_file_id: fileID, }, }, update(cache, result) { if (!result.data?.imageUpdate) return; evictQueries(cache, [ GQL.FindImagesDocument, // sort by primary basename when missing title ]); }, }); const movieMutationImpactedTypeFields = { Studio: ["movie_count"], }; const movieMutationImpactedQueries = [ GQL.FindMoviesDocument, // various filters ]; export const useMovieCreate = () => GQL.useMovieCreateMutation({ update(cache, result) { const movie = result.data?.movieCreate; if (!movie) return; appendObject(cache, movie, GQL.AllMoviesForFilterDocument); // update stats updateStats(cache, "studio_count", 1); evictTypeFields(cache, movieMutationImpactedTypeFields); evictQueries(cache, movieMutationImpactedQueries); }, }); export const useMovieUpdate = () => GQL.useMovieUpdateMutation({ update(cache, result) { if (!result.data?.movieUpdate) return; evictTypeFields(cache, movieMutationImpactedTypeFields); evictQueries(cache, movieMutationImpactedQueries); }, }); export const useBulkMovieUpdate = (input: GQL.BulkMovieUpdateInput) => GQL.useBulkMovieUpdateMutation({ variables: { input }, update(cache, result) { if (!result.data?.bulkMovieUpdate) return; evictTypeFields(cache, movieMutationImpactedTypeFields); evictQueries(cache, movieMutationImpactedQueries); }, }); export const useMovieDestroy = (input: GQL.MovieDestroyInput) => GQL.useMovieDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.movieDestroy) return; const obj = { __typename: "Movie", id: input.id }; deleteObject(cache, obj, GQL.FindMovieDocument); // update stats updateStats(cache, "movie_count", -1); evictTypeFields(cache, { Scene: ["movies"], Performer: ["movie_count"], Studio: ["movie_count"], }); evictQueries(cache, [ ...movieMutationImpactedQueries, GQL.FindScenesDocument, // filter by movie ]); }, }); export const useMoviesDestroy = (input: GQL.MoviesDestroyMutationVariables) => GQL.useMoviesDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.moviesDestroy) return; const { ids } = input; for (const id of ids) { const obj = { __typename: "Movie", id }; deleteObject(cache, obj, GQL.FindMovieDocument); } // update stats updateStats(cache, "movie_count", -ids.length); evictTypeFields(cache, { Scene: ["movies"], Performer: ["movie_count"], Studio: ["movie_count"], }); evictQueries(cache, [ ...movieMutationImpactedQueries, GQL.FindScenesDocument, // filter by movie ]); }, }); const sceneMarkerMutationImpactedTypeFields = { Tag: ["scene_marker_count"], }; const sceneMarkerMutationImpactedQueries = [ GQL.FindScenesDocument, // has marker filter GQL.FindSceneMarkersDocument, // various filters GQL.MarkerStringsDocument, // marker list GQL.FindSceneMarkerTagsDocument, // marker tag list GQL.FindTagsDocument, // filter by marker count ]; export const useSceneMarkerCreate = () => GQL.useSceneMarkerCreateMutation({ update(cache, result, { variables }) { if (!result.data?.sceneMarkerCreate || !variables) return; // refetch linked scene's marker list cache.evict({ id: cache.identify({ __typename: "Scene", id: variables.scene_id }), fieldName: "scene_markers", }); evictTypeFields(cache, sceneMarkerMutationImpactedTypeFields); evictQueries(cache, sceneMarkerMutationImpactedQueries); }, }); export const useSceneMarkerUpdate = () => GQL.useSceneMarkerUpdateMutation({ update(cache, result, { variables }) { if (!result.data?.sceneMarkerUpdate || !variables) return; // refetch linked scene's marker list cache.evict({ id: cache.identify({ __typename: "Scene", id: variables.scene_id }), fieldName: "scene_markers", }); evictTypeFields(cache, sceneMarkerMutationImpactedTypeFields); evictQueries(cache, sceneMarkerMutationImpactedQueries); }, }); export const useSceneMarkerDestroy = () => GQL.useSceneMarkerDestroyMutation({ update(cache, result, { variables }) { if (!result.data?.sceneMarkerDestroy || !variables) return; const obj = { __typename: "SceneMarker", id: variables.id }; cache.evict({ id: cache.identify(obj) }); evictTypeFields(cache, sceneMarkerMutationImpactedTypeFields); evictQueries(cache, sceneMarkerMutationImpactedQueries); }, }); const galleryMutationImpactedTypeFields = { Scene: ["galleries"], Performer: ["gallery_count", "performer_count"], Studio: ["gallery_count", "performer_count"], Tag: ["gallery_count"], }; const galleryMutationImpactedQueries = [ GQL.FindScenesDocument, // is missing galleries GQL.FindGalleriesDocument, // various filters GQL.FindPerformersDocument, // filter by gallery count GQL.FindStudiosDocument, // filter by gallery count GQL.FindTagsDocument, // filter by gallery count ]; export const useGalleryCreate = () => GQL.useGalleryCreateMutation({ update(cache, result) { if (!result.data?.galleryCreate) return; // update stats updateStats(cache, "gallery_count", 1); evictTypeFields(cache, galleryMutationImpactedTypeFields); evictQueries(cache, galleryMutationImpactedQueries); }, }); export const useGalleryUpdate = () => GQL.useGalleryUpdateMutation({ update(cache, result) { if (!result.data?.galleryUpdate) return; evictTypeFields(cache, galleryMutationImpactedTypeFields); evictQueries(cache, galleryMutationImpactedQueries); }, }); export const useBulkGalleryUpdate = () => GQL.useBulkGalleryUpdateMutation({ update(cache, result) { if (!result.data?.bulkGalleryUpdate) return; evictTypeFields(cache, galleryMutationImpactedTypeFields); evictQueries(cache, galleryMutationImpactedQueries); }, }); export const useGalleryDestroy = (input: GQL.GalleryDestroyInput) => GQL.useGalleryDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.galleryDestroy) return; for (const id of input.ids) { const obj = { __typename: "Gallery", id }; deleteObject(cache, obj, GQL.FindGalleryDocument); } evictTypeFields(cache, galleryMutationImpactedTypeFields); evictQueries(cache, [ ...galleryMutationImpactedQueries, GQL.FindImagesDocument, // filter by gallery GQL.StatsDocument, // images size, gallery count, etc ]); }, }); export const mutateAddGalleryImages = (input: GQL.GalleryAddInput) => client.mutate({ mutation: GQL.AddGalleryImagesDocument, variables: input, update(cache, result) { if (!result.data?.addGalleryImages) return; // refetch gallery image_count cache.evict({ id: cache.identify({ __typename: "Gallery", id: input.gallery_id }), fieldName: "image_count", }); // refetch images galleries field for (const id of input.image_ids) { cache.evict({ id: cache.identify({ __typename: "Image", id }), fieldName: "galleries", }); } evictQueries(cache, [ GQL.FindGalleriesDocument, // filter by image count GQL.FindImagesDocument, // filter by gallery ]); }, }); export const mutateRemoveGalleryImages = (input: GQL.GalleryRemoveInput) => client.mutate({ mutation: GQL.RemoveGalleryImagesDocument, variables: input, update(cache, result) { if (!result.data?.removeGalleryImages) return; // refetch gallery image_count cache.evict({ id: cache.identify({ __typename: "Gallery", id: input.gallery_id }), fieldName: "image_count", }); // refetch images galleries field for (const id of input.image_ids) { cache.evict({ id: cache.identify({ __typename: "Image", id }), fieldName: "galleries", }); } evictQueries(cache, [ GQL.FindGalleriesDocument, // filter by image count GQL.FindImagesDocument, // filter by gallery ]); }, }); export const mutateGallerySetPrimaryFile = (id: string, fileID: string) => client.mutate({ mutation: GQL.GalleryUpdateDocument, variables: { input: { id, primary_file_id: fileID, }, }, update(cache, result) { if (!result.data?.galleryUpdate) return; evictQueries(cache, [ GQL.FindGalleriesDocument, // sort by primary basename when missing title ]); }, }); const galleryChapterMutationImpactedTypeFields = { Gallery: ["chapters"], }; const galleryChapterMutationImpactedQueries = [ GQL.FindGalleriesDocument, // filter by has chapters ]; export const useGalleryChapterCreate = () => GQL.useGalleryChapterCreateMutation({ update(cache, result) { if (!result.data?.galleryChapterCreate) return; evictTypeFields(cache, galleryChapterMutationImpactedTypeFields); evictQueries(cache, galleryChapterMutationImpactedQueries); }, }); export const useGalleryChapterUpdate = () => GQL.useGalleryChapterUpdateMutation({ update(cache, result) { if (!result.data?.galleryChapterUpdate) return; evictTypeFields(cache, galleryChapterMutationImpactedTypeFields); evictQueries(cache, galleryChapterMutationImpactedQueries); }, }); export const useGalleryChapterDestroy = () => GQL.useGalleryChapterDestroyMutation({ update(cache, result, { variables }) { if (!result.data?.galleryChapterDestroy || !variables) return; const obj = { __typename: "GalleryChapter", id: variables.id }; cache.evict({ id: cache.identify(obj) }); evictTypeFields(cache, galleryChapterMutationImpactedTypeFields); evictQueries(cache, galleryChapterMutationImpactedQueries); }, }); const performerMutationImpactedTypeFields = { Tag: ["performer_count"], }; export const performerMutationImpactedQueries = [ GQL.FindScenesDocument, // filter by performer tags GQL.FindImagesDocument, // filter by performer tags GQL.FindGalleriesDocument, // filter by performer tags GQL.FindPerformersDocument, // various filters GQL.FindTagsDocument, // filter by performer count ]; export const usePerformerCreate = () => GQL.usePerformerCreateMutation({ update(cache, result) { const performer = result.data?.performerCreate; if (!performer) return; // update stats updateStats(cache, "performer_count", 1); evictTypeFields(cache, performerMutationImpactedTypeFields); evictQueries(cache, [ GQL.FindPerformersDocument, // various filters GQL.FindTagsDocument, // filter by performer count ]); }, }); export const usePerformerUpdate = () => GQL.usePerformerUpdateMutation({ update(cache, result) { if (!result.data?.performerUpdate) return; evictTypeFields(cache, performerMutationImpactedTypeFields); evictQueries(cache, performerMutationImpactedQueries); }, }); export const useBulkPerformerUpdate = (input: GQL.BulkPerformerUpdateInput) => GQL.useBulkPerformerUpdateMutation({ variables: { input }, update(cache, result) { if (!result.data?.bulkPerformerUpdate) return; evictTypeFields(cache, performerMutationImpactedTypeFields); evictQueries(cache, performerMutationImpactedQueries); }, }); export const usePerformerDestroy = () => GQL.usePerformerDestroyMutation({ update(cache, result, { variables }) { if (!result.data?.performerDestroy || !variables) return; const obj = { __typename: "Performer", id: variables.id }; deleteObject(cache, obj, GQL.FindPerformerDocument); // update stats updateStats(cache, "performer_count", -1); evictTypeFields(cache, { ...performerMutationImpactedTypeFields, Performer: ["performer_count"], Studio: ["performer_count"], }); evictQueries(cache, [ ...performerMutationImpactedQueries, GQL.FindPerformersDocument, // appears with GQL.FindMoviesDocument, // filter by performers GQL.FindSceneMarkersDocument, // filter by performers ]); }, }); export const usePerformersDestroy = ( input: GQL.PerformersDestroyMutationVariables ) => GQL.usePerformersDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.performersDestroy) return; const { ids } = input; let count: number; if (Array.isArray(ids)) { for (const id of ids) { const obj = { __typename: "Performer", id }; deleteObject(cache, obj, GQL.FindPerformerDocument); } count = ids.length; } else { const obj = { __typename: "Performer", id: ids }; deleteObject(cache, obj, GQL.FindPerformerDocument); count = 1; } // update stats updateStats(cache, "performer_count", -count); evictTypeFields(cache, { ...performerMutationImpactedTypeFields, Performer: ["performer_count"], Studio: ["performer_count"], }); evictQueries(cache, [ ...performerMutationImpactedQueries, GQL.FindPerformersDocument, // appears with GQL.FindMoviesDocument, // filter by performers GQL.FindSceneMarkersDocument, // filter by performers ]); }, }); const studioMutationImpactedTypeFields = { Studio: ["child_studios"], }; export const studioMutationImpactedQueries = [ GQL.FindScenesDocument, // filter by studio GQL.FindImagesDocument, // filter by studio GQL.FindMoviesDocument, // filter by studio GQL.FindGalleriesDocument, // filter by studio GQL.FindPerformersDocument, // filter by studio GQL.FindStudiosDocument, // various filters ]; export const useStudioCreate = () => GQL.useStudioCreateMutation({ update(cache, result, { variables }) { const studio = result.data?.studioCreate; if (!studio || !variables) return; appendObject(cache, studio, GQL.AllStudiosForFilterDocument); // update stats updateStats(cache, "studio_count", 1); // if new scene has a parent studio, // refetch the parent's list of child studios const { parent_id } = variables.input; if (parent_id !== undefined) { cache.evict({ id: cache.identify({ __typename: "Studio", id: parent_id }), fieldName: "child_studios", }); } evictQueries(cache, [ GQL.FindStudiosDocument, // various filters ]); }, }); export const useStudioUpdate = () => GQL.useStudioUpdateMutation({ update(cache, result) { const studio = result.data?.studioUpdate; if (!studio) return; const obj = { __typename: "Studio", id: studio.id }; evictTypeFields( cache, studioMutationImpactedTypeFields, cache.identify(obj) // don't evict this studio ); evictQueries(cache, studioMutationImpactedQueries); }, }); export const useStudioDestroy = (input: GQL.StudioDestroyInput) => GQL.useStudioDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.studioDestroy) return; const obj = { __typename: "Studio", id: input.id }; deleteObject(cache, obj, GQL.FindStudioDocument); // update stats updateStats(cache, "studio_count", -1); evictTypeFields(cache, studioMutationImpactedTypeFields); evictQueries(cache, studioMutationImpactedQueries); }, }); export const useStudiosDestroy = (input: GQL.StudiosDestroyMutationVariables) => GQL.useStudiosDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.studiosDestroy) return; const { ids } = input; for (const id of ids) { const obj = { __typename: "Studio", id }; deleteObject(cache, obj, GQL.FindStudioDocument); } // update stats updateStats(cache, "studio_count", -ids.length); evictTypeFields(cache, studioMutationImpactedTypeFields); evictQueries(cache, studioMutationImpactedQueries); }, }); const tagMutationImpactedTypeFields = { Tag: ["parents", "children"], }; const tagMutationImpactedQueries = [ GQL.FindScenesDocument, // filter by tags GQL.FindImagesDocument, // filter by tags GQL.FindGalleriesDocument, // filter by tags GQL.FindPerformersDocument, // filter by tags GQL.FindTagsDocument, // various filters ]; export const useTagCreate = () => GQL.useTagCreateMutation({ update(cache, result) { const tag = result.data?.tagCreate; if (!tag) return; appendObject(cache, tag, GQL.AllTagsForFilterDocument); // update stats updateStats(cache, "tag_count", 1); const obj = { __typename: "Tag", id: tag.id }; evictTypeFields( cache, tagMutationImpactedTypeFields, cache.identify(obj) // don't evict this tag ); evictQueries(cache, [ GQL.FindTagsDocument, // various filters ]); }, }); export const useTagUpdate = () => GQL.useTagUpdateMutation({ update(cache, result) { const tag = result.data?.tagUpdate; if (!tag) return; const obj = { __typename: "Tag", id: tag.id }; evictTypeFields( cache, tagMutationImpactedTypeFields, cache.identify(obj) // don't evict this tag ); evictQueries(cache, tagMutationImpactedQueries); }, }); export const useTagDestroy = (input: GQL.TagDestroyInput) => GQL.useTagDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.tagDestroy) return; const obj = { __typename: "Tag", id: input.id }; deleteObject(cache, obj, GQL.FindTagDocument); // update stats updateStats(cache, "tag_count", -1); evictTypeFields(cache, tagMutationImpactedTypeFields); evictQueries(cache, tagMutationImpactedQueries); }, }); export const useTagsDestroy = (input: GQL.TagsDestroyMutationVariables) => GQL.useTagsDestroyMutation({ variables: input, update(cache, result) { if (!result.data?.tagsDestroy) return; const { ids } = input; for (const id of ids) { const obj = { __typename: "Tag", id }; deleteObject(cache, obj, GQL.FindTagDocument); } // update stats updateStats(cache, "tag_count", -ids.length); evictTypeFields(cache, tagMutationImpactedTypeFields); evictQueries(cache, tagMutationImpactedQueries); }, }); export const useTagsMerge = () => GQL.useTagsMergeMutation({ update(cache, result, { variables }) { if (!result.data?.tagsMerge || !variables) return; const { source, destination } = variables; for (const id of source) { const obj = { __typename: "Tag", id }; deleteObject(cache, obj, GQL.FindTagDocument); } updateStats(cache, "tag_count", -source.length); const obj = { __typename: "Tag", id: destination }; evictTypeFields( cache, tagMutationImpactedTypeFields, cache.identify(obj) // don't evict destination tag ); evictQueries(cache, tagMutationImpactedQueries); }, }); export const useSaveFilter = () => GQL.useSaveFilterMutation({ update(cache, result) { if (!result.data?.saveFilter) return; evictQueries(cache, [GQL.FindSavedFiltersDocument]); }, }); export const useSetDefaultFilter = () => GQL.useSetDefaultFilterMutation({ update(cache, result) { if (!result.data?.setDefaultFilter) return; evictQueries(cache, [GQL.FindDefaultFilterDocument]); }, }); export const useSavedFilterDestroy = () => GQL.useDestroySavedFilterMutation({ update(cache, result, { variables }) { if (!result.data?.destroySavedFilter || !variables) return; const obj = { __typename: "SavedFilter", id: variables.input.id }; deleteObject(cache, obj, GQL.FindSavedFilterDocument); evictQueries(cache, [GQL.FindDefaultFilterDocument]); }, }); export const mutateDeleteFiles = (ids: string[]) => client.mutate({ mutation: GQL.DeleteFilesDocument, variables: { ids }, update(cache, result) { if (!result.data?.deleteFiles) return; // we don't know which type the files are, // so evict all of them for (const id of ids) { cache.evict({ id: cache.identify({ __typename: "VideoFile", id }), }); cache.evict({ id: cache.identify({ __typename: "ImageFile", id }), }); cache.evict({ id: cache.identify({ __typename: "GalleryFile", id }), }); } evictQueries(cache, [ GQL.FindScenesDocument, // filter by file count GQL.FindImagesDocument, // filter by file count GQL.FindGalleriesDocument, // filter by file count GQL.StatsDocument, // scenes size, images size ]); }, }); /// Scrapers export const useListSceneScrapers = () => GQL.useListSceneScrapersQuery(); export const queryScrapeScene = ( source: GQL.ScraperSourceInput, sceneId: string ) => client.query({ query: GQL.ScrapeSingleSceneDocument, variables: { source, input: { scene_id: sceneId, }, }, fetchPolicy: "network-only", }); export const queryScrapeSceneQuery = ( source: GQL.ScraperSourceInput, q: string ) => client.query({ query: GQL.ScrapeSingleSceneDocument, variables: { source, input: { query: q, }, }, fetchPolicy: "network-only", }); export const queryScrapeSceneURL = (url: string) => client.query({ query: GQL.ScrapeSceneUrlDocument, variables: { url }, fetchPolicy: "network-only", }); export const queryScrapeSceneQueryFragment = ( source: GQL.ScraperSourceInput, input: GQL.ScrapedSceneInput ) => client.query({ query: GQL.ScrapeSingleSceneDocument, variables: { source, input: { scene_input: input, }, }, fetchPolicy: "network-only", }); export const stashBoxSceneBatchQuery = ( sceneIds: string[], stashBoxIndex: number ) => client.query({ query: GQL.ScrapeMultiScenesDocument, variables: { source: { stash_box_index: stashBoxIndex, }, input: { scene_ids: sceneIds, }, }, }); export const useListPerformerScrapers = () => GQL.useListPerformerScrapersQuery(); export const useScrapePerformerList = (scraperId: string, q: string) => GQL.useScrapeSinglePerformerQuery({ variables: { source: { scraper_id: scraperId, }, input: { query: q, }, }, skip: q === "", }); export const queryScrapePerformer = ( scraperId: string, scrapedPerformer: GQL.ScrapedPerformerInput ) => client.query({ query: GQL.ScrapeSinglePerformerDocument, variables: { source: { scraper_id: scraperId, }, input: { performer_input: scrapedPerformer, }, }, fetchPolicy: "network-only", }); export const queryScrapePerformerURL = (url: string) => client.query({ query: GQL.ScrapePerformerUrlDocument, variables: { url }, fetchPolicy: "network-only", }); export const stashBoxPerformerQuery = ( searchVal: string, stashBoxIndex: number ) => client.query({ query: GQL.ScrapeSinglePerformerDocument, variables: { source: { stash_box_index: stashBoxIndex, }, input: { query: searchVal, }, }, fetchPolicy: "network-only", }); export const stashBoxStudioQuery = ( query: string | null, stashBoxIndex: number ) => client.query({ query: GQL.ScrapeSingleStudioDocument, variables: { source: { stash_box_index: stashBoxIndex, }, input: { query: query, }, }, fetchPolicy: "network-only", }); export const mutateStashBoxBatchPerformerTag = ( input: GQL.StashBoxBatchTagInput ) => client.mutate({ mutation: GQL.StashBoxBatchPerformerTagDocument, variables: { input }, }); export const mutateStashBoxBatchStudioTag = ( input: GQL.StashBoxBatchTagInput ) => client.mutate({ mutation: GQL.StashBoxBatchStudioTagDocument, variables: { input }, }); export const useListMovieScrapers = () => GQL.useListMovieScrapersQuery(); export const queryScrapeMovieURL = (url: string) => client.query({ query: GQL.ScrapeMovieUrlDocument, variables: { url }, fetchPolicy: "network-only", }); export const useListGalleryScrapers = () => GQL.useListGalleryScrapersQuery(); export const queryScrapeGallery = (scraperId: string, galleryId: string) => client.query({ query: GQL.ScrapeSingleGalleryDocument, variables: { source: { scraper_id: scraperId, }, input: { gallery_id: galleryId, }, }, fetchPolicy: "network-only", }); export const queryScrapeGalleryURL = (url: string) => client.query({ query: GQL.ScrapeGalleryUrlDocument, variables: { url }, fetchPolicy: "network-only", }); export const mutateSubmitStashBoxSceneDraft = ( input: GQL.StashBoxDraftSubmissionInput ) => client.mutate({ mutation: GQL.SubmitStashBoxSceneDraftDocument, variables: { input }, }); export const mutateSubmitStashBoxPerformerDraft = ( input: GQL.StashBoxDraftSubmissionInput ) => client.mutate({ mutation: GQL.SubmitStashBoxPerformerDraftDocument, variables: { input }, }); /// Configuration export const useConfiguration = () => GQL.useConfigurationQuery(); export const usePlugins = () => GQL.usePluginsQuery(); export const usePluginTasks = () => GQL.usePluginTasksQuery(); export const useStats = () => GQL.useStatsQuery(); export const useVersion = () => GQL.useVersionQuery(); export const useLatestVersion = () => GQL.useLatestVersionQuery({ notifyOnNetworkStatusChange: true, errorPolicy: "ignore", }); export const useDLNAStatus = () => GQL.useDlnaStatusQuery({ fetchPolicy: "no-cache", }); export const useJobQueue = () => GQL.useJobQueueQuery({ fetchPolicy: "no-cache", }); export const useLogs = () => GQL.useLogsQuery({ fetchPolicy: "no-cache", }); export const queryLogs = () => client.query({ query: GQL.LogsDocument, fetchPolicy: "no-cache", }); export const useSystemStatus = () => GQL.useSystemStatusQuery(); export const useJobsSubscribe = () => GQL.useJobsSubscribeSubscription(); export const useLoggingSubscribe = () => GQL.useLoggingSubscribeSubscription(); // all scraper-related queries export const scraperMutationImpactedQueries = [ GQL.ListMovieScrapersDocument, GQL.ListPerformerScrapersDocument, GQL.ListSceneScrapersDocument, GQL.InstalledScraperPackagesDocument, GQL.InstalledScraperPackagesStatusDocument, ]; export const mutateReloadScrapers = () => client.mutate({ mutation: GQL.ReloadScrapersDocument, update(cache, result) { if (!result.data?.reloadScrapers) return; evictQueries(cache, scraperMutationImpactedQueries); }, }); // all plugin-related queries export const pluginMutationImpactedQueries = [ GQL.PluginsDocument, GQL.PluginTasksDocument, GQL.InstalledPluginPackagesDocument, GQL.InstalledPluginPackagesStatusDocument, ]; export const mutateReloadPlugins = () => client.mutate({ mutation: GQL.ReloadPluginsDocument, update(cache, result) { if (!result.data?.reloadPlugins) return; evictQueries(cache, pluginMutationImpactedQueries); }, }); type BoolMap = { [key: string]: boolean }; export const mutateSetPluginsEnabled = (enabledMap: BoolMap) => client.mutate({ mutation: GQL.SetPluginsEnabledDocument, variables: { enabledMap }, update(cache, result) { if (!result.data?.setPluginsEnabled) return; for (const id in enabledMap) { cache.modify({ id: cache.identify({ __typename: "Plugin", id }), fields: { enabled() { return enabledMap[id]; }, }, }); } }, }); function updateConfiguration(cache: ApolloCache, result: FetchResult) { if (!result.data) return; evictQueries(cache, [GQL.ConfigurationDocument]); } export const useConfigureGeneral = () => GQL.useConfigureGeneralMutation({ update(cache, result) { if (!result.data?.configureGeneral) return; evictQueries(cache, [ GQL.ConfigurationDocument, ...scraperMutationImpactedQueries, ...pluginMutationImpactedQueries, ]); }, }); export const useConfigureInterface = () => GQL.useConfigureInterfaceMutation({ update: updateConfiguration, }); export const useGenerateAPIKey = () => GQL.useGenerateApiKeyMutation({ update: updateConfiguration, }); export const useConfigureDefaults = () => GQL.useConfigureDefaultsMutation({ update: updateConfiguration, }); export const useConfigureUI = () => GQL.useConfigureUiMutation({ update: updateConfiguration, }); export const useConfigureScraping = () => GQL.useConfigureScrapingMutation({ update: updateConfiguration, }); export const useConfigureDLNA = () => GQL.useConfigureDlnaMutation({ update: updateConfiguration, }); export const useConfigurePlugin = () => GQL.useConfigurePluginMutation({ update: updateConfiguration, }); export const useEnableDLNA = () => GQL.useEnableDlnaMutation(); export const useDisableDLNA = () => GQL.useDisableDlnaMutation(); export const useAddTempDLNAIP = () => GQL.useAddTempDlnaipMutation(); export const useRemoveTempDLNAIP = () => GQL.useRemoveTempDlnaipMutation(); export const mutateStopJob = (jobID: string) => client.mutate({ mutation: GQL.StopJobDocument, variables: { job_id: jobID }, }); const setupMutationImpactedQueries = [ GQL.ConfigurationDocument, GQL.SystemStatusDocument, ]; export const mutateSetup = (input: GQL.SetupInput) => client.mutate({ mutation: GQL.SetupDocument, variables: { input }, update(cache, result) { if (!result.data?.setup) return; evictQueries(cache, setupMutationImpactedQueries); }, }); export const mutateMigrate = (input: GQL.MigrateInput) => client.mutate({ mutation: GQL.MigrateDocument, variables: { input }, update(cache, result) { if (!result.data?.migrate) return; evictQueries(cache, setupMutationImpactedQueries); }, }); /// Packages // Acts like GQL.useInstalledScraperPackagesStatusQuery if loadUpgrades is true, // and GQL.useInstalledScraperPackagesQuery if it is false export const useInstalledScraperPackages = ( loadUpgrades: T ) => { const query = loadUpgrades ? GQL.InstalledScraperPackagesStatusDocument : GQL.InstalledScraperPackagesDocument; type TData = T extends true ? GQL.InstalledScraperPackagesStatusQuery : GQL.InstalledScraperPackagesQuery; type TVariables = T extends true ? GQL.InstalledScraperPackagesStatusQueryVariables : GQL.InstalledScraperPackagesQueryVariables; return useQuery(query); }; export const queryAvailableScraperPackages = (source: string) => client.query({ query: GQL.AvailableScraperPackagesDocument, variables: { source, }, fetchPolicy: "network-only", }); export const mutateInstallScraperPackages = ( packages: GQL.PackageSpecInput[] ) => client.mutate({ mutation: GQL.InstallScraperPackagesDocument, variables: { packages, }, }); export const mutateUpdateScraperPackages = (packages: GQL.PackageSpecInput[]) => client.mutate({ mutation: GQL.UpdateScraperPackagesDocument, variables: { packages, }, }); export const mutateUninstallScraperPackages = ( packages: GQL.PackageSpecInput[] ) => client.mutate({ mutation: GQL.UninstallScraperPackagesDocument, variables: { packages, }, }); // Acts like GQL.useInstalledPluginPackagesStatusQuery if loadUpgrades is true, // and GQL.useInstalledPluginPackagesQuery if it is false export const useInstalledPluginPackages = ( loadUpgrades: T ) => { const query = loadUpgrades ? GQL.InstalledPluginPackagesStatusDocument : GQL.InstalledPluginPackagesDocument; type TData = T extends true ? GQL.InstalledPluginPackagesStatusQuery : GQL.InstalledPluginPackagesQuery; type TVariables = T extends true ? GQL.InstalledPluginPackagesStatusQueryVariables : GQL.InstalledPluginPackagesQueryVariables; return useQuery(query); }; export const queryAvailablePluginPackages = (source: string) => client.query({ query: GQL.AvailablePluginPackagesDocument, variables: { source, }, fetchPolicy: "network-only", }); export const mutateInstallPluginPackages = (packages: GQL.PackageSpecInput[]) => client.mutate({ mutation: GQL.InstallPluginPackagesDocument, variables: { packages, }, }); export const mutateUpdatePluginPackages = (packages: GQL.PackageSpecInput[]) => client.mutate({ mutation: GQL.UpdatePluginPackagesDocument, variables: { packages, }, }); export const mutateUninstallPluginPackages = ( packages: GQL.PackageSpecInput[] ) => client.mutate({ mutation: GQL.UninstallPluginPackagesDocument, variables: { packages, }, }); /// Tasks export const mutateMetadataScan = (input: GQL.ScanMetadataInput) => client.mutate({ mutation: GQL.MetadataScanDocument, variables: { input }, }); export const mutateMetadataIdentify = (input: GQL.IdentifyMetadataInput) => client.mutate({ mutation: GQL.MetadataIdentifyDocument, variables: { input }, }); export const mutateMetadataAutoTag = (input: GQL.AutoTagMetadataInput) => client.mutate({ mutation: GQL.MetadataAutoTagDocument, variables: { input }, }); export const mutateMetadataGenerate = (input: GQL.GenerateMetadataInput) => client.mutate({ mutation: GQL.MetadataGenerateDocument, variables: { input }, }); export const mutateMetadataClean = (input: GQL.CleanMetadataInput) => client.mutate({ mutation: GQL.MetadataCleanDocument, variables: { input }, }); export const mutateRunPluginTask = ( pluginId: string, taskName: string, args?: GQL.PluginArgInput[] ) => client.mutate({ mutation: GQL.RunPluginTaskDocument, variables: { plugin_id: pluginId, task_name: taskName, args }, }); export const mutateMetadataExport = () => client.mutate({ mutation: GQL.MetadataExportDocument, }); export const mutateExportObjects = (input: GQL.ExportObjectsInput) => client.mutate({ mutation: GQL.ExportObjectsDocument, variables: { input }, }); export const mutateMetadataImport = () => client.mutate({ mutation: GQL.MetadataImportDocument, }); export const mutateImportObjects = (input: GQL.ImportObjectsInput) => client.mutate({ mutation: GQL.ImportObjectsDocument, variables: { input }, }); export const mutateBackupDatabase = (input: GQL.BackupDatabaseInput) => client.mutate({ mutation: GQL.BackupDatabaseDocument, variables: { input }, }); export const mutateAnonymiseDatabase = (input: GQL.AnonymiseDatabaseInput) => client.mutate({ mutation: GQL.AnonymiseDatabaseDocument, variables: { input }, }); export const mutateOptimiseDatabase = () => client.mutate({ mutation: GQL.OptimiseDatabaseDocument, }); export const mutateMigrateHashNaming = () => client.mutate({ mutation: GQL.MigrateHashNamingDocument, }); export const mutateMigrateSceneScreenshots = ( input: GQL.MigrateSceneScreenshotsInput ) => client.mutate({ mutation: GQL.MigrateSceneScreenshotsDocument, variables: { input }, }); export const mutateMigrateBlobs = (input: GQL.MigrateBlobsInput) => client.mutate({ mutation: GQL.MigrateBlobsDocument, variables: { input }, }); /// Misc export const useDirectory = (path?: string) => GQL.useDirectoryQuery({ variables: { path } }); export const queryParseSceneFilenames = ( filter: GQL.FindFilterType, config: GQL.SceneParserInput ) => client.query({ query: GQL.ParseSceneFilenamesDocument, variables: { filter, config }, fetchPolicy: "network-only", });