mirror of https://github.com/stashapp/stash.git
Add AND, OR and NOT support to studio filter (#1726)
This commit is contained in:
parent
23f852cd91
commit
f3119a6c38
|
@ -181,6 +181,10 @@ input MovieFilterType {
|
|||
}
|
||||
|
||||
input StudioFilterType {
|
||||
AND: StudioFilterType
|
||||
OR: StudioFilterType
|
||||
NOT: StudioFilterType
|
||||
|
||||
name: StringCriterionInput
|
||||
details: StringCriterionInput
|
||||
"""Filter to only include studios with this parent studio"""
|
||||
|
|
|
@ -165,7 +165,7 @@ func TestPerformerQueryEthnicityAndRating(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestPerformerQueryPathNotRating(t *testing.T) {
|
||||
func TestPerformerQueryEthnicityNotRating(t *testing.T) {
|
||||
const performerIdx = 1
|
||||
|
||||
performerRating := getRating(performerIdx)
|
||||
|
|
|
@ -147,9 +147,50 @@ func (qb *studioQueryBuilder) QueryForAutoTag(words []string) ([]*models.Studio,
|
|||
return qb.queryStudios(query+" WHERE "+where, args)
|
||||
}
|
||||
|
||||
func (qb *studioQueryBuilder) validateFilter(filter *models.StudioFilterType) error {
|
||||
const and = "AND"
|
||||
const or = "OR"
|
||||
const not = "NOT"
|
||||
|
||||
if filter.And != nil {
|
||||
if filter.Or != nil {
|
||||
return illegalFilterCombination(and, or)
|
||||
}
|
||||
if filter.Not != nil {
|
||||
return illegalFilterCombination(and, not)
|
||||
}
|
||||
|
||||
return qb.validateFilter(filter.And)
|
||||
}
|
||||
|
||||
if filter.Or != nil {
|
||||
if filter.Not != nil {
|
||||
return illegalFilterCombination(or, not)
|
||||
}
|
||||
|
||||
return qb.validateFilter(filter.Or)
|
||||
}
|
||||
|
||||
if filter.Not != nil {
|
||||
return qb.validateFilter(filter.Not)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qb *studioQueryBuilder) makeFilter(studioFilter *models.StudioFilterType) *filterBuilder {
|
||||
query := &filterBuilder{}
|
||||
|
||||
if studioFilter.And != nil {
|
||||
query.and(qb.makeFilter(studioFilter.And))
|
||||
}
|
||||
if studioFilter.Or != nil {
|
||||
query.or(qb.makeFilter(studioFilter.Or))
|
||||
}
|
||||
if studioFilter.Not != nil {
|
||||
query.not(qb.makeFilter(studioFilter.Not))
|
||||
}
|
||||
|
||||
query.handleCriterion(stringCriterionHandler(studioFilter.Name, studioTable+".name"))
|
||||
query.handleCriterion(stringCriterionHandler(studioFilter.Details, studioTable+".details"))
|
||||
query.handleCriterion(stringCriterionHandler(studioFilter.URL, studioTable+".url"))
|
||||
|
@ -193,6 +234,9 @@ func (qb *studioQueryBuilder) Query(studioFilter *models.StudioFilterType, findF
|
|||
query.addArg(thisArgs...)
|
||||
}
|
||||
|
||||
if err := qb.validateFilter(studioFilter); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
filter := qb.makeFilter(studioFilter)
|
||||
|
||||
query.addFilter(filter)
|
||||
|
|
|
@ -46,6 +46,143 @@ func TestStudioFindByName(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestStudioQueryNameOr(t *testing.T) {
|
||||
const studio1Idx = 1
|
||||
const studio2Idx = 2
|
||||
|
||||
studio1Name := getStudioStringValue(studio1Idx, "Name")
|
||||
studio2Name := getStudioStringValue(studio2Idx, "Name")
|
||||
|
||||
studioFilter := models.StudioFilterType{
|
||||
Name: &models.StringCriterionInput{
|
||||
Value: studio1Name,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
Or: &models.StudioFilterType{
|
||||
Name: &models.StringCriterionInput{
|
||||
Value: studio2Name,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
withTxn(func(r models.Repository) error {
|
||||
sqb := r.Studio()
|
||||
|
||||
studios := queryStudio(t, sqb, &studioFilter, nil)
|
||||
|
||||
assert.Len(t, studios, 2)
|
||||
assert.Equal(t, studio1Name, studios[0].Name.String)
|
||||
assert.Equal(t, studio2Name, studios[1].Name.String)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestStudioQueryNameAndUrl(t *testing.T) {
|
||||
const studioIdx = 1
|
||||
studioName := getStudioStringValue(studioIdx, "Name")
|
||||
studioUrl := getStudioNullStringValue(studioIdx, urlField)
|
||||
|
||||
studioFilter := models.StudioFilterType{
|
||||
Name: &models.StringCriterionInput{
|
||||
Value: studioName,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
And: &models.StudioFilterType{
|
||||
URL: &models.StringCriterionInput{
|
||||
Value: studioUrl.String,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
withTxn(func(r models.Repository) error {
|
||||
sqb := r.Studio()
|
||||
|
||||
studios := queryStudio(t, sqb, &studioFilter, nil)
|
||||
|
||||
assert.Len(t, studios, 1)
|
||||
assert.Equal(t, studioName, studios[0].Name.String)
|
||||
assert.Equal(t, studioUrl.String, studios[0].URL.String)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestStudioQueryNameNotUrl(t *testing.T) {
|
||||
const studioIdx = 1
|
||||
|
||||
studioUrl := getStudioNullStringValue(studioIdx, urlField)
|
||||
|
||||
nameCriterion := models.StringCriterionInput{
|
||||
Value: "studio_.*1_Name",
|
||||
Modifier: models.CriterionModifierMatchesRegex,
|
||||
}
|
||||
|
||||
urlCriterion := models.StringCriterionInput{
|
||||
Value: studioUrl.String,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
}
|
||||
|
||||
studioFilter := models.StudioFilterType{
|
||||
Name: &nameCriterion,
|
||||
Not: &models.StudioFilterType{
|
||||
URL: &urlCriterion,
|
||||
},
|
||||
}
|
||||
|
||||
withTxn(func(r models.Repository) error {
|
||||
sqb := r.Studio()
|
||||
|
||||
studios := queryStudio(t, sqb, &studioFilter, nil)
|
||||
|
||||
for _, studio := range studios {
|
||||
verifyString(t, studio.Name.String, nameCriterion)
|
||||
urlCriterion.Modifier = models.CriterionModifierNotEquals
|
||||
verifyNullString(t, studio.URL, urlCriterion)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestStudioIllegalQuery(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
const studioIdx = 1
|
||||
subFilter := models.StudioFilterType{
|
||||
Name: &models.StringCriterionInput{
|
||||
Value: getStudioStringValue(studioIdx, "Name"),
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
}
|
||||
|
||||
studioFilter := &models.StudioFilterType{
|
||||
And: &subFilter,
|
||||
Or: &subFilter,
|
||||
}
|
||||
|
||||
withTxn(func(r models.Repository) error {
|
||||
sqb := r.Studio()
|
||||
|
||||
_, _, err := sqb.Query(studioFilter, nil)
|
||||
assert.NotNil(err)
|
||||
|
||||
studioFilter.Or = nil
|
||||
studioFilter.Not = &subFilter
|
||||
_, _, err = sqb.Query(studioFilter, nil)
|
||||
assert.NotNil(err)
|
||||
|
||||
studioFilter.And = nil
|
||||
studioFilter.Or = &subFilter
|
||||
_, _, err = sqb.Query(studioFilter, nil)
|
||||
assert.NotNil(err)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestStudioQueryForAutoTag(t *testing.T) {
|
||||
withTxn(func(r models.Repository) error {
|
||||
tqb := r.Studio()
|
||||
|
|
Loading…
Reference in New Issue