mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 20:07:05 +03:00
Fix excludes handling in performer studio filter (#6413)
This commit is contained in:
@@ -447,7 +447,7 @@ func (qb *performerFilterHandler) studiosCriterionHandler(studios *models.Hierar
|
||||
return
|
||||
}
|
||||
|
||||
if len(studios.Value) == 0 {
|
||||
if len(studios.Value) == 0 && len(studios.Excludes) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -464,27 +464,54 @@ func (qb *performerFilterHandler) studiosCriterionHandler(studios *models.Hierar
|
||||
return
|
||||
}
|
||||
|
||||
const derivedPerformerStudioTable = "performer_studio"
|
||||
valuesClause, err := getHierarchicalValues(ctx, studios.Value, studioTable, "", "parent_id", "child_id", studios.Depth)
|
||||
if err != nil {
|
||||
f.setError(err)
|
||||
return
|
||||
}
|
||||
f.addWith("studio(root_id, item_id) AS (" + valuesClause + ")")
|
||||
if len(studios.Value) > 0 {
|
||||
const derivedPerformerStudioTable = "performer_studio"
|
||||
valuesClause, err := getHierarchicalValues(ctx, studios.Value, studioTable, "", "parent_id", "child_id", studios.Depth)
|
||||
if err != nil {
|
||||
f.setError(err)
|
||||
return
|
||||
}
|
||||
f.addWith("studio(root_id, item_id) AS (" + valuesClause + ")")
|
||||
|
||||
templStr := `SELECT performer_id FROM {primaryTable}
|
||||
templStr := `SELECT performer_id FROM {primaryTable}
|
||||
INNER JOIN {joinTable} ON {primaryTable}.id = {joinTable}.{primaryFK}
|
||||
INNER JOIN studio ON {primaryTable}.studio_id = studio.item_id`
|
||||
|
||||
var unions []string
|
||||
for _, c := range formatMaps {
|
||||
unions = append(unions, utils.StrFormat(templStr, c))
|
||||
}
|
||||
|
||||
f.addWith(fmt.Sprintf("%s AS (%s)", derivedPerformerStudioTable, strings.Join(unions, " UNION ")))
|
||||
|
||||
f.addLeftJoin(derivedPerformerStudioTable, "", fmt.Sprintf("performers.id = %s.performer_id", derivedPerformerStudioTable))
|
||||
f.addWhere(fmt.Sprintf("%s.performer_id IS %s NULL", derivedPerformerStudioTable, clauseCondition))
|
||||
}
|
||||
|
||||
// #6412 - handle excludes as well
|
||||
if len(studios.Excludes) > 0 {
|
||||
excludeValuesClause, err := getHierarchicalValues(ctx, studios.Excludes, studioTable, "", "parent_id", "child_id", studios.Depth)
|
||||
if err != nil {
|
||||
f.setError(err)
|
||||
return
|
||||
}
|
||||
f.addWith("exclude_studio(root_id, item_id) AS (" + excludeValuesClause + ")")
|
||||
|
||||
excludeTemplStr := `SELECT performer_id FROM {primaryTable}
|
||||
INNER JOIN {joinTable} ON {primaryTable}.id = {joinTable}.{primaryFK}
|
||||
INNER JOIN studio ON {primaryTable}.studio_id = studio.item_id`
|
||||
INNER JOIN exclude_studio ON {primaryTable}.studio_id = exclude_studio.item_id`
|
||||
|
||||
var unions []string
|
||||
for _, c := range formatMaps {
|
||||
unions = append(unions, utils.StrFormat(templStr, c))
|
||||
var unions []string
|
||||
for _, c := range formatMaps {
|
||||
unions = append(unions, utils.StrFormat(excludeTemplStr, c))
|
||||
}
|
||||
|
||||
const excludePerformerStudioTable = "performer_studio_exclude"
|
||||
f.addWith(fmt.Sprintf("%s AS (%s)", excludePerformerStudioTable, strings.Join(unions, " UNION ")))
|
||||
|
||||
f.addLeftJoin(excludePerformerStudioTable, "", fmt.Sprintf("performers.id = %s.performer_id", excludePerformerStudioTable))
|
||||
f.addWhere(fmt.Sprintf("%s.performer_id IS NULL", excludePerformerStudioTable))
|
||||
}
|
||||
|
||||
f.addWith(fmt.Sprintf("%s AS (%s)", derivedPerformerStudioTable, strings.Join(unions, " UNION ")))
|
||||
|
||||
f.addLeftJoin(derivedPerformerStudioTable, "", fmt.Sprintf("performers.id = %s.performer_id", derivedPerformerStudioTable))
|
||||
f.addWhere(fmt.Sprintf("%s.performer_id IS %s NULL", derivedPerformerStudioTable, clauseCondition))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1160,6 +1160,98 @@ func TestPerformerQuery(t *testing.T) {
|
||||
[]int{performerIdx1WithScene, performerIdxWithScene},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"include scene studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdxWithScenePerformer])},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
},
|
||||
},
|
||||
[]int{performerIdxWithSceneStudio},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"include image studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdxWithImagePerformer])},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
},
|
||||
},
|
||||
[]int{performerIdxWithImageStudio},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"include gallery studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdxWithGalleryPerformer])},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
},
|
||||
},
|
||||
[]int{performerIdxWithGalleryStudio},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude scene studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdxWithScenePerformer])},
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{performerIdxWithSceneStudio},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude image studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdxWithImagePerformer])},
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{performerIdxWithImageStudio},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude gallery studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdxWithGalleryPerformer])},
|
||||
Modifier: models.CriterionModifierExcludes,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{performerIdxWithGalleryStudio},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"include and exclude scene studio",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
Studios: &models.HierarchicalMultiCriterionInput{
|
||||
Value: []string{strconv.Itoa(studioIDs[studioIdx1WithTwoScenePerformer])},
|
||||
Modifier: models.CriterionModifierIncludes,
|
||||
Excludes: []string{strconv.Itoa(studioIDs[studioIdx2WithTwoScenePerformer])},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{performerIdxWithTwoSceneStudio},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -2260,7 +2352,7 @@ func TestPerformerQuerySortScenesCount(t *testing.T) {
|
||||
assert.True(t, len(performers) > 0)
|
||||
lastPerformer := performers[len(performers)-1]
|
||||
|
||||
assert.Equal(t, performerIDs[performerIdxWithTag], lastPerformer.ID)
|
||||
assert.Equal(t, performerIDs[performerIdxWithTwoSceneStudio], lastPerformer.ID)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -77,6 +77,8 @@ const (
|
||||
sceneIdxWithPerformerTwoTags
|
||||
sceneIdxWithSpacedName
|
||||
sceneIdxWithStudioPerformer
|
||||
sceneIdx1WithTwoStudioPerformer
|
||||
sceneIdx2WithTwoStudioPerformer
|
||||
sceneIdxWithGrandChildStudio
|
||||
sceneIdxMissingPhash
|
||||
sceneIdxWithPerformerParentTag
|
||||
@@ -138,6 +140,7 @@ const (
|
||||
performerIdxWithSceneStudio
|
||||
performerIdxWithImageStudio
|
||||
performerIdxWithGalleryStudio
|
||||
performerIdxWithTwoSceneStudio
|
||||
performerIdxWithParentTag
|
||||
// new indexes above
|
||||
// performers with dup names start from the end
|
||||
@@ -257,6 +260,8 @@ const (
|
||||
studioIdxWithScenePerformer
|
||||
studioIdxWithImagePerformer
|
||||
studioIdxWithGalleryPerformer
|
||||
studioIdx1WithTwoScenePerformer
|
||||
studioIdx2WithTwoScenePerformer
|
||||
studioIdxWithTag
|
||||
studioIdx2WithTag
|
||||
studioIdxWithTwoTags
|
||||
@@ -384,16 +389,18 @@ var (
|
||||
}
|
||||
|
||||
scenePerformers = linkMap{
|
||||
sceneIdxWithPerformer: {performerIdxWithScene},
|
||||
sceneIdxWithTwoPerformers: {performerIdx1WithScene, performerIdx2WithScene},
|
||||
sceneIdxWithThreePerformers: {performerIdx1WithScene, performerIdx2WithScene, performerIdx3WithScene},
|
||||
sceneIdxWithPerformerTag: {performerIdxWithTag},
|
||||
sceneIdxWithTwoPerformerTag: {performerIdxWithTag, performerIdx2WithTag},
|
||||
sceneIdxWithPerformerTwoTags: {performerIdxWithTwoTags},
|
||||
sceneIdx1WithPerformer: {performerIdxWithTwoScenes},
|
||||
sceneIdx2WithPerformer: {performerIdxWithTwoScenes},
|
||||
sceneIdxWithStudioPerformer: {performerIdxWithSceneStudio},
|
||||
sceneIdxWithPerformerParentTag: {performerIdxWithParentTag},
|
||||
sceneIdxWithPerformer: {performerIdxWithScene},
|
||||
sceneIdxWithTwoPerformers: {performerIdx1WithScene, performerIdx2WithScene},
|
||||
sceneIdxWithThreePerformers: {performerIdx1WithScene, performerIdx2WithScene, performerIdx3WithScene},
|
||||
sceneIdxWithPerformerTag: {performerIdxWithTag},
|
||||
sceneIdxWithTwoPerformerTag: {performerIdxWithTag, performerIdx2WithTag},
|
||||
sceneIdxWithPerformerTwoTags: {performerIdxWithTwoTags},
|
||||
sceneIdx1WithPerformer: {performerIdxWithTwoScenes},
|
||||
sceneIdx2WithPerformer: {performerIdxWithTwoScenes},
|
||||
sceneIdxWithStudioPerformer: {performerIdxWithSceneStudio},
|
||||
sceneIdx1WithTwoStudioPerformer: {performerIdxWithTwoSceneStudio},
|
||||
sceneIdx2WithTwoStudioPerformer: {performerIdxWithTwoSceneStudio},
|
||||
sceneIdxWithPerformerParentTag: {performerIdxWithParentTag},
|
||||
}
|
||||
|
||||
sceneGalleries = linkMap{
|
||||
@@ -406,11 +413,13 @@ var (
|
||||
}
|
||||
|
||||
sceneStudios = map[int]int{
|
||||
sceneIdxWithStudio: studioIdxWithScene,
|
||||
sceneIdx1WithStudio: studioIdxWithTwoScenes,
|
||||
sceneIdx2WithStudio: studioIdxWithTwoScenes,
|
||||
sceneIdxWithStudioPerformer: studioIdxWithScenePerformer,
|
||||
sceneIdxWithGrandChildStudio: studioIdxWithGrandParent,
|
||||
sceneIdxWithStudio: studioIdxWithScene,
|
||||
sceneIdx1WithStudio: studioIdxWithTwoScenes,
|
||||
sceneIdx2WithStudio: studioIdxWithTwoScenes,
|
||||
sceneIdxWithStudioPerformer: studioIdxWithScenePerformer,
|
||||
sceneIdx1WithTwoStudioPerformer: studioIdx1WithTwoScenePerformer,
|
||||
sceneIdx2WithTwoStudioPerformer: studioIdx2WithTwoScenePerformer,
|
||||
sceneIdxWithGrandChildStudio: studioIdxWithGrandParent,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user