mirror of
https://github.com/stashapp/stash.git
synced 2025-12-16 11:57:05 +03:00
Add tag stash ids filter criterion (#6403)
* Add stash id filter to tag filter * Add tag stash id criterion in UI
This commit is contained in:
@@ -606,6 +606,9 @@ input TagFilterType {
|
||||
"Filter by autotag ignore value"
|
||||
ignore_auto_tag: Boolean
|
||||
|
||||
"Filter by StashID"
|
||||
stash_id_endpoint: StashIDCriterionInput
|
||||
|
||||
"Filter by related scenes that meet this criteria"
|
||||
scenes_filter: SceneFilterType
|
||||
"Filter by related images that meet this criteria"
|
||||
|
||||
@@ -40,6 +40,8 @@ type TagFilterType struct {
|
||||
ChildCount *IntCriterionInput `json:"child_count"`
|
||||
// Filter by autotag ignore value
|
||||
IgnoreAutoTag *bool `json:"ignore_auto_tag"`
|
||||
// Filter by StashID Endpoint
|
||||
StashIDEndpoint *StashIDCriterionInput `json:"stash_id_endpoint"`
|
||||
// Filter by related scenes that meet this criteria
|
||||
ScenesFilter *SceneFilterType `json:"scenes_filter"`
|
||||
// Filter by related images that meet this criteria
|
||||
|
||||
@@ -1688,6 +1688,13 @@ func getTagChildCount(id int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func tagStashID(i int) models.StashID {
|
||||
return models.StashID{
|
||||
StashID: getTagStringValue(i, "stashid"),
|
||||
Endpoint: getTagStringValue(i, "endpoint"),
|
||||
}
|
||||
}
|
||||
|
||||
// createTags creates n tags with plain Name and o tags with camel cased NaMe included
|
||||
func createTags(ctx context.Context, tqb models.TagReaderWriter, n int, o int) error {
|
||||
const namePlain = "Name"
|
||||
@@ -1709,6 +1716,12 @@ func createTags(ctx context.Context, tqb models.TagReaderWriter, n int, o int) e
|
||||
IgnoreAutoTag: getIgnoreAutoTag(i),
|
||||
}
|
||||
|
||||
if (index+1)%5 != 0 {
|
||||
tag.StashIDs = models.NewRelatedStashIDs([]models.StashID{
|
||||
tagStashID(i),
|
||||
})
|
||||
}
|
||||
|
||||
err := tqb.Create(ctx, &tag)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -84,6 +84,14 @@ func (qb *tagFilterHandler) criterionHandler() criterionHandler {
|
||||
tagHierarchyHandler.ChildrenCriterionHandler(tagFilter.Children),
|
||||
tagHierarchyHandler.ParentCountCriterionHandler(tagFilter.ParentCount),
|
||||
tagHierarchyHandler.ChildCountCriterionHandler(tagFilter.ChildCount),
|
||||
|
||||
&stashIDCriterionHandler{
|
||||
c: tagFilter.StashIDEndpoint,
|
||||
stashIDRepository: &tagRepository.stashIDs,
|
||||
stashIDTableAs: "tag_stash_ids",
|
||||
parentIDCol: "tags.id",
|
||||
},
|
||||
|
||||
×tampCriterionHandler{tagFilter.CreatedAt, "tags.created_at", nil},
|
||||
×tampCriterionHandler{tagFilter.UpdatedAt, "tags.updated_at", nil},
|
||||
|
||||
|
||||
@@ -343,6 +343,109 @@ func queryTags(ctx context.Context, t *testing.T, qb models.TagReader, tagFilter
|
||||
return tags
|
||||
}
|
||||
|
||||
func tagsToIDs(i []*models.Tag) []int {
|
||||
ret := make([]int, len(i))
|
||||
for i, v := range i {
|
||||
ret[i] = v.ID
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestTagQuery(t *testing.T) {
|
||||
var (
|
||||
endpoint = tagStashID(tagIdxWithPerformer).Endpoint
|
||||
stashID = tagStashID(tagIdxWithPerformer).StashID
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
findFilter *models.FindFilterType
|
||||
filter *models.TagFilterType
|
||||
includeIdxs []int
|
||||
excludeIdxs []int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"stash id with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDEndpoint: &models.StashIDCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashID: &stashID,
|
||||
Modifier: models.CriterionModifierEquals,
|
||||
},
|
||||
},
|
||||
[]int{tagIdxWithPerformer},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"exclude stash id with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDEndpoint: &models.StashIDCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
StashID: &stashID,
|
||||
Modifier: models.CriterionModifierNotEquals,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{tagIdxWithPerformer},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"null stash id with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDEndpoint: &models.StashIDCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierIsNull,
|
||||
},
|
||||
},
|
||||
nil,
|
||||
[]int{tagIdxWithPerformer},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"not null stash id with endpoint",
|
||||
nil,
|
||||
&models.TagFilterType{
|
||||
StashIDEndpoint: &models.StashIDCriterionInput{
|
||||
Endpoint: &endpoint,
|
||||
Modifier: models.CriterionModifierNotNull,
|
||||
},
|
||||
},
|
||||
[]int{tagIdxWithPerformer},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
||||
assert := assert.New(t)
|
||||
|
||||
tags, _, err := db.Tag.Query(ctx, tt.filter, tt.findFilter)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("PerformerStore.Query() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
ids := tagsToIDs(tags)
|
||||
include := indexesToIDs(tagIDs, tt.includeIdxs)
|
||||
exclude := indexesToIDs(tagIDs, tt.excludeIdxs)
|
||||
|
||||
for _, i := range include {
|
||||
assert.Contains(ids, i)
|
||||
}
|
||||
for _, e := range exclude {
|
||||
assert.NotContains(ids, e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTagQueryIsMissingImage(t *testing.T) {
|
||||
withTxn(func(ctx context.Context) error {
|
||||
qb := db.Tag
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
ParentTagsCriterionOption,
|
||||
} from "./criteria/tags";
|
||||
import { FavoriteTagCriterionOption } from "./criteria/favorite";
|
||||
import { StashIDCriterionOption } from "./criteria/stash-ids";
|
||||
|
||||
const defaultSortBy = "name";
|
||||
const sortByOptions = ["name", "random", "scenes_duration"]
|
||||
@@ -58,6 +59,7 @@ const criterionOptions = [
|
||||
createStringCriterionOption("aliases"),
|
||||
createStringCriterionOption("description"),
|
||||
createBooleanCriterionOption("ignore_auto_tag"),
|
||||
StashIDCriterionOption,
|
||||
createMandatoryNumberCriterionOption("scene_count"),
|
||||
createMandatoryNumberCriterionOption("image_count"),
|
||||
createMandatoryNumberCriterionOption("gallery_count"),
|
||||
|
||||
Reference in New Issue
Block a user