mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Add date filters (#2834)
* graphql: support date and timestamp filter types * sql: add support for date & timestamp criterions * ui: add support for date and timestamp criterions * scenes: add support for filtering by date, created at and updated at * image: support filtering by created at and updated at * gallery: support filtering by date, created at and updated at * movie: support filtering by date, created at and updated at * studio: support filtering by date, created at and updated at * tag: support filtering by date, created at and updated at * performer: support filtering by bitrh & death date and created & updated at * marker: support filtering by created & updated at and scene date, created & updated at
This commit is contained in:
@@ -543,6 +543,24 @@ func boolCriterionHandler(c *bool, column string, addJoinFn func(f *filterBuilde
|
||||
}
|
||||
}
|
||||
|
||||
func dateCriterionHandler(c *models.DateCriterionInput, column string) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if c != nil {
|
||||
clause, args := getDateCriterionWhereClause(column, *c)
|
||||
f.addWhere(clause, args...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func timestampCriterionHandler(c *models.TimestampCriterionInput, column string) criterionHandlerFunc {
|
||||
return func(ctx context.Context, f *filterBuilder) {
|
||||
if c != nil {
|
||||
clause, args := getTimestampCriterionWhereClause(column, *c)
|
||||
f.addWhere(clause, args...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle for MultiCriterion where there is a join table between the new
|
||||
// objects
|
||||
type joinedMultiCriterionHandlerBuilder struct {
|
||||
|
||||
@@ -665,6 +665,9 @@ func (qb *GalleryStore) makeFilter(ctx context.Context, galleryFilter *models.Ga
|
||||
query.handleCriterion(ctx, galleryImageCountCriterionHandler(qb, galleryFilter.ImageCount))
|
||||
query.handleCriterion(ctx, galleryPerformerFavoriteCriterionHandler(galleryFilter.PerformerFavorite))
|
||||
query.handleCriterion(ctx, galleryPerformerAgeCriterionHandler(galleryFilter.PerformerAge))
|
||||
query.handleCriterion(ctx, dateCriterionHandler(galleryFilter.Date, "galleries.date"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(galleryFilter.CreatedAt, "galleries.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(galleryFilter.UpdatedAt, "galleries.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -647,6 +647,8 @@ func (qb *ImageStore) makeFilter(ctx context.Context, imageFilter *models.ImageF
|
||||
query.handleCriterion(ctx, imageStudioCriterionHandler(qb, imageFilter.Studios))
|
||||
query.handleCriterion(ctx, imagePerformerTagsCriterionHandler(qb, imageFilter.PerformerTags))
|
||||
query.handleCriterion(ctx, imagePerformerFavoriteCriterionHandler(imageFilter.PerformerFavorite))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(imageFilter.CreatedAt, "images.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(imageFilter.UpdatedAt, "images.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -153,6 +153,9 @@ func (qb *movieQueryBuilder) makeFilter(ctx context.Context, movieFilter *models
|
||||
query.handleCriterion(ctx, stringCriterionHandler(movieFilter.URL, "movies.url"))
|
||||
query.handleCriterion(ctx, movieStudioCriterionHandler(qb, movieFilter.Studios))
|
||||
query.handleCriterion(ctx, moviePerformersCriterionHandler(qb, movieFilter.Performers))
|
||||
query.handleCriterion(ctx, dateCriterionHandler(movieFilter.Date, "movies.date"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(movieFilter.CreatedAt, "movies.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(movieFilter.UpdatedAt, "movies.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -541,6 +541,10 @@ func (qb *PerformerStore) makeFilter(ctx context.Context, filter *models.Perform
|
||||
query.handleCriterion(ctx, performerSceneCountCriterionHandler(qb, filter.SceneCount))
|
||||
query.handleCriterion(ctx, performerImageCountCriterionHandler(qb, filter.ImageCount))
|
||||
query.handleCriterion(ctx, performerGalleryCountCriterionHandler(qb, filter.GalleryCount))
|
||||
query.handleCriterion(ctx, dateCriterionHandler(filter.Birthdate, tableName+".birthdate"))
|
||||
query.handleCriterion(ctx, dateCriterionHandler(filter.DeathDate, tableName+".death_date"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(filter.CreatedAt, tableName+".created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(filter.UpdatedAt, tableName+".updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -877,6 +877,9 @@ func (qb *SceneStore) makeFilter(ctx context.Context, sceneFilter *models.SceneF
|
||||
query.handleCriterion(ctx, scenePerformerFavoriteCriterionHandler(sceneFilter.PerformerFavorite))
|
||||
query.handleCriterion(ctx, scenePerformerAgeCriterionHandler(sceneFilter.PerformerAge))
|
||||
query.handleCriterion(ctx, scenePhashDuplicatedCriterionHandler(sceneFilter.Duplicated, qb.addSceneFilesTable))
|
||||
query.handleCriterion(ctx, dateCriterionHandler(sceneFilter.Date, "scenes.date"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(sceneFilter.CreatedAt, "scenes.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(sceneFilter.UpdatedAt, "scenes.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -131,6 +131,11 @@ func (qb *sceneMarkerQueryBuilder) makeFilter(ctx context.Context, sceneMarkerFi
|
||||
query.handleCriterion(ctx, sceneMarkerTagsCriterionHandler(qb, sceneMarkerFilter.Tags))
|
||||
query.handleCriterion(ctx, sceneMarkerSceneTagsCriterionHandler(qb, sceneMarkerFilter.SceneTags))
|
||||
query.handleCriterion(ctx, sceneMarkerPerformersCriterionHandler(qb, sceneMarkerFilter.Performers))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(sceneMarkerFilter.CreatedAt, "scene_markers.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(sceneMarkerFilter.UpdatedAt, "scene_markers.updated_at"))
|
||||
query.handleCriterion(ctx, dateCriterionHandler(sceneMarkerFilter.SceneDate, "scenes.date"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(sceneMarkerFilter.SceneCreatedAt, "scenes.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(sceneMarkerFilter.SceneUpdatedAt, "scenes.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
@@ -181,6 +182,76 @@ func getIntWhereClause(column string, modifier models.CriterionModifier, value i
|
||||
panic("unsupported int modifier type " + modifier)
|
||||
}
|
||||
|
||||
func getDateCriterionWhereClause(column string, input models.DateCriterionInput) (string, []interface{}) {
|
||||
return getDateWhereClause(column, input.Modifier, input.Value, input.Value2)
|
||||
}
|
||||
|
||||
func getDateWhereClause(column string, modifier models.CriterionModifier, value string, upper *string) (string, []interface{}) {
|
||||
if upper == nil {
|
||||
u := time.Now().AddDate(0, 0, 1).Format(time.RFC3339)
|
||||
upper = &u
|
||||
}
|
||||
|
||||
args := []interface{}{value}
|
||||
betweenArgs := []interface{}{value, *upper}
|
||||
|
||||
switch modifier {
|
||||
case models.CriterionModifierIsNull:
|
||||
return fmt.Sprintf("(%s IS NULL OR %s = '')", column, column), nil
|
||||
case models.CriterionModifierNotNull:
|
||||
return fmt.Sprintf("(%s IS NOT NULL AND %s != '')", column, column), nil
|
||||
case models.CriterionModifierEquals:
|
||||
return fmt.Sprintf("%s = ?", column), args
|
||||
case models.CriterionModifierNotEquals:
|
||||
return fmt.Sprintf("%s != ?", column), args
|
||||
case models.CriterionModifierBetween:
|
||||
return fmt.Sprintf("%s BETWEEN ? AND ?", column), betweenArgs
|
||||
case models.CriterionModifierNotBetween:
|
||||
return fmt.Sprintf("%s NOT BETWEEN ? AND ?", column), betweenArgs
|
||||
case models.CriterionModifierLessThan:
|
||||
return fmt.Sprintf("%s < ?", column), args
|
||||
case models.CriterionModifierGreaterThan:
|
||||
return fmt.Sprintf("%s > ?", column), args
|
||||
}
|
||||
|
||||
panic("unsupported date modifier type")
|
||||
}
|
||||
|
||||
func getTimestampCriterionWhereClause(column string, input models.TimestampCriterionInput) (string, []interface{}) {
|
||||
return getTimestampWhereClause(column, input.Modifier, input.Value, input.Value2)
|
||||
}
|
||||
|
||||
func getTimestampWhereClause(column string, modifier models.CriterionModifier, value string, upper *string) (string, []interface{}) {
|
||||
if upper == nil {
|
||||
u := time.Now().AddDate(0, 0, 1).Format(time.RFC3339)
|
||||
upper = &u
|
||||
}
|
||||
|
||||
args := []interface{}{value}
|
||||
betweenArgs := []interface{}{value, *upper}
|
||||
|
||||
switch modifier {
|
||||
case models.CriterionModifierIsNull:
|
||||
return fmt.Sprintf("%s IS NULL", column), nil
|
||||
case models.CriterionModifierNotNull:
|
||||
return fmt.Sprintf("%s IS NOT NULL", column), nil
|
||||
case models.CriterionModifierEquals:
|
||||
return fmt.Sprintf("%s = ?", column), args
|
||||
case models.CriterionModifierNotEquals:
|
||||
return fmt.Sprintf("%s != ?", column), args
|
||||
case models.CriterionModifierBetween:
|
||||
return fmt.Sprintf("%s BETWEEN ? AND ?", column), betweenArgs
|
||||
case models.CriterionModifierNotBetween:
|
||||
return fmt.Sprintf("%s NOT BETWEEN ? AND ?", column), betweenArgs
|
||||
case models.CriterionModifierLessThan:
|
||||
return fmt.Sprintf("%s < ?", column), args
|
||||
case models.CriterionModifierGreaterThan:
|
||||
return fmt.Sprintf("%s > ?", column), args
|
||||
}
|
||||
|
||||
panic("unsupported date modifier type")
|
||||
}
|
||||
|
||||
// returns where clause and having clause
|
||||
func getMultiCriterionClause(primaryTable, foreignTable, joinTable, primaryFK, foreignFK string, criterion *models.MultiCriterionInput) (string, string) {
|
||||
whereClause := ""
|
||||
|
||||
@@ -250,6 +250,8 @@ func (qb *studioQueryBuilder) makeFilter(ctx context.Context, studioFilter *mode
|
||||
query.handleCriterion(ctx, studioGalleryCountCriterionHandler(qb, studioFilter.GalleryCount))
|
||||
query.handleCriterion(ctx, studioParentCriterionHandler(qb, studioFilter.Parents))
|
||||
query.handleCriterion(ctx, studioAliasCriterionHandler(qb, studioFilter.Aliases))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(studioFilter.CreatedAt, "studios.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(studioFilter.UpdatedAt, "studios.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -338,6 +338,8 @@ func (qb *tagQueryBuilder) makeFilter(ctx context.Context, tagFilter *models.Tag
|
||||
query.handleCriterion(ctx, tagChildrenCriterionHandler(qb, tagFilter.Children))
|
||||
query.handleCriterion(ctx, tagParentCountCriterionHandler(qb, tagFilter.ParentCount))
|
||||
query.handleCriterion(ctx, tagChildCountCriterionHandler(qb, tagFilter.ChildCount))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(tagFilter.CreatedAt, "tags.created_at"))
|
||||
query.handleCriterion(ctx, timestampCriterionHandler(tagFilter.UpdatedAt, "tags.updated_at"))
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user