mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Handle NULL in regex criteria (#1208)
This commit is contained in:
@@ -311,13 +311,13 @@ func stringCriterionHandler(c *models.StringCriterionInput, column string) crite
|
|||||||
f.setError(err)
|
f.setError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.addWhere(column+" regexp ?", c.Value)
|
f.addWhere(fmt.Sprintf("(%s IS NOT NULL AND %[1]s regexp ?)", column), c.Value)
|
||||||
case models.CriterionModifierNotMatchesRegex:
|
case models.CriterionModifierNotMatchesRegex:
|
||||||
if _, err := regexp.Compile(c.Value); err != nil {
|
if _, err := regexp.Compile(c.Value); err != nil {
|
||||||
f.setError(err)
|
f.setError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.addWhere(column+" NOT regexp ?", c.Value)
|
f.addWhere(fmt.Sprintf("(%s IS NULL OR %[1]s NOT regexp ?)", column), c.Value)
|
||||||
default:
|
default:
|
||||||
clause, count := getSimpleCriterionClause(modifier, "?")
|
clause, count := getSimpleCriterionClause(modifier, "?")
|
||||||
|
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ func TestStringCriterionHandlerMatchesRegex(t *testing.T) {
|
|||||||
}, column))
|
}, column))
|
||||||
|
|
||||||
assert.Len(f.whereClauses, 1)
|
assert.Len(f.whereClauses, 1)
|
||||||
assert.Equal(fmt.Sprintf("%[1]s regexp ?", column), f.whereClauses[0].sql)
|
assert.Equal(fmt.Sprintf("(%s IS NOT NULL AND %[1]s regexp ?)", column), f.whereClauses[0].sql)
|
||||||
assert.Len(f.whereClauses[0].args, 1)
|
assert.Len(f.whereClauses[0].args, 1)
|
||||||
assert.Equal(validValue, f.whereClauses[0].args[0])
|
assert.Equal(validValue, f.whereClauses[0].args[0])
|
||||||
|
|
||||||
@@ -558,7 +558,7 @@ func TestStringCriterionHandlerNotMatchesRegex(t *testing.T) {
|
|||||||
}, column))
|
}, column))
|
||||||
|
|
||||||
assert.Len(f.whereClauses, 1)
|
assert.Len(f.whereClauses, 1)
|
||||||
assert.Equal(fmt.Sprintf("%[1]s NOT regexp ?", column), f.whereClauses[0].sql)
|
assert.Equal(fmt.Sprintf("(%s IS NULL OR %[1]s NOT regexp ?)", column), f.whereClauses[0].sql)
|
||||||
assert.Len(f.whereClauses[0].args, 1)
|
assert.Len(f.whereClauses[0].args, 1)
|
||||||
assert.Equal(validValue, f.whereClauses[0].args[0])
|
assert.Equal(validValue, f.whereClauses[0].args[0])
|
||||||
|
|
||||||
|
|||||||
@@ -228,6 +228,46 @@ func verifyPerformerAge(t *testing.T, ageCriterion models.IntCriterionInput) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPerformerQueryCareerLength(t *testing.T) {
|
||||||
|
const value = "2005"
|
||||||
|
careerLengthCriterion := models.StringCriterionInput{
|
||||||
|
Value: value,
|
||||||
|
Modifier: models.CriterionModifierEquals,
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyPerformerCareerLength(t, careerLengthCriterion)
|
||||||
|
|
||||||
|
careerLengthCriterion.Modifier = models.CriterionModifierNotEquals
|
||||||
|
verifyPerformerCareerLength(t, careerLengthCriterion)
|
||||||
|
|
||||||
|
careerLengthCriterion.Modifier = models.CriterionModifierMatchesRegex
|
||||||
|
verifyPerformerCareerLength(t, careerLengthCriterion)
|
||||||
|
|
||||||
|
careerLengthCriterion.Modifier = models.CriterionModifierNotMatchesRegex
|
||||||
|
verifyPerformerCareerLength(t, careerLengthCriterion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyPerformerCareerLength(t *testing.T, criterion models.StringCriterionInput) {
|
||||||
|
withTxn(func(r models.Repository) error {
|
||||||
|
qb := r.Performer()
|
||||||
|
performerFilter := models.PerformerFilterType{
|
||||||
|
CareerLength: &criterion,
|
||||||
|
}
|
||||||
|
|
||||||
|
performers, _, err := qb.Query(&performerFilter, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error querying performer: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, performer := range performers {
|
||||||
|
cl := performer.CareerLength
|
||||||
|
verifyNullString(t, cl, criterion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func queryPerformers(t *testing.T, qb models.PerformerReader, performerFilter *models.PerformerFilterType, findFilter *models.FindFilterType) []*models.Performer {
|
func queryPerformers(t *testing.T, qb models.PerformerReader, performerFilter *models.PerformerFilterType, findFilter *models.FindFilterType) []*models.Performer {
|
||||||
performers, _, err := qb.Query(performerFilter, findFilter)
|
performers, _, err := qb.Query(performerFilter, findFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlite
|
package sqlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
@@ -127,14 +128,14 @@ func (qb *queryBuilder) handleStringCriterionInput(c *models.StringCriterionInpu
|
|||||||
qb.err = err
|
qb.err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
qb.addWhere(column + " regexp ?")
|
qb.addWhere(fmt.Sprintf("(%s IS NOT NULL AND %[1]s regexp ?)", column))
|
||||||
qb.addArg(c.Value)
|
qb.addArg(c.Value)
|
||||||
case models.CriterionModifierNotMatchesRegex:
|
case models.CriterionModifierNotMatchesRegex:
|
||||||
if _, err := regexp.Compile(c.Value); err != nil {
|
if _, err := regexp.Compile(c.Value); err != nil {
|
||||||
qb.err = err
|
qb.err = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
qb.addWhere(column + " NOT regexp ?")
|
qb.addWhere(fmt.Sprintf("(%s IS NULL OR %[1]s NOT regexp ?)", column))
|
||||||
qb.addArg(c.Value)
|
qb.addArg(c.Value)
|
||||||
case models.CriterionModifierIsNull:
|
case models.CriterionModifierIsNull:
|
||||||
qb.addWhere("(" + column + " IS NULL OR TRIM(" + column + ") = '')")
|
qb.addWhere("(" + column + " IS NULL OR TRIM(" + column + ") = '')")
|
||||||
|
|||||||
@@ -356,6 +356,17 @@ func verifyNullString(t *testing.T, value sql.NullString, criterion models.Strin
|
|||||||
if criterion.Modifier == models.CriterionModifierNotEquals {
|
if criterion.Modifier == models.CriterionModifierNotEquals {
|
||||||
assert.NotEqual(criterion.Value, value.String)
|
assert.NotEqual(criterion.Value, value.String)
|
||||||
}
|
}
|
||||||
|
if criterion.Modifier == models.CriterionModifierMatchesRegex {
|
||||||
|
assert.True(value.Valid)
|
||||||
|
assert.Regexp(regexp.MustCompile(criterion.Value), value)
|
||||||
|
}
|
||||||
|
if criterion.Modifier == models.CriterionModifierNotMatchesRegex {
|
||||||
|
if !value.Valid {
|
||||||
|
// correct
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.NotRegexp(regexp.MustCompile(criterion.Value), value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyString(t *testing.T, value string, criterion models.StringCriterionInput) {
|
func verifyString(t *testing.T, value string, criterion models.StringCriterionInput) {
|
||||||
|
|||||||
@@ -587,6 +587,15 @@ func getPerformerBirthdate(index int) string {
|
|||||||
return birthdate.Format("2006-01-02")
|
return birthdate.Format("2006-01-02")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPerformerCareerLength(index int) *string {
|
||||||
|
if index%5 == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := fmt.Sprintf("20%2d", index)
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
//createPerformers creates n performers with plain Name and o performers with camel cased NaMe included
|
//createPerformers creates n performers with plain Name and o performers with camel cased NaMe included
|
||||||
func createPerformers(pqb models.PerformerReaderWriter, n int, o int) error {
|
func createPerformers(pqb models.PerformerReaderWriter, n int, o int) error {
|
||||||
const namePlain = "Name"
|
const namePlain = "Name"
|
||||||
@@ -613,6 +622,11 @@ func createPerformers(pqb models.PerformerReaderWriter, n int, o int) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
careerLength := getPerformerCareerLength(i)
|
||||||
|
if careerLength != nil {
|
||||||
|
performer.CareerLength = models.NullString(*careerLength)
|
||||||
|
}
|
||||||
|
|
||||||
created, err := pqb.Create(performer)
|
created, err := pqb.Create(performer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
* Added Rescan button to scene, image, gallery details overflow button.
|
* Added Rescan button to scene, image, gallery details overflow button.
|
||||||
|
|
||||||
### 🐛 Bug fixes
|
### 🐛 Bug fixes
|
||||||
|
* Fix SQL error when filtering nullable string fields with regex.
|
||||||
* Fix incorrect folders being excluded during scanning.
|
* Fix incorrect folders being excluded during scanning.
|
||||||
* Filter out streaming resolution options that are over the maximum streaming resolution.
|
* Filter out streaming resolution options that are over the maximum streaming resolution.
|
||||||
* Fix `cover.jpg` not being detected as cover image when in sub-directory.
|
* Fix `cover.jpg` not being detected as cover image when in sub-directory.
|
||||||
|
|||||||
Reference in New Issue
Block a user