Add AND, OR and NOT support to studio filter (#1726)

This commit is contained in:
gitgiggety 2021-09-16 04:09:23 +02:00 committed by GitHub
parent 23f852cd91
commit f3119a6c38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 186 additions and 1 deletions

View File

@ -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"""

View File

@ -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)

View File

@ -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)

View File

@ -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()