From 9ac65052415c24bfb99f34d0071e8e853bacc0a2 Mon Sep 17 00:00:00 2001 From: dogwithakeyboard <128322708+dogwithakeyboard@users.noreply.github.com> Date: Tue, 6 Feb 2024 02:24:00 +0000 Subject: [PATCH] Studio child filter and sort (#4479) --- graphql/schema/types/filters.graphql | 2 ++ pkg/models/studio.go | 2 ++ pkg/sqlite/sql.go | 2 +- pkg/sqlite/studio.go | 14 ++++++++++++++ ui/v2.5/src/locales/en-GB.json | 1 + ui/v2.5/src/models/list-filter/studios.ts | 8 ++++++++ 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index 8bcbfb4cc..0bc77e0ce 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -331,6 +331,8 @@ input StudioFilterType { url: StringCriterionInput "Filter by studio aliases" aliases: StringCriterionInput + "Filter by subsidiary studio count" + child_count: IntCriterionInput "Filter by autotag ignore value" ignore_auto_tag: Boolean "Filter by creation time" diff --git a/pkg/models/studio.go b/pkg/models/studio.go index 3b38cf409..2a54077ee 100644 --- a/pkg/models/studio.go +++ b/pkg/models/studio.go @@ -26,6 +26,8 @@ type StudioFilterType struct { URL *StringCriterionInput `json:"url"` // Filter by studio aliases Aliases *StringCriterionInput `json:"aliases"` + // Filter by subsidiary studio count + ChildCount *IntCriterionInput `json:"child_count"` // Filter by autotag ignore value IgnoreAutoTag *bool `json:"ignore_auto_tag"` // Filter by created at diff --git a/pkg/sqlite/sql.go b/pkg/sqlite/sql.go index 15ccf2ba4..38c59edc6 100644 --- a/pkg/sqlite/sql.go +++ b/pkg/sqlite/sql.go @@ -107,7 +107,7 @@ func getRandomSort(tableName string, direction string, seed uint64) string { } func getCountSort(primaryTable, joinTable, primaryFK, direction string) string { - return fmt.Sprintf(" ORDER BY (SELECT COUNT(*) FROM %s WHERE %s = %s.id) %s", joinTable, primaryFK, primaryTable, getSortDirection(direction)) + return fmt.Sprintf(" ORDER BY (SELECT COUNT(*) FROM %s AS sort WHERE sort.%s = %s.id) %s", joinTable, primaryFK, primaryTable, getSortDirection(direction)) } func getMultiSumSort(sum string, primaryTable, foreignTable1, joinTable1, foreignTable2, joinTable2, primaryFK, foreignFK1, foreignFK2, direction string) string { diff --git a/pkg/sqlite/studio.go b/pkg/sqlite/studio.go index 51f65d973..6df618ca1 100644 --- a/pkg/sqlite/studio.go +++ b/pkg/sqlite/studio.go @@ -517,6 +517,7 @@ func (qb *StudioStore) makeFilter(ctx context.Context, studioFilter *models.Stud query.handleCriterion(ctx, studioGalleryCountCriterionHandler(qb, studioFilter.GalleryCount)) query.handleCriterion(ctx, studioParentCriterionHandler(qb, studioFilter.Parents)) query.handleCriterion(ctx, studioAliasCriterionHandler(qb, studioFilter.Aliases)) + query.handleCriterion(ctx, studioChildCountCriterionHandler(qb, studioFilter.ChildCount)) query.handleCriterion(ctx, timestampCriterionHandler(studioFilter.CreatedAt, studioTable+".created_at")) query.handleCriterion(ctx, timestampCriterionHandler(studioFilter.UpdatedAt, studioTable+".updated_at")) @@ -649,6 +650,17 @@ func studioAliasCriterionHandler(qb *StudioStore, alias *models.StringCriterionI return h.handler(alias) } +func studioChildCountCriterionHandler(qb *StudioStore, childCount *models.IntCriterionInput) criterionHandlerFunc { + return func(ctx context.Context, f *filterBuilder) { + if childCount != nil { + f.addLeftJoin("studios", "children_count", "children_count.parent_id = studios.id") + clause, args := getIntCriterionWhereClause("count(distinct children_count.id)", *childCount) + + f.addHaving(clause, args...) + } + } +} + func (qb *StudioStore) getStudioSort(findFilter *models.FindFilterType) string { var sort string var direction string @@ -668,6 +680,8 @@ func (qb *StudioStore) getStudioSort(findFilter *models.FindFilterType) string { sortQuery += getCountSort(studioTable, imageTable, studioIDColumn, direction) case "galleries_count": sortQuery += getCountSort(studioTable, galleryTable, studioIDColumn, direction) + case "child_count": + sortQuery += getCountSort(studioTable, studioTable, studioParentIDColumn, direction) default: sortQuery += getSort(sort, direction, "studios") } diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index 1bc353523..01ba83332 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -1363,6 +1363,7 @@ "sub_tag_count": "Sub-Tag Count", "sub_tag_of": "Sub-tag of {parent}", "sub_tags": "Sub-Tags", + "subsidiary_studio_count": "Subsidiary Studio Count", "subsidiary_studios": "Subsidiary Studios", "synopsis": "Synopsis", "tag": "Tag", diff --git a/ui/v2.5/src/models/list-filter/studios.ts b/ui/v2.5/src/models/list-filter/studios.ts index e5e70aeec..c00a86c15 100644 --- a/ui/v2.5/src/models/list-filter/studios.ts +++ b/ui/v2.5/src/models/list-filter/studios.ts @@ -28,6 +28,10 @@ const sortByOptions = ["name", "random", "rating"] messageID: "scene_count", value: "scenes_count", }, + { + messageID: "subsidiary_studio_count", + value: "child_count", + }, ]); const displayModeOptions = [DisplayMode.Grid, DisplayMode.Tagger]; @@ -44,6 +48,10 @@ const criterionOptions = [ createStringCriterionOption("url"), StashIDCriterionOption, createStringCriterionOption("aliases"), + createMandatoryNumberCriterionOption( + "child_count", + "subsidiary_studio_count" + ), createMandatoryTimestampCriterionOption("created_at"), createMandatoryTimestampCriterionOption("updated_at"), ];