Filter improvement exploration

Changed the rating filter to allow for more than just an equality check.  This progresses #29.
This commit is contained in:
Stash Dev
2019-03-24 15:11:58 -07:00
parent c1f1a6ccff
commit b1db98bd1f
22 changed files with 339 additions and 54 deletions

View File

@@ -10858,6 +10858,35 @@ func (e *executableSchema) GenerateMetadataInputMiddleware(ctx context.Context,
return obj, nil
}
func UnmarshalIntCriterionInput(v interface{}) (IntCriterionInput, error) {
var it IntCriterionInput
var asMap = v.(map[string]interface{})
for k, v := range asMap {
switch k {
case "value":
var err error
it.Value, err = graphql.UnmarshalInt(v)
if err != nil {
return it, err
}
case "modifier":
var err error
err = (&it.Modifier).UnmarshalGQL(v)
if err != nil {
return it, err
}
}
}
return it, nil
}
func (e *executableSchema) IntCriterionInputMiddleware(ctx context.Context, obj *IntCriterionInput) (*IntCriterionInput, error) {
return obj, nil
}
func UnmarshalPerformerCreateInput(v interface{}) (PerformerCreateInput, error) {
var it PerformerCreateInput
var asMap = v.(map[string]interface{})
@@ -11303,9 +11332,9 @@ func UnmarshalSceneFilterType(v interface{}) (SceneFilterType, error) {
switch k {
case "rating":
var err error
var ptr1 int
var ptr1 IntCriterionInput
if v != nil {
ptr1, err = graphql.UnmarshalInt(v)
ptr1, err = UnmarshalIntCriterionInput(v)
it.Rating = &ptr1
}
@@ -11392,6 +11421,14 @@ func UnmarshalSceneFilterType(v interface{}) (SceneFilterType, error) {
func (e *executableSchema) SceneFilterTypeMiddleware(ctx context.Context, obj *SceneFilterType) (*SceneFilterType, error) {
if obj.Rating != nil {
var err error
obj.Rating, err = e.IntCriterionInputMiddleware(ctx, obj.Rating)
if err != nil {
return nil, err
}
}
return obj, nil
}
@@ -12301,7 +12338,7 @@ input SceneMarkerFilterType {
input SceneFilterType {
"""Filter by rating"""
rating: Int
rating: IntCriterionInput
"""Filter by resolution"""
resolution: ResolutionEnum
"""Filter to only include scenes which have markers. ` + "`" + `true` + "`" + ` or ` + "`" + `false` + "`" + `"""
@@ -12316,6 +12353,28 @@ input SceneFilterType {
performer_id: ID
}
enum CriterionModifier {
"""="""
EQUALS,
"""!="""
NOT_EQUALS,
""">"""
GREATER_THAN,
"""<"""
LESS_THAN,
"""IS NULL"""
IS_NULL,
"""IS NOT NULL"""
NOT_NULL,
INCLUDES,
EXCLUDES,
}
input IntCriterionInput {
value: Int!
modifier: CriterionModifier!
}
#######################################
# Config
#######################################

View File

@@ -77,6 +77,11 @@ type GenerateMetadataInput struct {
Transcodes bool `json:"transcodes"`
}
type IntCriterionInput struct {
Value int `json:"value"`
Modifier CriterionModifier `json:"modifier"`
}
type MarkerStringsResultType struct {
Count int `json:"count"`
ID string `json:"id"`
@@ -144,7 +149,7 @@ type SceneFileType struct {
type SceneFilterType struct {
// Filter by rating
Rating *int `json:"rating"`
Rating *IntCriterionInput `json:"rating"`
// Filter by resolution
Resolution *ResolutionEnum `json:"resolution"`
// Filter to only include scenes which have markers. `true` or `false`
@@ -270,6 +275,65 @@ type TagUpdateInput struct {
Name string `json:"name"`
}
type CriterionModifier string
const (
// =
CriterionModifierEquals CriterionModifier = "EQUALS"
// !=
CriterionModifierNotEquals CriterionModifier = "NOT_EQUALS"
// >
CriterionModifierGreaterThan CriterionModifier = "GREATER_THAN"
// <
CriterionModifierLessThan CriterionModifier = "LESS_THAN"
// IS NULL
CriterionModifierIsNull CriterionModifier = "IS_NULL"
// IS NOT NULL
CriterionModifierNotNull CriterionModifier = "NOT_NULL"
CriterionModifierIncludes CriterionModifier = "INCLUDES"
CriterionModifierExcludes CriterionModifier = "EXCLUDES"
)
var AllCriterionModifier = []CriterionModifier{
CriterionModifierEquals,
CriterionModifierNotEquals,
CriterionModifierGreaterThan,
CriterionModifierLessThan,
CriterionModifierIsNull,
CriterionModifierNotNull,
CriterionModifierIncludes,
CriterionModifierExcludes,
}
func (e CriterionModifier) IsValid() bool {
switch e {
case CriterionModifierEquals, CriterionModifierNotEquals, CriterionModifierGreaterThan, CriterionModifierLessThan, CriterionModifierIsNull, CriterionModifierNotNull, CriterionModifierIncludes, CriterionModifierExcludes:
return true
}
return false
}
func (e CriterionModifier) String() string {
return string(e)
}
func (e *CriterionModifier) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = CriterionModifier(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid CriterionModifier", str)
}
return nil
}
func (e CriterionModifier) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
type ResolutionEnum string
const (

View File

@@ -164,8 +164,11 @@ func (qb *SceneQueryBuilder) Query(sceneFilter *SceneFilterType, findFilter *Fin
}
if rating := sceneFilter.Rating; rating != nil {
whereClauses = append(whereClauses, "rating = ?")
args = append(args, *sceneFilter.Rating)
clause, count := getIntCriterionWhereClause("rating", *sceneFilter.Rating)
whereClauses = append(whereClauses, clause)
if count == 1 {
args = append(args, sceneFilter.Rating.Value)
}
}
if resolutionFilter := sceneFilter.Resolution; resolutionFilter != nil {

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/database"
"github.com/stashapp/stash/pkg/logger"
"reflect"
"strconv"
"strings"
@@ -104,6 +105,48 @@ func getInBinding(length int) string {
return "(" + bindings + ")"
}
func getCriterionModifierBinding(criterionModifier CriterionModifier, value interface{}) (string, int) {
var length int
switch x := value.(type) {
case []string:
length = len(x)
case []int:
length = len(x)
default:
length = 1
logger.Debugf("unsupported type: %T\n", x)
}
if modifier := criterionModifier.String(); criterionModifier.IsValid() {
switch modifier {
case "EQUALS":
return "= ?", 1
case "NOT_EQUALS":
return "!= ?", 1
case "GREATER_THAN":
return "> ?", 1
case "LESS_THAN":
return "< ?", 1
case "IS_NULL":
return "IS NULL", 0
case "NOT_NULL":
return "IS NOT NULL", 0
case "INCLUDES":
return "IN "+getInBinding(length), length // TODO?
case "EXCLUDES":
return "NOT IN "+getInBinding(length), length // TODO?
default:
logger.Errorf("todo")
return "= ?", 1 // TODO
}
}
return "= ?", 1 // TODO
}
func getIntCriterionWhereClause(column string, input IntCriterionInput) (string, int) {
binding, count := getCriterionModifierBinding(input.Modifier, input.Value)
return column+" "+binding, count
}
func runIdsQuery(query string, args []interface{}) ([]int, error) {
var result []struct {
Int int `db:"id"`