2021-09-08 05:30:15 +00:00
|
|
|
//go:build integration
|
2021-01-18 01:23:20 +00:00
|
|
|
// +build integration
|
|
|
|
|
|
|
|
package sqlite_test
|
|
|
|
|
|
|
|
import (
|
2022-05-19 07:49:32 +00:00
|
|
|
"context"
|
2024-10-29 00:26:23 +00:00
|
|
|
"slices"
|
2023-06-06 03:01:50 +00:00
|
|
|
"strconv"
|
2021-01-18 01:23:20 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stashapp/stash/pkg/models"
|
2023-06-06 03:01:50 +00:00
|
|
|
"github.com/stashapp/stash/pkg/sliceutil/stringslice"
|
2021-01-18 01:23:20 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestMarkerFindBySceneID(t *testing.T) {
|
2022-05-19 07:49:32 +00:00
|
|
|
withTxn(func(ctx context.Context) error {
|
2023-06-15 02:46:09 +00:00
|
|
|
mqb := db.SceneMarker
|
2021-01-18 01:23:20 +00:00
|
|
|
|
2021-11-06 22:34:33 +00:00
|
|
|
sceneID := sceneIDs[sceneIdxWithMarkers]
|
2022-05-19 07:49:32 +00:00
|
|
|
markers, err := mqb.FindBySceneID(ctx, sceneID)
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Error finding markers: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
2021-11-06 22:34:33 +00:00
|
|
|
assert.Greater(t, len(markers), 0)
|
|
|
|
for _, marker := range markers {
|
2023-06-15 02:46:09 +00:00
|
|
|
assert.Equal(t, sceneIDs[sceneIdxWithMarkers], marker.SceneID)
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
2021-01-18 01:23:20 +00:00
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
markers, err = mqb.FindBySceneID(ctx, 0)
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Error finding marker: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Len(t, markers, 0)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMarkerCountByTagID(t *testing.T) {
|
2022-05-19 07:49:32 +00:00
|
|
|
withTxn(func(ctx context.Context) error {
|
2023-06-15 02:46:09 +00:00
|
|
|
mqb := db.SceneMarker
|
2021-01-18 01:23:20 +00:00
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
markerCount, err := mqb.CountByTagID(ctx, tagIDs[tagIdxWithPrimaryMarkers])
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error calling CountByTagID: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
2023-06-23 01:04:54 +00:00
|
|
|
assert.Equal(t, 6, markerCount)
|
2021-01-18 01:23:20 +00:00
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
markerCount, err = mqb.CountByTagID(ctx, tagIDs[tagIdxWithMarkers])
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error calling CountByTagID: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
2023-06-23 01:04:54 +00:00
|
|
|
assert.Equal(t, 2, markerCount)
|
2021-01-18 01:23:20 +00:00
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
markerCount, err = mqb.CountByTagID(ctx, 0)
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error calling CountByTagID: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, 0, markerCount)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-06-24 06:02:46 +00:00
|
|
|
func TestMarkerQueryQ(t *testing.T) {
|
|
|
|
withTxn(func(ctx context.Context) error {
|
|
|
|
q := getSceneTitle(sceneIdxWithMarkers)
|
|
|
|
m, _, err := db.SceneMarker.Query(ctx, nil, &models.FindFilterType{
|
|
|
|
Q: &q,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Error querying scene markers: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if !assert.Greater(t, len(m), 0) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, sceneIDs[sceneIdxWithMarkers], m[0].SceneID)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-27 02:26:38 +00:00
|
|
|
func TestMarkerQuerySortBySceneUpdated(t *testing.T) {
|
2022-05-19 07:49:32 +00:00
|
|
|
withTxn(func(ctx context.Context) error {
|
2021-09-27 02:26:38 +00:00
|
|
|
sort := "scenes_updated_at"
|
2023-06-15 02:46:09 +00:00
|
|
|
_, _, err := db.SceneMarker.Query(ctx, nil, &models.FindFilterType{
|
2021-09-27 02:26:38 +00:00
|
|
|
Sort: &sort,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Error querying scene markers: %s", err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-06-23 01:04:54 +00:00
|
|
|
func verifyIDs(t *testing.T, modifier models.CriterionModifier, values []int, results []int) {
|
|
|
|
t.Helper()
|
|
|
|
switch modifier {
|
|
|
|
case models.CriterionModifierIsNull:
|
|
|
|
assert.Len(t, results, 0)
|
|
|
|
case models.CriterionModifierNotNull:
|
|
|
|
assert.NotEqual(t, 0, len(results))
|
|
|
|
case models.CriterionModifierIncludes:
|
|
|
|
for _, v := range values {
|
|
|
|
assert.Contains(t, results, v)
|
|
|
|
}
|
|
|
|
case models.CriterionModifierExcludes:
|
|
|
|
for _, v := range values {
|
|
|
|
assert.NotContains(t, results, v)
|
|
|
|
}
|
|
|
|
case models.CriterionModifierEquals:
|
|
|
|
for _, v := range values {
|
|
|
|
assert.Contains(t, results, v)
|
|
|
|
}
|
|
|
|
assert.Len(t, results, len(values))
|
|
|
|
case models.CriterionModifierNotEquals:
|
|
|
|
foundAll := true
|
|
|
|
for _, v := range values {
|
2024-10-29 00:26:23 +00:00
|
|
|
if !slices.Contains(results, v) {
|
2023-06-23 01:04:54 +00:00
|
|
|
foundAll = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if foundAll && len(results) == len(values) {
|
|
|
|
t.Errorf("expected ids not equal to %v - found %v", values, results)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-06 22:34:33 +00:00
|
|
|
func TestMarkerQueryTags(t *testing.T) {
|
|
|
|
type test struct {
|
|
|
|
name string
|
|
|
|
markerFilter *models.SceneMarkerFilterType
|
|
|
|
findFilter *models.FindFilterType
|
|
|
|
}
|
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
withTxn(func(ctx context.Context) error {
|
2023-06-23 01:04:54 +00:00
|
|
|
testTags := func(t *testing.T, m *models.SceneMarker, markerFilter *models.SceneMarkerFilterType) {
|
2023-06-15 02:46:09 +00:00
|
|
|
tagIDs, err := db.SceneMarker.GetTagIDs(ctx, m.ID)
|
2021-11-06 22:34:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error getting marker tag ids: %v", err)
|
|
|
|
}
|
2023-06-23 01:04:54 +00:00
|
|
|
|
|
|
|
// HACK - if modifier isn't null/not null, then add the primary tag id
|
|
|
|
if markerFilter.Tags.Modifier != models.CriterionModifierIsNull && markerFilter.Tags.Modifier != models.CriterionModifierNotNull {
|
|
|
|
tagIDs = append(tagIDs, m.PrimaryTagID)
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
2023-06-23 01:04:54 +00:00
|
|
|
|
|
|
|
values, _ := stringslice.StringSliceToIntSlice(markerFilter.Tags.Value)
|
|
|
|
verifyIDs(t, markerFilter.Tags.Modifier, values, tagIDs)
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cases := []test{
|
|
|
|
{
|
|
|
|
"is null",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIsNull,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"not null",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierNotNull,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
2023-06-23 01:04:54 +00:00
|
|
|
{
|
|
|
|
"includes",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIncludes,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdxWithMarkers]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"includes all",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIncludesAll,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdxWithMarkers]),
|
|
|
|
strconv.Itoa(tagIDs[tagIdx2WithMarkers]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"equals",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierEquals,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdxWithPrimaryMarkers]),
|
|
|
|
strconv.Itoa(tagIDs[tagIdxWithMarkers]),
|
|
|
|
strconv.Itoa(tagIDs[tagIdx2WithMarkers]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
// not equals not supported
|
|
|
|
// {
|
|
|
|
// "not equals",
|
|
|
|
// &models.SceneMarkerFilterType{
|
|
|
|
// Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
// Modifier: models.CriterionModifierNotEquals,
|
|
|
|
// Value: []string{
|
|
|
|
// strconv.Itoa(tagIDs[tagIdx2WithScene]),
|
|
|
|
// strconv.Itoa(tagIDs[tagIdx3WithScene]),
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// nil,
|
|
|
|
// },
|
|
|
|
{
|
|
|
|
"excludes",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
Tags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIncludes,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdx2WithMarkers]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
2023-06-15 02:46:09 +00:00
|
|
|
markers := queryMarkers(ctx, t, db.SceneMarker, tc.markerFilter, tc.findFilter)
|
2021-11-06 22:34:33 +00:00
|
|
|
assert.Greater(t, len(markers), 0)
|
|
|
|
for _, m := range markers {
|
2023-06-23 01:04:54 +00:00
|
|
|
testTags(t, m, tc.markerFilter)
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMarkerQuerySceneTags(t *testing.T) {
|
|
|
|
type test struct {
|
|
|
|
name string
|
|
|
|
markerFilter *models.SceneMarkerFilterType
|
|
|
|
findFilter *models.FindFilterType
|
|
|
|
}
|
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
withTxn(func(ctx context.Context) error {
|
2023-06-06 03:01:50 +00:00
|
|
|
testTags := func(t *testing.T, m *models.SceneMarker, markerFilter *models.SceneMarkerFilterType) {
|
2023-06-15 02:46:09 +00:00
|
|
|
s, err := db.Scene.Find(ctx, m.SceneID)
|
2021-11-06 22:34:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("error getting marker tag ids: %v", err)
|
2022-07-13 06:30:54 +00:00
|
|
|
return
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
2022-08-12 02:21:46 +00:00
|
|
|
|
|
|
|
if err := s.LoadTagIDs(ctx, db.Scene); err != nil {
|
|
|
|
t.Errorf("error getting marker tag ids: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
tagIDs := s.TagIDs.List()
|
2023-06-06 03:01:50 +00:00
|
|
|
values, _ := stringslice.StringSliceToIntSlice(markerFilter.SceneTags.Value)
|
2023-06-23 01:04:54 +00:00
|
|
|
verifyIDs(t, markerFilter.SceneTags.Modifier, values, tagIDs)
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cases := []test{
|
|
|
|
{
|
|
|
|
"is null",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIsNull,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"not null",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierNotNull,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
2023-06-06 03:01:50 +00:00
|
|
|
{
|
|
|
|
"includes",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIncludes,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdx3WithScene]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"includes all",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIncludesAll,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdx2WithScene]),
|
|
|
|
strconv.Itoa(tagIDs[tagIdx3WithScene]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"equals",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierEquals,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdx2WithScene]),
|
|
|
|
strconv.Itoa(tagIDs[tagIdx3WithScene]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
|
|
|
// not equals not supported
|
|
|
|
// {
|
|
|
|
// "not equals",
|
|
|
|
// &models.SceneMarkerFilterType{
|
|
|
|
// SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
// Modifier: models.CriterionModifierNotEquals,
|
|
|
|
// Value: []string{
|
|
|
|
// strconv.Itoa(tagIDs[tagIdx2WithScene]),
|
|
|
|
// strconv.Itoa(tagIDs[tagIdx3WithScene]),
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// },
|
|
|
|
// nil,
|
|
|
|
// },
|
|
|
|
{
|
|
|
|
"excludes",
|
|
|
|
&models.SceneMarkerFilterType{
|
|
|
|
SceneTags: &models.HierarchicalMultiCriterionInput{
|
|
|
|
Modifier: models.CriterionModifierIncludes,
|
|
|
|
Value: []string{
|
|
|
|
strconv.Itoa(tagIDs[tagIdx2WithScene]),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
nil,
|
|
|
|
},
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
2023-06-15 02:46:09 +00:00
|
|
|
markers := queryMarkers(ctx, t, db.SceneMarker, tc.markerFilter, tc.findFilter)
|
2021-11-06 22:34:33 +00:00
|
|
|
assert.Greater(t, len(markers), 0)
|
|
|
|
for _, m := range markers {
|
2023-06-06 03:01:50 +00:00
|
|
|
testTags(t, m, tc.markerFilter)
|
2021-11-06 22:34:33 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-05-19 07:49:32 +00:00
|
|
|
func queryMarkers(ctx context.Context, t *testing.T, sqb models.SceneMarkerReader, markerFilter *models.SceneMarkerFilterType, findFilter *models.FindFilterType) []*models.SceneMarker {
|
2021-11-06 22:34:33 +00:00
|
|
|
t.Helper()
|
2022-05-19 07:49:32 +00:00
|
|
|
result, _, err := sqb.Query(ctx, markerFilter, findFilter)
|
2021-11-06 22:34:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Error querying markers: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-01-18 01:23:20 +00:00
|
|
|
// TODO Update
|
|
|
|
// TODO Destroy
|
|
|
|
// TODO Find
|
|
|
|
// TODO GetMarkerStrings
|
|
|
|
// TODO Wall
|
2023-02-19 22:24:47 +00:00
|
|
|
// TODO Count
|
|
|
|
// TODO All
|
2021-01-18 01:23:20 +00:00
|
|
|
// TODO Query
|