mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Remove unnecessary graphql fields (#1370)
* Remove unnecessary graphql fields * Optimise joined queries * Tag resolver query optimisation
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
fragment GallerySlimData on Gallery {
|
||||
fragment SlimGalleryData on Gallery {
|
||||
id
|
||||
checksum
|
||||
path
|
||||
@@ -10,16 +10,31 @@ fragment GallerySlimData on Gallery {
|
||||
organized
|
||||
image_count
|
||||
cover {
|
||||
...SlimImageData
|
||||
file {
|
||||
size
|
||||
width
|
||||
height
|
||||
}
|
||||
|
||||
paths {
|
||||
thumbnail
|
||||
}
|
||||
}
|
||||
studio {
|
||||
...StudioData
|
||||
id
|
||||
name
|
||||
image_path
|
||||
}
|
||||
tags {
|
||||
...TagData
|
||||
id
|
||||
name
|
||||
}
|
||||
performers {
|
||||
...PerformerData
|
||||
id
|
||||
name
|
||||
gender
|
||||
favorite
|
||||
image_path
|
||||
}
|
||||
scenes {
|
||||
id
|
||||
|
||||
@@ -15,16 +15,16 @@ fragment GalleryData on Gallery {
|
||||
...SlimImageData
|
||||
}
|
||||
studio {
|
||||
...StudioData
|
||||
...SlimStudioData
|
||||
}
|
||||
tags {
|
||||
...TagData
|
||||
...SlimTagData
|
||||
}
|
||||
|
||||
performers {
|
||||
...PerformerData
|
||||
}
|
||||
scenes {
|
||||
...SceneData
|
||||
...SlimSceneData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ fragment ImageData on Image {
|
||||
}
|
||||
|
||||
studio {
|
||||
...StudioData
|
||||
...SlimStudioData
|
||||
}
|
||||
|
||||
tags {
|
||||
...TagData
|
||||
...SlimTagData
|
||||
}
|
||||
|
||||
performers {
|
||||
|
||||
@@ -9,7 +9,7 @@ fragment MovieData on Movie {
|
||||
director
|
||||
|
||||
studio {
|
||||
...StudioData
|
||||
...SlimStudioData
|
||||
}
|
||||
|
||||
synopsis
|
||||
|
||||
@@ -24,7 +24,7 @@ fragment PerformerData on Performer {
|
||||
gallery_count
|
||||
|
||||
tags {
|
||||
...TagData
|
||||
...SlimTagData
|
||||
}
|
||||
|
||||
stash_ids {
|
||||
|
||||
@@ -37,11 +37,11 @@ fragment SceneData on Scene {
|
||||
}
|
||||
|
||||
galleries {
|
||||
...GallerySlimData
|
||||
...SlimGalleryData
|
||||
}
|
||||
|
||||
studio {
|
||||
...StudioData
|
||||
...SlimStudioData
|
||||
}
|
||||
|
||||
movies {
|
||||
@@ -52,7 +52,7 @@ fragment SceneData on Scene {
|
||||
}
|
||||
|
||||
tags {
|
||||
...TagData
|
||||
...SlimTagData
|
||||
}
|
||||
|
||||
performers {
|
||||
|
||||
5
graphql/documents/data/tag-slim.graphql
Normal file
5
graphql/documents/data/tag-slim.graphql
Normal file
@@ -0,0 +1,5 @@
|
||||
fragment SlimTagData on Tag {
|
||||
id
|
||||
name
|
||||
image_path
|
||||
}
|
||||
@@ -2,7 +2,7 @@ query FindGalleries($filter: FindFilterType, $gallery_filter: GalleryFilterType)
|
||||
findGalleries(gallery_filter: $gallery_filter, filter: $filter) {
|
||||
count
|
||||
galleries {
|
||||
...GallerySlimData
|
||||
...SlimGalleryData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,6 +376,60 @@ func stringLiteralCriterionHandler(v *string, column string) criterionHandlerFun
|
||||
}
|
||||
}
|
||||
|
||||
// handle for MultiCriterion where there is a join table between the new
|
||||
// objects
|
||||
type joinedMultiCriterionHandlerBuilder struct {
|
||||
// table containing the primary objects
|
||||
primaryTable string
|
||||
// table joining primary and foreign objects
|
||||
joinTable string
|
||||
// alias for join table, if required
|
||||
joinAs string
|
||||
// foreign key of the primary object on the join table
|
||||
primaryFK string
|
||||
// foreign key of the foreign object on the join table
|
||||
foreignFK string
|
||||
|
||||
addJoinTable func(f *filterBuilder)
|
||||
}
|
||||
|
||||
func (m *joinedMultiCriterionHandlerBuilder) handler(criterion *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
return func(f *filterBuilder) {
|
||||
if criterion != nil && len(criterion.Value) > 0 {
|
||||
var args []interface{}
|
||||
for _, tagID := range criterion.Value {
|
||||
args = append(args, tagID)
|
||||
}
|
||||
|
||||
joinAlias := m.joinAs
|
||||
if joinAlias == "" {
|
||||
joinAlias = m.joinTable
|
||||
}
|
||||
|
||||
whereClause := ""
|
||||
havingClause := ""
|
||||
if criterion.Modifier == models.CriterionModifierIncludes {
|
||||
// includes any of the provided ids
|
||||
m.addJoinTable(f)
|
||||
whereClause = fmt.Sprintf("%s.%s IN %s", joinAlias, m.foreignFK, getInBinding(len(criterion.Value)))
|
||||
} else if criterion.Modifier == models.CriterionModifierIncludesAll {
|
||||
// includes all of the provided ids
|
||||
m.addJoinTable(f)
|
||||
whereClause = fmt.Sprintf("%s.%s IN %s", joinAlias, m.foreignFK, getInBinding(len(criterion.Value)))
|
||||
havingClause = fmt.Sprintf("count(distinct %s.%s) IS %d", joinAlias, m.foreignFK, len(criterion.Value))
|
||||
} else if criterion.Modifier == models.CriterionModifierExcludes {
|
||||
// excludes all of the provided ids
|
||||
// need to use actual join table name for this
|
||||
// not exists (select <joinTable>.<primaryFK> from <joinTable> where <joinTable>.<primaryFK> = <primaryTable>.id and <joinTable>.<foreignFK> in <values>)
|
||||
whereClause = fmt.Sprintf("not exists (select %[1]s.%[2]s from %[1]s where %[1]s.%[2]s = %[3]s.id and %[1]s.%[4]s in %[5]s)", m.joinTable, m.primaryFK, m.primaryTable, m.foreignFK, getInBinding(len(criterion.Value)))
|
||||
}
|
||||
|
||||
f.addWhere(whereClause, args...)
|
||||
f.addHaving(havingClause)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type multiCriterionHandlerBuilder struct {
|
||||
primaryTable string
|
||||
foreignTable string
|
||||
|
||||
@@ -321,11 +321,17 @@ func (qb *galleryQueryBuilder) getMultiCriterionHandlerBuilder(foreignTable, joi
|
||||
}
|
||||
|
||||
func galleryTagsCriterionHandler(qb *galleryQueryBuilder, tags *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
addJoinsFunc := func(f *filterBuilder) {
|
||||
qb.tagsRepository().join(f, "tags_join", "galleries.id")
|
||||
f.addJoin(tagTable, "", "tags_join.tag_id = tags.id")
|
||||
h := joinedMultiCriterionHandlerBuilder{
|
||||
primaryTable: galleryTable,
|
||||
joinTable: galleriesTagsTable,
|
||||
joinAs: "tags_join",
|
||||
primaryFK: galleryIDColumn,
|
||||
foreignFK: tagIDColumn,
|
||||
|
||||
addJoinTable: func(f *filterBuilder) {
|
||||
qb.tagsRepository().join(f, "tags_join", "galleries.id")
|
||||
},
|
||||
}
|
||||
h := qb.getMultiCriterionHandlerBuilder(tagTable, galleriesTagsTable, tagIDColumn, addJoinsFunc)
|
||||
|
||||
return h.handler(tags)
|
||||
}
|
||||
@@ -341,11 +347,17 @@ func galleryTagCountCriterionHandler(qb *galleryQueryBuilder, tagCount *models.I
|
||||
}
|
||||
|
||||
func galleryPerformersCriterionHandler(qb *galleryQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
addJoinsFunc := func(f *filterBuilder) {
|
||||
qb.performersRepository().join(f, "performers_join", "galleries.id")
|
||||
f.addJoin(performerTable, "", "performers_join.performer_id = performers.id")
|
||||
h := joinedMultiCriterionHandlerBuilder{
|
||||
primaryTable: galleryTable,
|
||||
joinTable: performersGalleriesTable,
|
||||
joinAs: "performers_join",
|
||||
primaryFK: galleryIDColumn,
|
||||
foreignFK: performerIDColumn,
|
||||
|
||||
addJoinTable: func(f *filterBuilder) {
|
||||
qb.performersRepository().join(f, "performers_join", "galleries.id")
|
||||
},
|
||||
}
|
||||
h := qb.getMultiCriterionHandlerBuilder(performerTable, performersGalleriesTable, performerIDColumn, addJoinsFunc)
|
||||
|
||||
return h.handler(performers)
|
||||
}
|
||||
|
||||
@@ -347,11 +347,17 @@ func (qb *imageQueryBuilder) getMultiCriterionHandlerBuilder(foreignTable, joinT
|
||||
}
|
||||
|
||||
func imageTagsCriterionHandler(qb *imageQueryBuilder, tags *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
addJoinsFunc := func(f *filterBuilder) {
|
||||
qb.tagsRepository().join(f, "tags_join", "images.id")
|
||||
f.addJoin(tagTable, "", "tags_join.tag_id = tags.id")
|
||||
h := joinedMultiCriterionHandlerBuilder{
|
||||
primaryTable: imageTable,
|
||||
joinTable: imagesTagsTable,
|
||||
joinAs: "tags_join",
|
||||
primaryFK: imageIDColumn,
|
||||
foreignFK: tagIDColumn,
|
||||
|
||||
addJoinTable: func(f *filterBuilder) {
|
||||
qb.tagsRepository().join(f, "tags_join", "images.id")
|
||||
},
|
||||
}
|
||||
h := qb.getMultiCriterionHandlerBuilder(tagTable, imagesTagsTable, tagIDColumn, addJoinsFunc)
|
||||
|
||||
return h.handler(tags)
|
||||
}
|
||||
@@ -377,11 +383,17 @@ func imageGalleriesCriterionHandler(qb *imageQueryBuilder, galleries *models.Mul
|
||||
}
|
||||
|
||||
func imagePerformersCriterionHandler(qb *imageQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
addJoinsFunc := func(f *filterBuilder) {
|
||||
qb.performersRepository().join(f, "performers_join", "images.id")
|
||||
f.addJoin(performerTable, "", "performers_join.performer_id = performers.id")
|
||||
h := joinedMultiCriterionHandlerBuilder{
|
||||
primaryTable: imageTable,
|
||||
joinTable: performersImagesTable,
|
||||
joinAs: "performers_join",
|
||||
primaryFK: imageIDColumn,
|
||||
foreignFK: performerIDColumn,
|
||||
|
||||
addJoinTable: func(f *filterBuilder) {
|
||||
qb.performersRepository().join(f, "performers_join", "images.id")
|
||||
},
|
||||
}
|
||||
h := qb.getMultiCriterionHandlerBuilder(performerTable, performersImagesTable, performerIDColumn, addJoinsFunc)
|
||||
|
||||
return h.handler(performers)
|
||||
}
|
||||
|
||||
@@ -562,11 +562,17 @@ func sceneTagCountCriterionHandler(qb *sceneQueryBuilder, tagCount *models.IntCr
|
||||
}
|
||||
|
||||
func scenePerformersCriterionHandler(qb *sceneQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc {
|
||||
addJoinsFunc := func(f *filterBuilder) {
|
||||
qb.performersRepository().join(f, "performers_join", "scenes.id")
|
||||
f.addJoin("performers", "", "performers_join.performer_id = performers.id")
|
||||
h := joinedMultiCriterionHandlerBuilder{
|
||||
primaryTable: sceneTable,
|
||||
joinTable: performersScenesTable,
|
||||
joinAs: "performers_join",
|
||||
primaryFK: sceneIDColumn,
|
||||
foreignFK: performerIDColumn,
|
||||
|
||||
addJoinTable: func(f *filterBuilder) {
|
||||
qb.performersRepository().join(f, "performers_join", "scenes.id")
|
||||
},
|
||||
}
|
||||
h := qb.getMultiCriterionHandlerBuilder(performerTable, performersScenesTable, performerIDColumn, addJoinsFunc)
|
||||
|
||||
return h.handler(performers)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import MultiSet from "../Shared/MultiSet";
|
||||
import { RatingStars } from "../Scenes/SceneDetails/RatingStars";
|
||||
|
||||
interface IListOperationProps {
|
||||
selected: GQL.GallerySlimDataFragment[];
|
||||
selected: GQL.SlimGalleryDataFragment[];
|
||||
onClose: (applied: boolean) => void;
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
setIsUpdating(false);
|
||||
}
|
||||
|
||||
function getRating(state: GQL.GallerySlimDataFragment[]) {
|
||||
function getRating(state: GQL.SlimGalleryDataFragment[]) {
|
||||
let ret: number | undefined;
|
||||
let first = true;
|
||||
|
||||
@@ -162,7 +162,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getStudioId(state: GQL.GallerySlimDataFragment[]) {
|
||||
function getStudioId(state: GQL.SlimGalleryDataFragment[]) {
|
||||
let ret: string | undefined;
|
||||
let first = true;
|
||||
|
||||
@@ -181,7 +181,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getPerformerIds(state: GQL.GallerySlimDataFragment[]) {
|
||||
function getPerformerIds(state: GQL.SlimGalleryDataFragment[]) {
|
||||
let ret: string[] = [];
|
||||
let first = true;
|
||||
|
||||
@@ -205,7 +205,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getTagIds(state: GQL.GallerySlimDataFragment[]) {
|
||||
function getTagIds(state: GQL.SlimGalleryDataFragment[]) {
|
||||
let ret: string[] = [];
|
||||
let first = true;
|
||||
|
||||
@@ -234,7 +234,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
let updateOrganized: boolean | undefined;
|
||||
let first = true;
|
||||
|
||||
state.forEach((gallery: GQL.GallerySlimDataFragment) => {
|
||||
state.forEach((gallery: GQL.SlimGalleryDataFragment) => {
|
||||
const galleryRating = gallery.rating;
|
||||
const GalleriestudioID = gallery?.studio?.id;
|
||||
const galleryPerformerIDs = (gallery.performers ?? [])
|
||||
|
||||
@@ -15,7 +15,7 @@ import { TextUtils } from "src/utils";
|
||||
import { PerformerPopoverButton } from "../Shared/PerformerPopoverButton";
|
||||
|
||||
interface IProps {
|
||||
gallery: GQL.GallerySlimDataFragment;
|
||||
gallery: GQL.SlimGalleryDataFragment;
|
||||
selecting?: boolean;
|
||||
selected?: boolean | undefined;
|
||||
zoomIndex?: number;
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as GQL from "src/core/generated-graphql";
|
||||
import { SceneCard } from "src/components/Scenes/SceneCard";
|
||||
|
||||
interface IGalleryScenesPanelProps {
|
||||
scenes: GQL.SceneDataFragment[];
|
||||
scenes: GQL.SlimSceneDataFragment[];
|
||||
}
|
||||
|
||||
export const GalleryScenesPanel: React.FC<IGalleryScenesPanelProps> = ({
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Link, useHistory } from "react-router-dom";
|
||||
import Mousetrap from "mousetrap";
|
||||
import {
|
||||
FindGalleriesQueryResult,
|
||||
GallerySlimDataFragment,
|
||||
SlimGalleryDataFragment,
|
||||
} from "src/core/generated-graphql";
|
||||
import { useGalleriesList } from "src/hooks";
|
||||
import { TextUtils } from "src/utils";
|
||||
@@ -130,7 +130,7 @@ export const GalleryList: React.FC<IGalleryList> = ({
|
||||
}
|
||||
|
||||
function renderEditGalleriesDialog(
|
||||
selectedImages: GallerySlimDataFragment[],
|
||||
selectedImages: SlimGalleryDataFragment[],
|
||||
onClose: (applied: boolean) => void
|
||||
) {
|
||||
return (
|
||||
@@ -141,7 +141,7 @@ export const GalleryList: React.FC<IGalleryList> = ({
|
||||
}
|
||||
|
||||
function renderDeleteGalleriesDialog(
|
||||
selectedImages: GallerySlimDataFragment[],
|
||||
selectedImages: SlimGalleryDataFragment[],
|
||||
onClose: (confirmed: boolean) => void
|
||||
) {
|
||||
return (
|
||||
|
||||
@@ -12,7 +12,7 @@ const CLASSNAME_IMG = `${CLASSNAME}-img`;
|
||||
const CLASSNAME_TITLE = `${CLASSNAME}-title`;
|
||||
|
||||
interface IProps {
|
||||
gallery: GQL.GallerySlimDataFragment;
|
||||
gallery: GQL.SlimGalleryDataFragment;
|
||||
}
|
||||
|
||||
const GalleryWallCard: React.FC<IProps> = ({ gallery }) => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as GQL from "src/core/generated-graphql";
|
||||
import { GalleryCard } from "src/components/Galleries/GalleryCard";
|
||||
|
||||
interface ISceneGalleriesPanelProps {
|
||||
galleries: GQL.GallerySlimDataFragment[];
|
||||
galleries: GQL.SlimGalleryDataFragment[];
|
||||
}
|
||||
|
||||
export const SceneGalleriesPanel: React.FC<ISceneGalleriesPanelProps> = ({
|
||||
|
||||
@@ -13,7 +13,7 @@ import Mousetrap from "mousetrap";
|
||||
import {
|
||||
SlimSceneDataFragment,
|
||||
SceneMarkerDataFragment,
|
||||
GallerySlimDataFragment,
|
||||
SlimGalleryDataFragment,
|
||||
StudioDataFragment,
|
||||
PerformerDataFragment,
|
||||
FindScenesQueryResult,
|
||||
@@ -621,9 +621,9 @@ export const useImagesList = (
|
||||
});
|
||||
|
||||
export const useGalleriesList = (
|
||||
props: IListHookOptions<FindGalleriesQueryResult, GallerySlimDataFragment>
|
||||
props: IListHookOptions<FindGalleriesQueryResult, SlimGalleryDataFragment>
|
||||
) =>
|
||||
useList<FindGalleriesQueryResult, GallerySlimDataFragment>({
|
||||
useList<FindGalleriesQueryResult, SlimGalleryDataFragment>({
|
||||
...props,
|
||||
filterMode: FilterMode.Galleries,
|
||||
useData: useFindGalleries,
|
||||
|
||||
Reference in New Issue
Block a user