mirror of
https://github.com/stashapp/stash.git
synced 2026-01-25 09:35:33 +01:00
Implement stash_ids_endpoint for the SceneFilterType (#6401)
* Implement stash_ids_endpoint for the SceneFilterType * Reduce code duplication by calling the stashIDsCriterionHandler from the stashIDCriterionHandler * Mark stash_id_endpoint in SceneFilterType, StudioFilterType, and PerformerFilterType as deprecated
This commit is contained in:
parent
2a5b59a96a
commit
ed3a239366
15 changed files with 297 additions and 14 deletions
|
|
@ -84,13 +84,23 @@ input PHashDuplicationCriterionInput {
|
|||
input StashIDCriterionInput {
|
||||
"""
|
||||
If present, this value is treated as a predicate.
|
||||
That is, it will filter based on stash_ids with the matching endpoint
|
||||
That is, it will filter based on stash_id with the matching endpoint
|
||||
"""
|
||||
endpoint: String
|
||||
stash_id: String
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input StashIDsCriterionInput {
|
||||
"""
|
||||
If present, this value is treated as a predicate.
|
||||
That is, it will filter based on stash_ids with the matching endpoint
|
||||
"""
|
||||
endpoint: String
|
||||
stash_ids: [String]
|
||||
modifier: CriterionModifier!
|
||||
}
|
||||
|
||||
input CustomFieldCriterionInput {
|
||||
field: String!
|
||||
value: [Any!]
|
||||
|
|
@ -156,6 +166,9 @@ input PerformerFilterType {
|
|||
o_counter: IntCriterionInput
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
@deprecated(reason: "use stash_ids_endpoint instead")
|
||||
"Filter by StashIDs"
|
||||
stash_ids_endpoint: StashIDsCriterionInput
|
||||
# rating expressed as 1-100
|
||||
rating100: IntCriterionInput
|
||||
"Filter by url"
|
||||
|
|
@ -292,6 +305,9 @@ input SceneFilterType {
|
|||
performer_count: IntCriterionInput
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
@deprecated(reason: "use stash_ids_endpoint instead")
|
||||
"Filter by StashIDs"
|
||||
stash_ids_endpoint: StashIDsCriterionInput
|
||||
"Filter by url"
|
||||
url: StringCriterionInput
|
||||
"Filter by interactive"
|
||||
|
|
@ -432,6 +448,9 @@ input StudioFilterType {
|
|||
parents: MultiCriterionInput
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
@deprecated(reason: "use stash_ids_endpoint instead")
|
||||
"Filter by StashIDs"
|
||||
stash_ids_endpoint: StashIDsCriterionInput
|
||||
"Filter to only include studios with these tags"
|
||||
tags: HierarchicalMultiCriterionInput
|
||||
"Filter to only include studios missing this property"
|
||||
|
|
@ -608,6 +627,10 @@ input TagFilterType {
|
|||
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
@deprecated(reason: "use stash_ids_endpoint instead")
|
||||
|
||||
"Filter by StashID"
|
||||
stash_ids_endpoint: StashIDsCriterionInput
|
||||
|
||||
"Filter by related scenes that meet this criteria"
|
||||
scenes_filter: SceneFilterType
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ type PerformerFilterType struct {
|
|||
StashID *StringCriterionInput `json:"stash_id"`
|
||||
// Filter by StashID Endpoint
|
||||
StashIDEndpoint *StashIDCriterionInput `json:"stash_id_endpoint"`
|
||||
// Filter by StashIDs Endpoint
|
||||
StashIDsEndpoint *StashIDsCriterionInput `json:"stash_ids_endpoint"`
|
||||
// Filter by rating expressed as 1-100
|
||||
Rating100 *IntCriterionInput `json:"rating100"`
|
||||
// Filter by url
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ type SceneFilterType struct {
|
|||
StashID *StringCriterionInput `json:"stash_id"`
|
||||
// Filter by StashID Endpoint
|
||||
StashIDEndpoint *StashIDCriterionInput `json:"stash_id_endpoint"`
|
||||
// Filter by StashIDs Endpoint
|
||||
StashIDsEndpoint *StashIDsCriterionInput `json:"stash_ids_endpoint"`
|
||||
// Filter by url
|
||||
URL *StringCriterionInput `json:"url"`
|
||||
// Filter by interactive
|
||||
|
|
|
|||
|
|
@ -129,8 +129,16 @@ func (u *UpdateStashIDs) Set(v StashID) {
|
|||
|
||||
type StashIDCriterionInput struct {
|
||||
// If present, this value is treated as a predicate.
|
||||
// That is, it will filter based on stash_ids with the matching endpoint
|
||||
// That is, it will filter based on stash_id with the matching endpoint
|
||||
Endpoint *string `json:"endpoint"`
|
||||
StashID *string `json:"stash_id"`
|
||||
Modifier CriterionModifier `json:"modifier"`
|
||||
}
|
||||
|
||||
type StashIDsCriterionInput struct {
|
||||
// If present, this value is treated as a predicate.
|
||||
// That is, it will filter based on stash_ids with the matching endpoint
|
||||
Endpoint *string `json:"endpoint"`
|
||||
StashIDs []*string `json:"stash_ids"`
|
||||
Modifier CriterionModifier `json:"modifier"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ type StudioFilterType struct {
|
|||
StashID *StringCriterionInput `json:"stash_id"`
|
||||
// Filter by StashID Endpoint
|
||||
StashIDEndpoint *StashIDCriterionInput `json:"stash_id_endpoint"`
|
||||
// Filter by StashIDs Endpoint
|
||||
StashIDsEndpoint *StashIDsCriterionInput `json:"stash_ids_endpoint"`
|
||||
// Filter to only include studios missing this property
|
||||
IsMissing *string `json:"is_missing"`
|
||||
// Filter by rating expressed as 1-100
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ type TagFilterType struct {
|
|||
IgnoreAutoTag *bool `json:"ignore_auto_tag"`
|
||||
// Filter by StashID Endpoint
|
||||
StashIDEndpoint *StashIDCriterionInput `json:"stash_id_endpoint"`
|
||||
// Filter by StashIDs Endpoint
|
||||
StashIDsEndpoint *StashIDsCriterionInput `json:"stash_ids_endpoint"`
|
||||
// Filter by related scenes that meet this criteria
|
||||
ScenesFilter *SceneFilterType `json:"scenes_filter"`
|
||||
// Filter by related images that meet this criteria
|
||||
|
|
|
|||
|
|
@ -1012,6 +1012,41 @@ func (h *stashIDCriterionHandler) handle(ctx context.Context, f *filterBuilder)
|
|||
return
|
||||
}
|
||||
|
||||
var stashIDs []*string
|
||||
if h.c.StashID != nil {
|
||||
stashIDs = []*string{h.c.StashID}
|
||||
} else {
|
||||
stashIDs = nil
|
||||
}
|
||||
|
||||
convertedInput := &models.StashIDsCriterionInput{
|
||||
Endpoint: h.c.Endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: h.c.Modifier,
|
||||
}
|
||||
|
||||
convertedHandler := stashIDsCriterionHandler{
|
||||
c: convertedInput,
|
||||
stashIDRepository: h.stashIDRepository,
|
||||
stashIDTableAs: h.stashIDTableAs,
|
||||
parentIDCol: h.parentIDCol,
|
||||
}
|
||||
|
||||
convertedHandler.handle(ctx, f)
|
||||
}
|
||||
|
||||
type stashIDsCriterionHandler struct {
|
||||
c *models.StashIDsCriterionInput
|
||||
stashIDRepository *stashIDRepository
|
||||
stashIDTableAs string
|
||||
parentIDCol string
|
||||
}
|
||||
|
||||
func (h *stashIDsCriterionHandler) handle(ctx context.Context, f *filterBuilder) {
|
||||
if h.c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
stashIDRepo := h.stashIDRepository
|
||||
t := stashIDRepo.tableName
|
||||
if h.stashIDTableAs != "" {
|
||||
|
|
@ -1025,15 +1060,33 @@ func (h *stashIDCriterionHandler) handle(ctx context.Context, f *filterBuilder)
|
|||
|
||||
f.addLeftJoin(stashIDRepo.tableName, h.stashIDTableAs, joinClause)
|
||||
|
||||
v := ""
|
||||
if h.c.StashID != nil {
|
||||
v = *h.c.StashID
|
||||
}
|
||||
if len(h.c.StashIDs) == 0 {
|
||||
stringCriterionHandler(&models.StringCriterionInput{
|
||||
Value: "",
|
||||
Modifier: h.c.Modifier,
|
||||
}, t+".stash_id")(ctx, f)
|
||||
} else {
|
||||
b := f
|
||||
for _, n := range h.c.StashIDs {
|
||||
query := &filterBuilder{}
|
||||
v := ""
|
||||
if n != nil {
|
||||
v = *n
|
||||
}
|
||||
|
||||
stringCriterionHandler(&models.StringCriterionInput{
|
||||
Value: v,
|
||||
Modifier: h.c.Modifier,
|
||||
}, t+".stash_id")(ctx, f)
|
||||
stringCriterionHandler(&models.StringCriterionInput{
|
||||
Value: v,
|
||||
Modifier: h.c.Modifier,
|
||||
}, t+".stash_id")(ctx, query)
|
||||
|
||||
if h.c.Modifier == models.CriterionModifierNotEquals {
|
||||
b.and(query)
|
||||
} else {
|
||||
b.or(query)
|
||||
}
|
||||
b = query
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type relatedFilterHandler struct {
|
||||
|
|
|
|||
|
|
@ -148,6 +148,12 @@ func (qb *performerFilterHandler) criterionHandler() criterionHandler {
|
|||
stashIDTableAs: "performer_stash_ids",
|
||||
parentIDCol: "performers.id",
|
||||
},
|
||||
&stashIDsCriterionHandler{
|
||||
c: filter.StashIDsEndpoint,
|
||||
stashIDRepository: &performerRepository.stashIDs,
|
||||
stashIDTableAs: "performer_stash_ids",
|
||||
parentIDCol: "performers.id",
|
||||
},
|
||||
|
||||
qb.aliasCriterionHandler(filter.Aliases),
|
||||
|
||||
|
|
|
|||
|
|
@ -1069,6 +1069,8 @@ func TestPerformerQuery(t *testing.T) {
|
|||
var (
|
||||
endpoint = performerStashID(performerIdxWithGallery).Endpoint
|
||||
stashID = performerStashID(performerIdxWithGallery).StashID
|
||||
stashID2 = performerStashID(performerIdx1WithGallery).StashID
|
||||
stashIDs = []*string{&stashID, &stashID2}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
|
|
@ -1133,6 +1135,60 @@ func TestPerformerQuery(t *testing.T) {
|
|||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"stash ids with endpoint",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
},
|
||||
[]int{performerIdxWithGallery, performerIdx1WithGallery},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude stash ids with endpoint",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: models.CriterionModifierNotEquals,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{performerIdxWithGallery, performerIdx1WithGallery},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"null stash ids with endpoint",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierIsNull,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{performerIdxWithGallery, performerIdx1WithGallery},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"not null stash ids with endpoint",
|
||||
nil,
|
||||
&models.PerformerFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierNotNull,
|
||||
},
|
||||
},
|
||||
[]int{performerIdxWithGallery, performerIdx1WithGallery},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"circumcised (cut)",
|
||||
nil,
|
||||
|
|
|
|||
|
|
@ -114,13 +114,18 @@ func (qb *sceneFilterHandler) criterionHandler() criterionHandler {
|
|||
stringCriterionHandler(sceneFilter.StashID, "scene_stash_ids.stash_id")(ctx, f)
|
||||
}
|
||||
}),
|
||||
|
||||
&stashIDCriterionHandler{
|
||||
c: sceneFilter.StashIDEndpoint,
|
||||
stashIDRepository: &sceneRepository.stashIDs,
|
||||
stashIDTableAs: "scene_stash_ids",
|
||||
parentIDCol: "scenes.id",
|
||||
},
|
||||
&stashIDsCriterionHandler{
|
||||
c: sceneFilter.StashIDsEndpoint,
|
||||
stashIDRepository: &sceneRepository.stashIDs,
|
||||
stashIDTableAs: "scene_stash_ids",
|
||||
parentIDCol: "scenes.id",
|
||||
},
|
||||
|
||||
boolCriterionHandler(sceneFilter.Interactive, "video_files.interactive", qb.addVideoFilesTable),
|
||||
intCriterionHandler(sceneFilter.InteractiveSpeed, "video_files.interactive_speed", qb.addVideoFilesTable),
|
||||
|
|
|
|||
|
|
@ -2098,6 +2098,8 @@ func TestSceneQuery(t *testing.T) {
|
|||
var (
|
||||
endpoint = sceneStashID(sceneIdxWithGallery).Endpoint
|
||||
stashID = sceneStashID(sceneIdxWithGallery).StashID
|
||||
stashID2 = sceneStashID(sceneIdxWithPerformer).StashID
|
||||
stashIDs = []*string{&stashID, &stashID2}
|
||||
|
||||
depth = -1
|
||||
)
|
||||
|
|
@ -2203,6 +2205,60 @@ func TestSceneQuery(t *testing.T) {
|
|||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"stash ids with endpoint",
|
||||
nil,
|
||||
&models.SceneFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
},
|
||||
[]int{sceneIdxWithGallery, sceneIdxWithPerformer},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude stash ids with endpoint",
|
||||
nil,
|
||||
&models.SceneFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: models.CriterionModifierNotEquals,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{sceneIdxWithGallery, sceneIdxWithPerformer},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"null stash ids with endpoint",
|
||||
nil,
|
||||
&models.SceneFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierIsNull,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{sceneIdxWithGallery, sceneIdxWithPerformer},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"not null stash ids with endpoint",
|
||||
nil,
|
||||
&models.SceneFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierNotNull,
|
||||
},
|
||||
},
|
||||
[]int{sceneIdxWithGallery, sceneIdxWithPerformer},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"with studio id 0 including child studios",
|
||||
nil,
|
||||
|
|
|
|||
|
|
@ -1079,7 +1079,7 @@ func getObjectDate(index int) *models.Date {
|
|||
func sceneStashID(i int) models.StashID {
|
||||
return models.StashID{
|
||||
StashID: getSceneStringValue(i, "stashid"),
|
||||
Endpoint: getSceneStringValue(i, "endpoint"),
|
||||
Endpoint: getSceneStringValue(0, "endpoint"),
|
||||
UpdatedAt: epochTime,
|
||||
}
|
||||
}
|
||||
|
|
@ -1547,7 +1547,7 @@ func getIgnoreAutoTag(index int) bool {
|
|||
func performerStashID(i int) models.StashID {
|
||||
return models.StashID{
|
||||
StashID: getPerformerStringValue(i, "stashid"),
|
||||
Endpoint: getPerformerStringValue(i, "endpoint"),
|
||||
Endpoint: getPerformerStringValue(0, "endpoint"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1700,7 +1700,7 @@ func getTagChildCount(id int) int {
|
|||
func tagStashID(i int) models.StashID {
|
||||
return models.StashID{
|
||||
StashID: getTagStringValue(i, "stashid"),
|
||||
Endpoint: getTagStringValue(i, "endpoint"),
|
||||
Endpoint: getTagStringValue(0, "endpoint"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,12 @@ func (qb *studioFilterHandler) criterionHandler() criterionHandler {
|
|||
stashIDTableAs: "studio_stash_ids",
|
||||
parentIDCol: "studios.id",
|
||||
},
|
||||
&stashIDsCriterionHandler{
|
||||
c: studioFilter.StashIDsEndpoint,
|
||||
stashIDRepository: &studioRepository.stashIDs,
|
||||
stashIDTableAs: "studio_stash_ids",
|
||||
parentIDCol: "studios.id",
|
||||
},
|
||||
|
||||
qb.isMissingCriterionHandler(studioFilter.IsMissing),
|
||||
qb.tagCountCriterionHandler(studioFilter.TagCount),
|
||||
|
|
|
|||
|
|
@ -91,6 +91,12 @@ func (qb *tagFilterHandler) criterionHandler() criterionHandler {
|
|||
stashIDTableAs: "tag_stash_ids",
|
||||
parentIDCol: "tags.id",
|
||||
},
|
||||
&stashIDsCriterionHandler{
|
||||
c: tagFilter.StashIDsEndpoint,
|
||||
stashIDRepository: &tagRepository.stashIDs,
|
||||
stashIDTableAs: "tag_stash_ids",
|
||||
parentIDCol: "tags.id",
|
||||
},
|
||||
|
||||
×tampCriterionHandler{tagFilter.CreatedAt, "tags.created_at", nil},
|
||||
×tampCriterionHandler{tagFilter.UpdatedAt, "tags.updated_at", nil},
|
||||
|
|
|
|||
|
|
@ -356,6 +356,8 @@ func TestTagQuery(t *testing.T) {
|
|||
var (
|
||||
endpoint = tagStashID(tagIdxWithPerformer).Endpoint
|
||||
stashID = tagStashID(tagIdxWithPerformer).StashID
|
||||
stashID2 = tagStashID(tagIdx1WithPerformer).StashID
|
||||
stashIDs = []*string{&stashID, &stashID2}
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
|
|
@ -420,6 +422,60 @@ func TestTagQuery(t *testing.T) {
|
|||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"stash ids with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
},
|
||||
[]int{tagIdxWithPerformer, tagIdx1WithPerformer},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude stash ids with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashIDs: stashIDs,
|
||||
Modifier: models.CriterionModifierNotEquals,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{tagIdxWithPerformer, tagIdx1WithPerformer},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"null stash ids with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierIsNull,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{tagIdxWithPerformer, tagIdx1WithPerformer},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"not null stash ids with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDsEndpoint: &models.StashIDsCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierNotNull,
|
||||
},
|
||||
},
|
||||
[]int{tagIdxWithPerformer, tagIdx1WithPerformer},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
Loading…
Reference in a new issue