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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(studios.Value) == 0 {
|
if len(studios.Value) == 0 && len(studios.Excludes) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,27 +464,54 @@ func (qb *performerFilterHandler) studiosCriterionHandler(studios *models.Hierar
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const derivedPerformerStudioTable = "performer_studio"
|
if len(studios.Value) > 0 {
|
||||||
valuesClause, err := getHierarchicalValues(ctx, studios.Value, studioTable, "", "parent_id", "child_id", studios.Depth)
|
const derivedPerformerStudioTable = "performer_studio"
|
||||||
if err != nil {
|
valuesClause, err := getHierarchicalValues(ctx, studios.Value, studioTable, "", "parent_id", "child_id", studios.Depth)
|
||||||
f.setError(err)
|
if err != nil {
|
||||||
return
|
f.setError(err)
|
||||||
}
|
return
|
||||||
f.addWith("studio(root_id, item_id) AS (" + valuesClause + ")")
|
}
|
||||||
|
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 {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
|
var unions []string
|
||||||
for _, c := range formatMaps {
|
for _, c := range formatMaps {
|
||||||
unions = append(unions, utils.StrFormat(templStr, c))
|
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},
|
[]int{performerIdx1WithScene, performerIdxWithScene},
|
||||||
false,
|
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 {
|
for _, tt := range tests {
|
||||||
@@ -2260,7 +2352,7 @@ func TestPerformerQuerySortScenesCount(t *testing.T) {
|
|||||||
assert.True(t, len(performers) > 0)
|
assert.True(t, len(performers) > 0)
|
||||||
lastPerformer := performers[len(performers)-1]
|
lastPerformer := performers[len(performers)-1]
|
||||||
|
|
||||||
assert.Equal(t, performerIDs[performerIdxWithTag], lastPerformer.ID)
|
assert.Equal(t, performerIDs[performerIdxWithTwoSceneStudio], lastPerformer.ID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ const (
|
|||||||
sceneIdxWithPerformerTwoTags
|
sceneIdxWithPerformerTwoTags
|
||||||
sceneIdxWithSpacedName
|
sceneIdxWithSpacedName
|
||||||
sceneIdxWithStudioPerformer
|
sceneIdxWithStudioPerformer
|
||||||
|
sceneIdx1WithTwoStudioPerformer
|
||||||
|
sceneIdx2WithTwoStudioPerformer
|
||||||
sceneIdxWithGrandChildStudio
|
sceneIdxWithGrandChildStudio
|
||||||
sceneIdxMissingPhash
|
sceneIdxMissingPhash
|
||||||
sceneIdxWithPerformerParentTag
|
sceneIdxWithPerformerParentTag
|
||||||
@@ -138,6 +140,7 @@ const (
|
|||||||
performerIdxWithSceneStudio
|
performerIdxWithSceneStudio
|
||||||
performerIdxWithImageStudio
|
performerIdxWithImageStudio
|
||||||
performerIdxWithGalleryStudio
|
performerIdxWithGalleryStudio
|
||||||
|
performerIdxWithTwoSceneStudio
|
||||||
performerIdxWithParentTag
|
performerIdxWithParentTag
|
||||||
// new indexes above
|
// new indexes above
|
||||||
// performers with dup names start from the end
|
// performers with dup names start from the end
|
||||||
@@ -257,6 +260,8 @@ const (
|
|||||||
studioIdxWithScenePerformer
|
studioIdxWithScenePerformer
|
||||||
studioIdxWithImagePerformer
|
studioIdxWithImagePerformer
|
||||||
studioIdxWithGalleryPerformer
|
studioIdxWithGalleryPerformer
|
||||||
|
studioIdx1WithTwoScenePerformer
|
||||||
|
studioIdx2WithTwoScenePerformer
|
||||||
studioIdxWithTag
|
studioIdxWithTag
|
||||||
studioIdx2WithTag
|
studioIdx2WithTag
|
||||||
studioIdxWithTwoTags
|
studioIdxWithTwoTags
|
||||||
@@ -384,16 +389,18 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
scenePerformers = linkMap{
|
scenePerformers = linkMap{
|
||||||
sceneIdxWithPerformer: {performerIdxWithScene},
|
sceneIdxWithPerformer: {performerIdxWithScene},
|
||||||
sceneIdxWithTwoPerformers: {performerIdx1WithScene, performerIdx2WithScene},
|
sceneIdxWithTwoPerformers: {performerIdx1WithScene, performerIdx2WithScene},
|
||||||
sceneIdxWithThreePerformers: {performerIdx1WithScene, performerIdx2WithScene, performerIdx3WithScene},
|
sceneIdxWithThreePerformers: {performerIdx1WithScene, performerIdx2WithScene, performerIdx3WithScene},
|
||||||
sceneIdxWithPerformerTag: {performerIdxWithTag},
|
sceneIdxWithPerformerTag: {performerIdxWithTag},
|
||||||
sceneIdxWithTwoPerformerTag: {performerIdxWithTag, performerIdx2WithTag},
|
sceneIdxWithTwoPerformerTag: {performerIdxWithTag, performerIdx2WithTag},
|
||||||
sceneIdxWithPerformerTwoTags: {performerIdxWithTwoTags},
|
sceneIdxWithPerformerTwoTags: {performerIdxWithTwoTags},
|
||||||
sceneIdx1WithPerformer: {performerIdxWithTwoScenes},
|
sceneIdx1WithPerformer: {performerIdxWithTwoScenes},
|
||||||
sceneIdx2WithPerformer: {performerIdxWithTwoScenes},
|
sceneIdx2WithPerformer: {performerIdxWithTwoScenes},
|
||||||
sceneIdxWithStudioPerformer: {performerIdxWithSceneStudio},
|
sceneIdxWithStudioPerformer: {performerIdxWithSceneStudio},
|
||||||
sceneIdxWithPerformerParentTag: {performerIdxWithParentTag},
|
sceneIdx1WithTwoStudioPerformer: {performerIdxWithTwoSceneStudio},
|
||||||
|
sceneIdx2WithTwoStudioPerformer: {performerIdxWithTwoSceneStudio},
|
||||||
|
sceneIdxWithPerformerParentTag: {performerIdxWithParentTag},
|
||||||
}
|
}
|
||||||
|
|
||||||
sceneGalleries = linkMap{
|
sceneGalleries = linkMap{
|
||||||
@@ -406,11 +413,13 @@ var (
|
|||||||
}
|
}
|
||||||
|
|
||||||
sceneStudios = map[int]int{
|
sceneStudios = map[int]int{
|
||||||
sceneIdxWithStudio: studioIdxWithScene,
|
sceneIdxWithStudio: studioIdxWithScene,
|
||||||
sceneIdx1WithStudio: studioIdxWithTwoScenes,
|
sceneIdx1WithStudio: studioIdxWithTwoScenes,
|
||||||
sceneIdx2WithStudio: studioIdxWithTwoScenes,
|
sceneIdx2WithStudio: studioIdxWithTwoScenes,
|
||||||
sceneIdxWithStudioPerformer: studioIdxWithScenePerformer,
|
sceneIdxWithStudioPerformer: studioIdxWithScenePerformer,
|
||||||
sceneIdxWithGrandChildStudio: studioIdxWithGrandParent,
|
sceneIdx1WithTwoStudioPerformer: studioIdx1WithTwoScenePerformer,
|
||||||
|
sceneIdx2WithTwoStudioPerformer: studioIdx2WithTwoScenePerformer,
|
||||||
|
sceneIdxWithGrandChildStudio: studioIdxWithGrandParent,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user