Remove unnecessary graphql fields (#1370)

* Remove unnecessary graphql fields
* Optimise joined queries
* Tag resolver query optimisation
This commit is contained in:
WithoutPants
2021-05-09 19:25:57 +10:00
committed by GitHub
parent 81cf3d3337
commit 3f97b3a1cb
19 changed files with 156 additions and 52 deletions

View File

@@ -1,4 +1,4 @@
fragment GallerySlimData on Gallery { fragment SlimGalleryData on Gallery {
id id
checksum checksum
path path
@@ -10,16 +10,31 @@ fragment GallerySlimData on Gallery {
organized organized
image_count image_count
cover { cover {
...SlimImageData file {
size
width
height
}
paths {
thumbnail
}
} }
studio { studio {
...StudioData id
name
image_path
} }
tags { tags {
...TagData id
name
} }
performers { performers {
...PerformerData id
name
gender
favorite
image_path
} }
scenes { scenes {
id id

View File

@@ -15,16 +15,16 @@ fragment GalleryData on Gallery {
...SlimImageData ...SlimImageData
} }
studio { studio {
...StudioData ...SlimStudioData
} }
tags { tags {
...TagData ...SlimTagData
} }
performers { performers {
...PerformerData ...PerformerData
} }
scenes { scenes {
...SceneData ...SlimSceneData
} }
} }

View File

@@ -23,11 +23,11 @@ fragment ImageData on Image {
} }
studio { studio {
...StudioData ...SlimStudioData
} }
tags { tags {
...TagData ...SlimTagData
} }
performers { performers {

View File

@@ -9,7 +9,7 @@ fragment MovieData on Movie {
director director
studio { studio {
...StudioData ...SlimStudioData
} }
synopsis synopsis

View File

@@ -24,7 +24,7 @@ fragment PerformerData on Performer {
gallery_count gallery_count
tags { tags {
...TagData ...SlimTagData
} }
stash_ids { stash_ids {

View File

@@ -37,11 +37,11 @@ fragment SceneData on Scene {
} }
galleries { galleries {
...GallerySlimData ...SlimGalleryData
} }
studio { studio {
...StudioData ...SlimStudioData
} }
movies { movies {
@@ -52,7 +52,7 @@ fragment SceneData on Scene {
} }
tags { tags {
...TagData ...SlimTagData
} }
performers { performers {

View File

@@ -0,0 +1,5 @@
fragment SlimTagData on Tag {
id
name
image_path
}

View File

@@ -2,7 +2,7 @@ query FindGalleries($filter: FindFilterType, $gallery_filter: GalleryFilterType)
findGalleries(gallery_filter: $gallery_filter, filter: $filter) { findGalleries(gallery_filter: $gallery_filter, filter: $filter) {
count count
galleries { galleries {
...GallerySlimData ...SlimGalleryData
} }
} }
} }

View File

@@ -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 { type multiCriterionHandlerBuilder struct {
primaryTable string primaryTable string
foreignTable string foreignTable string

View File

@@ -321,11 +321,17 @@ func (qb *galleryQueryBuilder) getMultiCriterionHandlerBuilder(foreignTable, joi
} }
func galleryTagsCriterionHandler(qb *galleryQueryBuilder, tags *models.MultiCriterionInput) criterionHandlerFunc { func galleryTagsCriterionHandler(qb *galleryQueryBuilder, tags *models.MultiCriterionInput) criterionHandlerFunc {
addJoinsFunc := func(f *filterBuilder) { 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") qb.tagsRepository().join(f, "tags_join", "galleries.id")
f.addJoin(tagTable, "", "tags_join.tag_id = tags.id") },
} }
h := qb.getMultiCriterionHandlerBuilder(tagTable, galleriesTagsTable, tagIDColumn, addJoinsFunc)
return h.handler(tags) return h.handler(tags)
} }
@@ -341,11 +347,17 @@ func galleryTagCountCriterionHandler(qb *galleryQueryBuilder, tagCount *models.I
} }
func galleryPerformersCriterionHandler(qb *galleryQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc { func galleryPerformersCriterionHandler(qb *galleryQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc {
addJoinsFunc := func(f *filterBuilder) { 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") qb.performersRepository().join(f, "performers_join", "galleries.id")
f.addJoin(performerTable, "", "performers_join.performer_id = performers.id") },
} }
h := qb.getMultiCriterionHandlerBuilder(performerTable, performersGalleriesTable, performerIDColumn, addJoinsFunc)
return h.handler(performers) return h.handler(performers)
} }

View File

@@ -347,11 +347,17 @@ func (qb *imageQueryBuilder) getMultiCriterionHandlerBuilder(foreignTable, joinT
} }
func imageTagsCriterionHandler(qb *imageQueryBuilder, tags *models.MultiCriterionInput) criterionHandlerFunc { func imageTagsCriterionHandler(qb *imageQueryBuilder, tags *models.MultiCriterionInput) criterionHandlerFunc {
addJoinsFunc := func(f *filterBuilder) { 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") qb.tagsRepository().join(f, "tags_join", "images.id")
f.addJoin(tagTable, "", "tags_join.tag_id = tags.id") },
} }
h := qb.getMultiCriterionHandlerBuilder(tagTable, imagesTagsTable, tagIDColumn, addJoinsFunc)
return h.handler(tags) return h.handler(tags)
} }
@@ -377,11 +383,17 @@ func imageGalleriesCriterionHandler(qb *imageQueryBuilder, galleries *models.Mul
} }
func imagePerformersCriterionHandler(qb *imageQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc { func imagePerformersCriterionHandler(qb *imageQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc {
addJoinsFunc := func(f *filterBuilder) { 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") qb.performersRepository().join(f, "performers_join", "images.id")
f.addJoin(performerTable, "", "performers_join.performer_id = performers.id") },
} }
h := qb.getMultiCriterionHandlerBuilder(performerTable, performersImagesTable, performerIDColumn, addJoinsFunc)
return h.handler(performers) return h.handler(performers)
} }

View File

@@ -562,11 +562,17 @@ func sceneTagCountCriterionHandler(qb *sceneQueryBuilder, tagCount *models.IntCr
} }
func scenePerformersCriterionHandler(qb *sceneQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc { func scenePerformersCriterionHandler(qb *sceneQueryBuilder, performers *models.MultiCriterionInput) criterionHandlerFunc {
addJoinsFunc := func(f *filterBuilder) { 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") qb.performersRepository().join(f, "performers_join", "scenes.id")
f.addJoin("performers", "", "performers_join.performer_id = performers.id") },
} }
h := qb.getMultiCriterionHandlerBuilder(performerTable, performersScenesTable, performerIDColumn, addJoinsFunc)
return h.handler(performers) return h.handler(performers)
} }

View File

@@ -10,7 +10,7 @@ import MultiSet from "../Shared/MultiSet";
import { RatingStars } from "../Scenes/SceneDetails/RatingStars"; import { RatingStars } from "../Scenes/SceneDetails/RatingStars";
interface IListOperationProps { interface IListOperationProps {
selected: GQL.GallerySlimDataFragment[]; selected: GQL.SlimGalleryDataFragment[];
onClose: (applied: boolean) => void; onClose: (applied: boolean) => void;
} }
@@ -146,7 +146,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
setIsUpdating(false); setIsUpdating(false);
} }
function getRating(state: GQL.GallerySlimDataFragment[]) { function getRating(state: GQL.SlimGalleryDataFragment[]) {
let ret: number | undefined; let ret: number | undefined;
let first = true; let first = true;
@@ -162,7 +162,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
return ret; return ret;
} }
function getStudioId(state: GQL.GallerySlimDataFragment[]) { function getStudioId(state: GQL.SlimGalleryDataFragment[]) {
let ret: string | undefined; let ret: string | undefined;
let first = true; let first = true;
@@ -181,7 +181,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
return ret; return ret;
} }
function getPerformerIds(state: GQL.GallerySlimDataFragment[]) { function getPerformerIds(state: GQL.SlimGalleryDataFragment[]) {
let ret: string[] = []; let ret: string[] = [];
let first = true; let first = true;
@@ -205,7 +205,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
return ret; return ret;
} }
function getTagIds(state: GQL.GallerySlimDataFragment[]) { function getTagIds(state: GQL.SlimGalleryDataFragment[]) {
let ret: string[] = []; let ret: string[] = [];
let first = true; let first = true;
@@ -234,7 +234,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
let updateOrganized: boolean | undefined; let updateOrganized: boolean | undefined;
let first = true; let first = true;
state.forEach((gallery: GQL.GallerySlimDataFragment) => { state.forEach((gallery: GQL.SlimGalleryDataFragment) => {
const galleryRating = gallery.rating; const galleryRating = gallery.rating;
const GalleriestudioID = gallery?.studio?.id; const GalleriestudioID = gallery?.studio?.id;
const galleryPerformerIDs = (gallery.performers ?? []) const galleryPerformerIDs = (gallery.performers ?? [])

View File

@@ -15,7 +15,7 @@ import { TextUtils } from "src/utils";
import { PerformerPopoverButton } from "../Shared/PerformerPopoverButton"; import { PerformerPopoverButton } from "../Shared/PerformerPopoverButton";
interface IProps { interface IProps {
gallery: GQL.GallerySlimDataFragment; gallery: GQL.SlimGalleryDataFragment;
selecting?: boolean; selecting?: boolean;
selected?: boolean | undefined; selected?: boolean | undefined;
zoomIndex?: number; zoomIndex?: number;

View File

@@ -3,7 +3,7 @@ import * as GQL from "src/core/generated-graphql";
import { SceneCard } from "src/components/Scenes/SceneCard"; import { SceneCard } from "src/components/Scenes/SceneCard";
interface IGalleryScenesPanelProps { interface IGalleryScenesPanelProps {
scenes: GQL.SceneDataFragment[]; scenes: GQL.SlimSceneDataFragment[];
} }
export const GalleryScenesPanel: React.FC<IGalleryScenesPanelProps> = ({ export const GalleryScenesPanel: React.FC<IGalleryScenesPanelProps> = ({

View File

@@ -5,7 +5,7 @@ import { Link, useHistory } from "react-router-dom";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { import {
FindGalleriesQueryResult, FindGalleriesQueryResult,
GallerySlimDataFragment, SlimGalleryDataFragment,
} from "src/core/generated-graphql"; } from "src/core/generated-graphql";
import { useGalleriesList } from "src/hooks"; import { useGalleriesList } from "src/hooks";
import { TextUtils } from "src/utils"; import { TextUtils } from "src/utils";
@@ -130,7 +130,7 @@ export const GalleryList: React.FC<IGalleryList> = ({
} }
function renderEditGalleriesDialog( function renderEditGalleriesDialog(
selectedImages: GallerySlimDataFragment[], selectedImages: SlimGalleryDataFragment[],
onClose: (applied: boolean) => void onClose: (applied: boolean) => void
) { ) {
return ( return (
@@ -141,7 +141,7 @@ export const GalleryList: React.FC<IGalleryList> = ({
} }
function renderDeleteGalleriesDialog( function renderDeleteGalleriesDialog(
selectedImages: GallerySlimDataFragment[], selectedImages: SlimGalleryDataFragment[],
onClose: (confirmed: boolean) => void onClose: (confirmed: boolean) => void
) { ) {
return ( return (

View File

@@ -12,7 +12,7 @@ const CLASSNAME_IMG = `${CLASSNAME}-img`;
const CLASSNAME_TITLE = `${CLASSNAME}-title`; const CLASSNAME_TITLE = `${CLASSNAME}-title`;
interface IProps { interface IProps {
gallery: GQL.GallerySlimDataFragment; gallery: GQL.SlimGalleryDataFragment;
} }
const GalleryWallCard: React.FC<IProps> = ({ gallery }) => { const GalleryWallCard: React.FC<IProps> = ({ gallery }) => {

View File

@@ -3,7 +3,7 @@ import * as GQL from "src/core/generated-graphql";
import { GalleryCard } from "src/components/Galleries/GalleryCard"; import { GalleryCard } from "src/components/Galleries/GalleryCard";
interface ISceneGalleriesPanelProps { interface ISceneGalleriesPanelProps {
galleries: GQL.GallerySlimDataFragment[]; galleries: GQL.SlimGalleryDataFragment[];
} }
export const SceneGalleriesPanel: React.FC<ISceneGalleriesPanelProps> = ({ export const SceneGalleriesPanel: React.FC<ISceneGalleriesPanelProps> = ({

View File

@@ -13,7 +13,7 @@ import Mousetrap from "mousetrap";
import { import {
SlimSceneDataFragment, SlimSceneDataFragment,
SceneMarkerDataFragment, SceneMarkerDataFragment,
GallerySlimDataFragment, SlimGalleryDataFragment,
StudioDataFragment, StudioDataFragment,
PerformerDataFragment, PerformerDataFragment,
FindScenesQueryResult, FindScenesQueryResult,
@@ -621,9 +621,9 @@ export const useImagesList = (
}); });
export const useGalleriesList = ( export const useGalleriesList = (
props: IListHookOptions<FindGalleriesQueryResult, GallerySlimDataFragment> props: IListHookOptions<FindGalleriesQueryResult, SlimGalleryDataFragment>
) => ) =>
useList<FindGalleriesQueryResult, GallerySlimDataFragment>({ useList<FindGalleriesQueryResult, SlimGalleryDataFragment>({
...props, ...props,
filterMode: FilterMode.Galleries, filterMode: FilterMode.Galleries,
useData: useFindGalleries, useData: useFindGalleries,