[Files Refactor] Performance tuning (#2819)

* Load scene relationships on demand
* Load image relationships on demand
* Load gallery relationships on demand
* Add dataloaden
* Use dataloaders
* Use where in for other find many functions
This commit is contained in:
WithoutPants
2022-08-12 12:21:46 +10:00
parent 9b31b20fed
commit 00608c167a
317 changed files with 28002 additions and 14875 deletions

View File

@@ -133,14 +133,20 @@ func (qb *GalleryStore) Create(ctx context.Context, newObject *models.Gallery, f
}
}
if err := galleriesPerformersTableMgr.insertJoins(ctx, id, newObject.PerformerIDs); err != nil {
return err
if newObject.PerformerIDs.Loaded() {
if err := galleriesPerformersTableMgr.insertJoins(ctx, id, newObject.PerformerIDs.List()); err != nil {
return err
}
}
if err := galleriesTagsTableMgr.insertJoins(ctx, id, newObject.TagIDs); err != nil {
return err
if newObject.TagIDs.Loaded() {
if err := galleriesTagsTableMgr.insertJoins(ctx, id, newObject.TagIDs.List()); err != nil {
return err
}
}
if err := galleriesScenesTableMgr.insertJoins(ctx, id, newObject.SceneIDs); err != nil {
return err
if newObject.SceneIDs.Loaded() {
if err := galleriesScenesTableMgr.insertJoins(ctx, id, newObject.SceneIDs.List()); err != nil {
return err
}
}
updated, err := qb.Find(ctx, id)
@@ -161,14 +167,20 @@ func (qb *GalleryStore) Update(ctx context.Context, updatedObject *models.Galler
return err
}
if err := galleriesPerformersTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.PerformerIDs); err != nil {
return err
if updatedObject.PerformerIDs.Loaded() {
if err := galleriesPerformersTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.PerformerIDs.List()); err != nil {
return err
}
}
if err := galleriesTagsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.TagIDs); err != nil {
return err
if updatedObject.TagIDs.Loaded() {
if err := galleriesTagsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.TagIDs.List()); err != nil {
return err
}
}
if err := galleriesScenesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.SceneIDs); err != nil {
return err
if updatedObject.SceneIDs.Loaded() {
if err := galleriesScenesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.SceneIDs.List()); err != nil {
return err
}
}
fileIDs := make([]file.ID, len(updatedObject.Files))
@@ -249,16 +261,18 @@ func (qb *GalleryStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*
s := f.resolve()
if err := qb.resolveRelationships(ctx, s); err != nil {
return err
}
ret = append(ret, s)
return nil
}); err != nil {
return nil, err
}
for _, s := range ret {
if err := qb.resolveRelationships(ctx, s); err != nil {
return nil, err
}
}
return ret, nil
}
@@ -281,24 +295,6 @@ func (qb *GalleryStore) resolveRelationships(ctx context.Context, s *models.Gall
s.FolderPath = folder.Path
}
// performers
s.PerformerIDs, err = qb.performersRepository().getIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving gallery performers: %w", err)
}
// tags
s.TagIDs, err = qb.tagsRepository().getIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving gallery tags: %w", err)
}
// scenes
s.SceneIDs, err = qb.scenesRepository().getIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving gallery scenes: %w", err)
}
return nil
}
@@ -989,6 +985,11 @@ func (qb *GalleryStore) filesRepository() *filesRepository {
}
}
func (qb *GalleryStore) AddFileID(ctx context.Context, id int, fileID file.ID) error {
const firstPrimary = false
return galleriesFilesTableMgr.insertJoins(ctx, id, firstPrimary, []file.ID{fileID})
}
func (qb *GalleryStore) performersRepository() *joinRepository {
return &joinRepository{
repository: repository{
@@ -1000,6 +1001,10 @@ func (qb *GalleryStore) performersRepository() *joinRepository {
}
}
func (qb *GalleryStore) GetPerformerIDs(ctx context.Context, id int) ([]int, error) {
return qb.performersRepository().getIDs(ctx, id)
}
func (qb *GalleryStore) tagsRepository() *joinRepository {
return &joinRepository{
repository: repository{
@@ -1011,6 +1016,10 @@ func (qb *GalleryStore) tagsRepository() *joinRepository {
}
}
func (qb *GalleryStore) GetTagIDs(ctx context.Context, id int) ([]int, error) {
return qb.tagsRepository().getIDs(ctx, id)
}
func (qb *GalleryStore) imagesRepository() *joinRepository {
return &joinRepository{
repository: repository{
@@ -1041,3 +1050,7 @@ func (qb *GalleryStore) scenesRepository() *joinRepository {
fkColumn: sceneIDColumn,
}
}
func (qb *GalleryStore) GetSceneIDs(ctx context.Context, id int) ([]int, error) {
return qb.scenesRepository().getIDs(ctx, id)
}

View File

@@ -17,6 +17,26 @@ import (
var invalidID = -1
func loadGalleryRelationships(ctx context.Context, expected models.Gallery, actual *models.Gallery) error {
if expected.SceneIDs.Loaded() {
if err := actual.LoadSceneIDs(ctx, db.Gallery); err != nil {
return err
}
}
if expected.TagIDs.Loaded() {
if err := actual.LoadTagIDs(ctx, db.Gallery); err != nil {
return err
}
}
if expected.PerformerIDs.Loaded() {
if err := actual.LoadPerformerIDs(ctx, db.Gallery); err != nil {
return err
}
}
return nil
}
func Test_galleryQueryBuilder_Create(t *testing.T) {
var (
title = "title"
@@ -48,9 +68,9 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
StudioID: &studioIDs[studioIdxWithScene],
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: []int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
Files: []file.File{},
},
false,
@@ -70,9 +90,9 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: []int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -86,21 +106,21 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
{
"invalid scene id",
models.Gallery{
SceneIDs: []int{invalidID},
SceneIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid tag id",
models.Gallery{
TagIDs: []int{invalidID},
TagIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid performer id",
models.Gallery{
PerformerIDs: []int{invalidID},
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
@@ -132,6 +152,12 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
copy := tt.newObject
copy.ID = s.ID
// load relationships
if err := loadGalleryRelationships(ctx, copy, &s); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(copy, s)
// ensure can find the scene
@@ -144,6 +170,12 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
return
}
// load relationships
if err := loadGalleryRelationships(ctx, copy, found); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(copy, *found)
return
@@ -190,9 +222,9 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: []int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -203,9 +235,9 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithImage),
},
SceneIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -219,9 +251,9 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithScene),
},
SceneIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -235,9 +267,9 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithTag),
},
SceneIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -251,9 +283,9 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithPerformer),
},
SceneIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -282,7 +314,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
makeGalleryFileWithID(galleryIdxWithImage),
},
Organized: true,
SceneIDs: []int{invalidID},
SceneIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
},
@@ -296,7 +328,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
makeGalleryFileWithID(galleryIdxWithImage),
},
Organized: true,
TagIDs: []int{invalidID},
TagIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
},
@@ -310,7 +342,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
makeGalleryFileWithID(galleryIdxWithImage),
},
Organized: true,
PerformerIDs: []int{invalidID},
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
},
@@ -339,6 +371,12 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
return
}
// load relationships
if err := loadGalleryRelationships(ctx, copy, s); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(copy, *s)
return
@@ -426,9 +464,9 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: []int{sceneIDs[sceneIdxWithGallery]},
TagIDs: []int{tagIDs[tagIdx1WithGallery], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithGallery], performerIDs[performerIdx1WithDupName]},
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdxWithGallery]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithGallery], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithGallery], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -441,9 +479,9 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
Files: []file.File{
makeGalleryFile(galleryIdxWithImage),
},
SceneIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -472,6 +510,11 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
}
clearGalleryFileIDs(got)
// load relationships
if err := loadGalleryRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, *got)
s, err := qb.Find(ctx, tt.id)
@@ -480,6 +523,11 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
}
clearGalleryFileIDs(s)
// load relationships
if err := loadGalleryRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, *s)
})
}
@@ -503,10 +551,10 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
SceneIDs: append(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(galleryIdx1WithImage)),
SceneIDs: models.NewRelatedIDs(append(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(galleryIdx1WithImage)),
sceneIDs[sceneIdx1WithStudio],
sceneIDs[sceneIdx1WithPerformer],
),
)),
},
false,
},
@@ -520,10 +568,10 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
TagIDs: append(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
tagIDs[tagIdx1WithDupName],
tagIDs[tagIdx1WithImage],
),
)),
},
false,
},
@@ -537,10 +585,10 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
PerformerIDs: append(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
performerIDs[performerIdx1WithDupName],
performerIDs[performerIdx1WithImage],
),
)),
},
false,
},
@@ -554,9 +602,9 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
SceneIDs: append(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(galleryIdxWithScene)),
SceneIDs: models.NewRelatedIDs(append(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(galleryIdxWithScene)),
sceneIDs[sceneIdx1WithPerformer],
),
)),
},
false,
},
@@ -570,9 +618,9 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
TagIDs: append(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
tagIDs[tagIdx1WithScene],
),
)),
},
false,
},
@@ -586,9 +634,9 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
PerformerIDs: append(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
performerIDs[performerIdx1WithScene],
),
)),
},
false,
},
@@ -638,7 +686,7 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
SceneIDs: []int{},
SceneIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -652,7 +700,7 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
TagIDs: []int{tagIDs[tagIdx2WithGallery]},
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx2WithGallery]}),
},
false,
},
@@ -666,7 +714,7 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
PerformerIDs: []int{performerIDs[performerIdx2WithGallery]},
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx2WithGallery]}),
},
false,
},
@@ -680,7 +728,7 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
SceneIDs: []int{sceneIDs[sceneIdxWithGallery]},
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdxWithGallery]}),
},
false,
},
@@ -694,7 +742,7 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
TagIDs: indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(indexesToIDs(tagIDs, galleryTags[galleryIdxWithTwoTags])),
},
false,
},
@@ -708,7 +756,7 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Gallery{
PerformerIDs: indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(indexesToIDs(performerIDs, galleryPerformers[galleryIdxWithTwoPerformers])),
},
false,
},
@@ -735,6 +783,16 @@ func Test_galleryQueryBuilder_UpdatePartialRelationships(t *testing.T) {
t.Errorf("galleryQueryBuilder.Find() error = %v", err)
}
// load relationships
if err := loadGalleryRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
if err := loadGalleryRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
// only compare fields that were in the partial
if tt.partial.PerformerIDs != nil {
assert.Equal(tt.want.PerformerIDs, got.PerformerIDs)
@@ -851,12 +909,33 @@ func Test_galleryQueryBuilder_Find(t *testing.T) {
if got != nil {
clearGalleryFileIDs(got)
// load relationships
if err := loadGalleryRelationships(ctx, *tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
}
assert.Equal(tt.want, got)
})
}
}
func postFindGalleries(ctx context.Context, want []*models.Gallery, got []*models.Gallery) error {
for i, s := range got {
clearGalleryFileIDs(s)
// load relationships
if i < len(want) {
if err := loadGalleryRelationships(ctx, *want[i], s); err != nil {
return err
}
}
}
return nil
}
func Test_galleryQueryBuilder_FindMany(t *testing.T) {
tests := []struct {
name string
@@ -893,8 +972,9 @@ func Test_galleryQueryBuilder_FindMany(t *testing.T) {
return
}
for _, f := range got {
clearGalleryFileIDs(f)
if err := postFindGalleries(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -950,8 +1030,9 @@ func Test_galleryQueryBuilder_FindByChecksum(t *testing.T) {
return
}
for _, f := range got {
clearGalleryFileIDs(f)
if err := postFindGalleries(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1012,8 +1093,9 @@ func Test_galleryQueryBuilder_FindByChecksums(t *testing.T) {
return
}
for _, f := range got {
clearGalleryFileIDs(f)
if err := postFindGalleries(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1069,8 +1151,9 @@ func Test_galleryQueryBuilder_FindByPath(t *testing.T) {
return
}
for _, f := range got {
clearGalleryFileIDs(f)
if err := postFindGalleries(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1110,8 +1193,9 @@ func Test_galleryQueryBuilder_FindBySceneID(t *testing.T) {
return
}
for _, f := range got {
clearGalleryFileIDs(f)
if err := postFindGalleries(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1154,8 +1238,9 @@ func Test_galleryQueryBuilder_FindByImageID(t *testing.T) {
return
}
for _, f := range got {
clearGalleryFileIDs(f)
if err := postFindGalleries(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -2143,7 +2228,11 @@ func verifyGalleriesTagCount(t *testing.T, tagCountCriterion models.IntCriterion
assert.Greater(t, len(galleries), 0)
for _, gallery := range galleries {
verifyInt(t, len(gallery.TagIDs), tagCountCriterion)
if err := gallery.LoadTagIDs(ctx, sqb); err != nil {
t.Errorf("gallery.LoadTagIDs() error = %v", err)
return nil
}
verifyInt(t, len(gallery.TagIDs.List()), tagCountCriterion)
}
return nil
@@ -2180,7 +2269,12 @@ func verifyGalleriesPerformerCount(t *testing.T, performerCountCriterion models.
assert.Greater(t, len(galleries), 0)
for _, gallery := range galleries {
verifyInt(t, len(gallery.PerformerIDs), performerCountCriterion)
if err := gallery.LoadPerformerIDs(ctx, sqb); err != nil {
t.Errorf("gallery.LoadPerformerIDs() error = %v", err)
return nil
}
verifyInt(t, len(gallery.PerformerIDs.List()), performerCountCriterion)
}
return nil

View File

@@ -116,18 +116,19 @@ func (qb *ImageStore) Create(ctx context.Context, newObject *models.ImageCreateI
}
}
if len(newObject.GalleryIDs) > 0 {
if err := imageGalleriesTableMgr.insertJoins(ctx, id, newObject.GalleryIDs); err != nil {
if newObject.PerformerIDs.Loaded() {
if err := imagesPerformersTableMgr.insertJoins(ctx, id, newObject.PerformerIDs.List()); err != nil {
return err
}
}
if len(newObject.PerformerIDs) > 0 {
if err := imagesPerformersTableMgr.insertJoins(ctx, id, newObject.PerformerIDs); err != nil {
if newObject.TagIDs.Loaded() {
if err := imagesTagsTableMgr.insertJoins(ctx, id, newObject.TagIDs.List()); err != nil {
return err
}
}
if len(newObject.TagIDs) > 0 {
if err := imagesTagsTableMgr.insertJoins(ctx, id, newObject.TagIDs); err != nil {
if newObject.GalleryIDs.Loaded() {
if err := imageGalleriesTableMgr.insertJoins(ctx, id, newObject.GalleryIDs.List()); err != nil {
return err
}
}
@@ -184,14 +185,22 @@ func (qb *ImageStore) Update(ctx context.Context, updatedObject *models.Image) e
return err
}
if err := imageGalleriesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.GalleryIDs); err != nil {
return err
if updatedObject.PerformerIDs.Loaded() {
if err := imagesPerformersTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.PerformerIDs.List()); err != nil {
return err
}
}
if err := imagesPerformersTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.PerformerIDs); err != nil {
return err
if updatedObject.TagIDs.Loaded() {
if err := imagesTagsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.TagIDs.List()); err != nil {
return err
}
}
if err := imagesTagsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.TagIDs); err != nil {
return err
if updatedObject.GalleryIDs.Loaded() {
if err := imageGalleriesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.GalleryIDs.List()); err != nil {
return err
}
}
fileIDs := make([]file.ID, len(updatedObject.Files))
@@ -265,16 +274,18 @@ func (qb *ImageStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
i := f.resolve()
if err := qb.resolveRelationships(ctx, i); err != nil {
return err
}
ret = append(ret, i)
return nil
}); err != nil {
return nil, err
}
for _, i := range ret {
if err := qb.resolveRelationships(ctx, i); err != nil {
return nil, err
}
}
return ret, nil
}
@@ -287,24 +298,6 @@ func (qb *ImageStore) resolveRelationships(ctx context.Context, i *models.Image)
return fmt.Errorf("resolving image files: %w", err)
}
// performers
i.PerformerIDs, err = qb.performersRepository().getIDs(ctx, i.ID)
if err != nil {
return fmt.Errorf("resolving image performers: %w", err)
}
// tags
i.TagIDs, err = qb.tagsRepository().getIDs(ctx, i.ID)
if err != nil {
return fmt.Errorf("resolving image tags: %w", err)
}
// galleries
i.GalleryIDs, err = qb.galleriesRepository().getIDs(ctx, i.ID)
if err != nil {
return fmt.Errorf("resolving image galleries: %w", err)
}
return nil
}
@@ -1004,9 +997,14 @@ func (qb *ImageStore) filesRepository() *filesRepository {
}
}
// func (qb *imageQueryBuilder) GetGalleryIDs(ctx context.Context, imageID int) ([]int, error) {
// return qb.galleriesRepository().getIDs(ctx, imageID)
// }
func (qb *ImageStore) AddFileID(ctx context.Context, id int, fileID file.ID) error {
const firstPrimary = false
return imagesFilesTableMgr.insertJoins(ctx, id, firstPrimary, []file.ID{fileID})
}
func (qb *ImageStore) GetGalleryIDs(ctx context.Context, imageID int) ([]int, error) {
return qb.galleriesRepository().getIDs(ctx, imageID)
}
// func (qb *imageQueryBuilder) UpdateGalleries(ctx context.Context, imageID int, galleryIDs []int) error {
// // Delete the existing joins and then create new ones

View File

@@ -15,6 +15,26 @@ import (
"github.com/stretchr/testify/assert"
)
func loadImageRelationships(ctx context.Context, expected models.Image, actual *models.Image) error {
if expected.GalleryIDs.Loaded() {
if err := actual.LoadGalleryIDs(ctx, db.Image); err != nil {
return err
}
}
if expected.TagIDs.Loaded() {
if err := actual.LoadTagIDs(ctx, db.Image); err != nil {
return err
}
}
if expected.PerformerIDs.Loaded() {
if err := actual.LoadPerformerIDs(ctx, db.Image); err != nil {
return err
}
}
return nil
}
func Test_imageQueryBuilder_Create(t *testing.T) {
var (
title = "title"
@@ -41,9 +61,9 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
StudioID: &studioIDs[studioIdxWithImage],
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithImage]},
TagIDs: []int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]},
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]}),
Files: []*file.ImageFile{},
},
false,
@@ -61,9 +81,9 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithImage]},
TagIDs: []int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]},
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -77,21 +97,21 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
{
"invalid gallery id",
models.Image{
GalleryIDs: []int{invalidID},
GalleryIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid tag id",
models.Image{
TagIDs: []int{invalidID},
TagIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid performer id",
models.Image{
PerformerIDs: []int{invalidID},
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
@@ -126,6 +146,12 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
copy := tt.newObject
copy.ID = s.ID
// load relationships
if err := loadImageRelationships(ctx, copy, &s); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(copy, s)
// ensure can find the image
@@ -134,6 +160,12 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
t.Errorf("imageQueryBuilder.Find() error = %v", err)
}
// load relationships
if err := loadImageRelationships(ctx, copy, found); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(copy, *found)
return
@@ -181,9 +213,9 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithImage]},
TagIDs: []int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]},
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -194,9 +226,9 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -210,9 +242,9 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -226,9 +258,9 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithTag),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -242,9 +274,9 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithPerformer),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Organized: true,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
@@ -273,7 +305,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
makeImageFileWithID(imageIdxWithGallery),
},
Organized: true,
GalleryIDs: []int{invalidID},
GalleryIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
},
@@ -287,7 +319,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
makeImageFileWithID(imageIdxWithGallery),
},
Organized: true,
TagIDs: []int{invalidID},
TagIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
},
@@ -301,7 +333,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
makeImageFileWithID(imageIdxWithGallery),
},
Organized: true,
PerformerIDs: []int{invalidID},
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
},
@@ -329,6 +361,12 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
t.Errorf("imageQueryBuilder.Find() error = %v", err)
}
// load relationships
if err := loadImageRelationships(ctx, copy, s); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(copy, *s)
return
@@ -400,9 +438,9 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithImage]},
TagIDs: []int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]},
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -416,9 +454,9 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
Files: []*file.ImageFile{
makeImageFile(imageIdx1WithGallery),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -447,6 +485,12 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
}
clearImageFileIDs(got)
// load relationships
if err := loadImageRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(tt.want, *got)
s, err := qb.Find(ctx, tt.id)
@@ -455,6 +499,11 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
}
clearImageFileIDs(s)
// load relationships
if err := loadImageRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(tt.want, *s)
})
}
@@ -478,10 +527,10 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
GalleryIDs: append(indexesToIDs(galleryIDs, imageGalleries[imageIdxWithGallery]),
GalleryIDs: models.NewRelatedIDs(append(indexesToIDs(galleryIDs, imageGalleries[imageIdxWithGallery]),
galleryIDs[galleryIdx1WithImage],
galleryIDs[galleryIdx1WithPerformer],
),
)),
},
false,
},
@@ -495,10 +544,10 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
TagIDs: append(indexesToIDs(tagIDs, imageTags[imageIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, imageTags[imageIdxWithTwoTags]),
tagIDs[tagIdx1WithDupName],
tagIDs[tagIdx1WithGallery],
),
)),
},
false,
},
@@ -512,10 +561,10 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
PerformerIDs: append(indexesToIDs(performerIDs, imagePerformers[imageIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, imagePerformers[imageIdxWithTwoPerformers]),
performerIDs[performerIdx1WithDupName],
performerIDs[performerIdx1WithGallery],
),
)),
},
false,
},
@@ -529,9 +578,9 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
GalleryIDs: append(indexesToIDs(galleryIDs, imageGalleries[imageIdxWithGallery]),
GalleryIDs: models.NewRelatedIDs(append(indexesToIDs(galleryIDs, imageGalleries[imageIdxWithGallery]),
galleryIDs[galleryIdx1WithPerformer],
),
)),
},
false,
},
@@ -545,9 +594,9 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
TagIDs: append(indexesToIDs(tagIDs, imageTags[imageIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, imageTags[imageIdxWithTwoTags]),
tagIDs[tagIdx1WithGallery],
),
)),
},
false,
},
@@ -561,9 +610,9 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
PerformerIDs: append(indexesToIDs(performerIDs, imagePerformers[imageIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, imagePerformers[imageIdxWithTwoPerformers]),
performerIDs[performerIdx1WithGallery],
),
)),
},
false,
},
@@ -613,7 +662,7 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
GalleryIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -627,7 +676,7 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
TagIDs: []int{tagIDs[tagIdx2WithImage]},
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx2WithImage]}),
},
false,
},
@@ -641,7 +690,7 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
PerformerIDs: []int{performerIDs[performerIdx2WithImage]},
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx2WithImage]}),
},
false,
},
@@ -655,7 +704,7 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
GalleryIDs: []int{galleryIDs[galleryIdxWithImage]},
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
},
false,
},
@@ -669,7 +718,7 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
TagIDs: indexesToIDs(tagIDs, imageTags[imageIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(indexesToIDs(tagIDs, imageTags[imageIdxWithTwoTags])),
},
false,
},
@@ -683,7 +732,7 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Image{
PerformerIDs: indexesToIDs(performerIDs, imagePerformers[imageIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(indexesToIDs(performerIDs, imagePerformers[imageIdxWithTwoPerformers])),
},
false,
},
@@ -710,6 +759,16 @@ func Test_imageQueryBuilder_UpdatePartialRelationships(t *testing.T) {
t.Errorf("imageQueryBuilder.Find() error = %v", err)
}
// load relationships
if err := loadImageRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
if err := loadImageRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
// only compare fields that were in the partial
if tt.partial.PerformerIDs != nil {
assert.Equal(tt.want.PerformerIDs, got.PerformerIDs)
@@ -944,12 +1003,33 @@ func Test_imageQueryBuilder_Find(t *testing.T) {
if got != nil {
clearImageFileIDs(got)
// load relationships
if err := loadImageRelationships(ctx, *tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
}
assert.Equal(tt.want, got)
})
}
}
func postFindImages(ctx context.Context, want []*models.Image, got []*models.Image) error {
for i, s := range got {
clearImageFileIDs(s)
// load relationships
if i < len(want) {
if err := loadImageRelationships(ctx, *want[i], s); err != nil {
return err
}
}
}
return nil
}
func Test_imageQueryBuilder_FindMany(t *testing.T) {
tests := []struct {
name string
@@ -985,8 +1065,9 @@ func Test_imageQueryBuilder_FindMany(t *testing.T) {
return
}
for _, f := range got {
clearImageFileIDs(f)
if err := postFindImages(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
if !reflect.DeepEqual(got, tt.want) {
@@ -1044,8 +1125,9 @@ func Test_imageQueryBuilder_FindByChecksum(t *testing.T) {
return
}
for _, f := range got {
clearImageFileIDs(f)
if err := postFindImages(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1121,8 +1203,9 @@ func Test_imageQueryBuilder_FindByFingerprints(t *testing.T) {
return
}
for _, f := range got {
clearImageFileIDs(f)
if err := postFindImages(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1162,8 +1245,9 @@ func Test_imageQueryBuilder_FindByGalleryID(t *testing.T) {
return
}
for _, f := range got {
clearImageFileIDs(f)
if err := postFindImages(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)

View File

@@ -6,7 +6,10 @@ import (
"errors"
"fmt"
"github.com/doug-martin/goqu/v9"
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/sliceutil/intslice"
)
const movieTable = "movies"
@@ -66,21 +69,45 @@ func (qb *movieQueryBuilder) Find(ctx context.Context, id int) (*models.Movie, e
}
func (qb *movieQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Movie, error) {
var movies []*models.Movie
for _, id := range ids {
movie, err := qb.Find(ctx, id)
if err != nil {
return nil, err
}
if movie == nil {
return nil, fmt.Errorf("movie with id %d not found", id)
}
movies = append(movies, movie)
tableMgr := movieTableMgr
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
unsorted, err := qb.getMany(ctx, q)
if err != nil {
return nil, err
}
return movies, nil
ret := make([]*models.Movie, len(ids))
for _, s := range unsorted {
i := intslice.IntIndex(ids, s.ID)
ret[i] = s
}
for i := range ret {
if ret[i] == nil {
return nil, fmt.Errorf("movie with id %d not found", ids[i])
}
}
return ret, nil
}
func (qb *movieQueryBuilder) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Movie, error) {
const single = false
var ret []*models.Movie
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f models.Movie
if err := r.StructScan(&f); err != nil {
return err
}
ret = append(ret, &f)
return nil
}); err != nil {
return nil, err
}
return ret, nil
}
func (qb *movieQueryBuilder) FindByName(ctx context.Context, name string, nocase bool) (*models.Movie, error) {
@@ -156,14 +183,9 @@ func (qb *movieQueryBuilder) Query(ctx context.Context, movieFilter *models.Movi
return nil, 0, err
}
var movies []*models.Movie
for _, id := range idsResult {
movie, err := qb.Find(ctx, id)
if err != nil {
return nil, 0, err
}
movies = append(movies, movie)
movies, err := qb.FindMany(ctx, idsResult)
if err != nil {
return nil, 0, err
}
return movies, countResult, nil

View File

@@ -7,7 +7,10 @@ import (
"fmt"
"strings"
"github.com/doug-martin/goqu/v9"
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/sliceutil/intslice"
"github.com/stashapp/stash/pkg/utils"
)
@@ -92,21 +95,45 @@ func (qb *performerQueryBuilder) Find(ctx context.Context, id int) (*models.Perf
}
func (qb *performerQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Performer, error) {
var performers []*models.Performer
for _, id := range ids {
performer, err := qb.Find(ctx, id)
if err != nil {
return nil, err
}
if performer == nil {
return nil, fmt.Errorf("performer with id %d not found", id)
}
performers = append(performers, performer)
tableMgr := performerTableMgr
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
unsorted, err := qb.getMany(ctx, q)
if err != nil {
return nil, err
}
return performers, nil
ret := make([]*models.Performer, len(ids))
for _, s := range unsorted {
i := intslice.IntIndex(ids, s.ID)
ret[i] = s
}
for i := range ret {
if ret[i] == nil {
return nil, fmt.Errorf("performer with id %d not found", ids[i])
}
}
return ret, nil
}
func (qb *performerQueryBuilder) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Performer, error) {
const single = false
var ret []*models.Performer
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f models.Performer
if err := r.StructScan(&f); err != nil {
return err
}
ret = append(ret, &f)
return nil
}); err != nil {
return nil, err
}
return ret, nil
}
func (qb *performerQueryBuilder) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
@@ -324,13 +351,9 @@ func (qb *performerQueryBuilder) Query(ctx context.Context, performerFilter *mod
return nil, 0, err
}
var performers []*models.Performer
for _, id := range idsResult {
performer, err := qb.Find(ctx, id)
if err != nil {
return nil, 0, err
}
performers = append(performers, performer)
performers, err := qb.FindMany(ctx, idsResult)
if err != nil {
return nil, 0, err
}
return performers, countResult, nil
@@ -600,11 +623,11 @@ func (qb *performerQueryBuilder) stashIDRepository() *stashIDRepository {
}
}
func (qb *performerQueryBuilder) GetStashIDs(ctx context.Context, performerID int) ([]*models.StashID, error) {
func (qb *performerQueryBuilder) GetStashIDs(ctx context.Context, performerID int) ([]models.StashID, error) {
return qb.stashIDRepository().get(ctx, performerID)
}
func (qb *performerQueryBuilder) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []*models.StashID) error {
func (qb *performerQueryBuilder) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
return qb.stashIDRepository().replace(ctx, performerID, stashIDs)
}

View File

@@ -441,24 +441,24 @@ type stashIDRepository struct {
repository
}
type stashIDs []*models.StashID
type stashIDs []models.StashID
func (s *stashIDs) Append(o interface{}) {
*s = append(*s, o.(*models.StashID))
*s = append(*s, *o.(*models.StashID))
}
func (s *stashIDs) New() interface{} {
return &models.StashID{}
}
func (r *stashIDRepository) get(ctx context.Context, id int) ([]*models.StashID, error) {
func (r *stashIDRepository) get(ctx context.Context, id int) ([]models.StashID, error) {
query := fmt.Sprintf("SELECT stash_id, endpoint from %s WHERE %s = ?", r.tableName, r.idColumn)
var ret stashIDs
err := r.query(ctx, query, []interface{}{id}, &ret)
return []*models.StashID(ret), err
return []models.StashID(ret), err
}
func (r *stashIDRepository) replace(ctx context.Context, id int, newIDs []*models.StashID) error {
func (r *stashIDRepository) replace(ctx context.Context, id int, newIDs []models.StashID) error {
if err := r.destroy(ctx, []int{id}); err != nil {
return err
}

View File

@@ -157,20 +157,33 @@ func (qb *SceneStore) Create(ctx context.Context, newObject *models.Scene, fileI
}
}
if err := scenesPerformersTableMgr.insertJoins(ctx, id, newObject.PerformerIDs); err != nil {
return err
if newObject.PerformerIDs.Loaded() {
if err := scenesPerformersTableMgr.insertJoins(ctx, id, newObject.PerformerIDs.List()); err != nil {
return err
}
}
if err := scenesTagsTableMgr.insertJoins(ctx, id, newObject.TagIDs); err != nil {
return err
if newObject.TagIDs.Loaded() {
if err := scenesTagsTableMgr.insertJoins(ctx, id, newObject.TagIDs.List()); err != nil {
return err
}
}
if err := scenesGalleriesTableMgr.insertJoins(ctx, id, newObject.GalleryIDs); err != nil {
return err
if newObject.GalleryIDs.Loaded() {
if err := scenesGalleriesTableMgr.insertJoins(ctx, id, newObject.GalleryIDs.List()); err != nil {
return err
}
}
if err := scenesStashIDsTableMgr.insertJoins(ctx, id, newObject.StashIDs); err != nil {
return err
if newObject.StashIDs.Loaded() {
if err := scenesStashIDsTableMgr.insertJoins(ctx, id, newObject.StashIDs.List()); err != nil {
return err
}
}
if err := scenesMoviesTableMgr.insertJoins(ctx, id, newObject.Movies); err != nil {
return err
if newObject.Movies.Loaded() {
if err := scenesMoviesTableMgr.insertJoins(ctx, id, newObject.Movies.List()); err != nil {
return err
}
}
updated, err := qb.find(ctx, id)
@@ -235,20 +248,34 @@ func (qb *SceneStore) Update(ctx context.Context, updatedObject *models.Scene) e
return err
}
if err := scenesPerformersTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.PerformerIDs); err != nil {
return err
if updatedObject.PerformerIDs.Loaded() {
if err := scenesPerformersTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.PerformerIDs.List()); err != nil {
return err
}
}
if err := scenesTagsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.TagIDs); err != nil {
return err
if updatedObject.TagIDs.Loaded() {
if err := scenesTagsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.TagIDs.List()); err != nil {
return err
}
}
if err := scenesGalleriesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.GalleryIDs); err != nil {
return err
if updatedObject.GalleryIDs.Loaded() {
if err := scenesGalleriesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.GalleryIDs.List()); err != nil {
return err
}
}
if err := scenesStashIDsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.StashIDs); err != nil {
return err
if updatedObject.StashIDs.Loaded() {
if err := scenesStashIDsTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.StashIDs.List()); err != nil {
return err
}
}
if err := scenesMoviesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.Movies); err != nil {
return err
if updatedObject.Movies.Loaded() {
if err := scenesMoviesTableMgr.replaceJoins(ctx, updatedObject.ID, updatedObject.Movies.List()); err != nil {
return err
}
}
fileIDs := make([]file.ID, len(updatedObject.Files))
@@ -333,16 +360,18 @@ func (qb *SceneStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
s := f.resolve()
if err := qb.resolveRelationships(ctx, s); err != nil {
return err
}
ret = append(ret, s)
return nil
}); err != nil {
return nil, err
}
for _, s := range ret {
if err := qb.resolveRelationships(ctx, s); err != nil {
return nil, err
}
}
return ret, nil
}
@@ -355,36 +384,6 @@ func (qb *SceneStore) resolveRelationships(ctx context.Context, s *models.Scene)
return fmt.Errorf("resolving scene files: %w", err)
}
// movies
s.Movies, err = qb.getMovies(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving scene movies: %w", err)
}
// performers
s.PerformerIDs, err = qb.performersRepository().getIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving scene performers: %w", err)
}
// tags
s.TagIDs, err = qb.tagsRepository().getIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving scene tags: %w", err)
}
// galleries
s.GalleryIDs, err = qb.galleriesRepository().getIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving scene galleries: %w", err)
}
// stash ids
s.StashIDs, err = qb.getStashIDs(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving scene stash ids: %w", err)
}
return nil
}
@@ -412,37 +411,6 @@ func (qb *SceneStore) getFiles(ctx context.Context, id int) ([]*file.VideoFile,
return ret, nil
}
func (qb *SceneStore) getMovies(ctx context.Context, id int) (ret []models.MoviesScenes, err error) {
ret = []models.MoviesScenes{}
if err := qb.moviesRepository().getAll(ctx, id, func(rows *sqlx.Rows) error {
var ms moviesScenesRow
if err := rows.StructScan(&ms); err != nil {
return err
}
ret = append(ret, ms.resolve(id))
return nil
}); err != nil {
return nil, err
}
return ret, nil
}
func (qb *SceneStore) getStashIDs(ctx context.Context, id int) ([]models.StashID, error) {
stashIDs, err := qb.stashIDRepository().get(ctx, id)
if err != nil {
return nil, err
}
ret := make([]models.StashID, len(stashIDs))
for i, sid := range stashIDs {
ret[i] = *sid
}
return ret, nil
}
func (qb *SceneStore) find(ctx context.Context, id int) (*models.Scene, error) {
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
@@ -1399,6 +1367,24 @@ func (qb *SceneStore) moviesRepository() *repository {
}
}
func (qb *SceneStore) GetMovies(ctx context.Context, id int) (ret []models.MoviesScenes, err error) {
ret = []models.MoviesScenes{}
if err := qb.moviesRepository().getAll(ctx, id, func(rows *sqlx.Rows) error {
var ms moviesScenesRow
if err := rows.StructScan(&ms); err != nil {
return err
}
ret = append(ret, ms.resolve(id))
return nil
}); err != nil {
return nil, err
}
return ret, nil
}
func (qb *SceneStore) filesRepository() *filesRepository {
return &filesRepository{
repository: repository{
@@ -1409,6 +1395,11 @@ func (qb *SceneStore) filesRepository() *filesRepository {
}
}
func (qb *SceneStore) AddFileID(ctx context.Context, id int, fileID file.ID) error {
const firstPrimary = false
return scenesFilesTableMgr.insertJoins(ctx, id, firstPrimary, []file.ID{fileID})
}
func (qb *SceneStore) performersRepository() *joinRepository {
return &joinRepository{
repository: repository{
@@ -1420,6 +1411,10 @@ func (qb *SceneStore) performersRepository() *joinRepository {
}
}
func (qb *SceneStore) GetPerformerIDs(ctx context.Context, id int) ([]int, error) {
return qb.performersRepository().getIDs(ctx, id)
}
func (qb *SceneStore) tagsRepository() *joinRepository {
return &joinRepository{
repository: repository{
@@ -1431,6 +1426,10 @@ func (qb *SceneStore) tagsRepository() *joinRepository {
}
}
func (qb *SceneStore) GetTagIDs(ctx context.Context, id int) ([]int, error) {
return qb.tagsRepository().getIDs(ctx, id)
}
func (qb *SceneStore) galleriesRepository() *joinRepository {
return &joinRepository{
repository: repository{
@@ -1442,6 +1441,14 @@ func (qb *SceneStore) galleriesRepository() *joinRepository {
}
}
func (qb *SceneStore) GetGalleryIDs(ctx context.Context, id int) ([]int, error) {
return qb.galleriesRepository().getIDs(ctx, id)
}
func (qb *SceneStore) AddGalleryIDs(ctx context.Context, sceneID int, galleryIDs []int) error {
return scenesGalleriesTableMgr.addJoins(ctx, sceneID, galleryIDs)
}
func (qb *SceneStore) stashIDRepository() *stashIDRepository {
return &stashIDRepository{
repository{
@@ -1452,6 +1459,10 @@ func (qb *SceneStore) stashIDRepository() *stashIDRepository {
}
}
func (qb *SceneStore) GetStashIDs(ctx context.Context, sceneID int) ([]models.StashID, error) {
return qb.stashIDRepository().get(ctx, sceneID)
}
func (qb *SceneStore) FindDuplicates(ctx context.Context, distance int) ([][]*models.Scene, error) {
var dupeIds [][]int
if distance == 0 {

View File

@@ -157,7 +157,13 @@ func TestMarkerQuerySceneTags(t *testing.T) {
t.Errorf("error getting marker tag ids: %v", err)
return
}
tagIDs := s.TagIDs
if err := s.LoadTagIDs(ctx, db.Scene); err != nil {
t.Errorf("error getting marker tag ids: %v", err)
return
}
tagIDs := s.TagIDs.List()
if markerFilter.SceneTags.Modifier == models.CriterionModifierIsNull && len(tagIDs) > 0 {
t.Errorf("expected marker %d to have no scene tags - found %d", m.ID, len(tagIDs))
}

View File

@@ -21,6 +21,36 @@ import (
"github.com/stretchr/testify/assert"
)
func loadSceneRelationships(ctx context.Context, expected models.Scene, actual *models.Scene) error {
if expected.GalleryIDs.Loaded() {
if err := actual.LoadGalleryIDs(ctx, db.Scene); err != nil {
return err
}
}
if expected.TagIDs.Loaded() {
if err := actual.LoadTagIDs(ctx, db.Scene); err != nil {
return err
}
}
if expected.PerformerIDs.Loaded() {
if err := actual.LoadPerformerIDs(ctx, db.Scene); err != nil {
return err
}
}
if expected.Movies.Loaded() {
if err := actual.LoadMovies(ctx, db.Scene); err != nil {
return err
}
}
if expected.StashIDs.Loaded() {
if err := actual.LoadStashIDs(ctx, db.Scene); err != nil {
return err
}
}
return nil
}
func Test_sceneQueryBuilder_Create(t *testing.T) {
var (
title = "title"
@@ -60,10 +90,10 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
StudioID: &studioIDs[studioIdxWithScene],
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithScene]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
Movies: []models.MoviesScenes{
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: movieIDs[movieIdxWithScene],
SceneIndex: &sceneIndex,
@@ -72,8 +102,8 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
MovieID: movieIDs[movieIdxWithStudio],
SceneIndex: &sceneIndex2,
},
},
StashIDs: []models.StashID{
}),
StashIDs: models.NewRelatedStashIDs([]models.StashID{
{
StashID: stashID1,
Endpoint: endpoint1,
@@ -82,7 +112,7 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
StashID: stashID2,
Endpoint: endpoint2,
},
},
}),
Files: []*file.VideoFile{},
},
false,
@@ -103,10 +133,10 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithScene]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
Movies: []models.MoviesScenes{
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: movieIDs[movieIdxWithScene],
SceneIndex: &sceneIndex,
@@ -115,8 +145,8 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
MovieID: movieIDs[movieIdxWithStudio],
SceneIndex: &sceneIndex2,
},
},
StashIDs: []models.StashID{
}),
StashIDs: models.NewRelatedStashIDs([]models.StashID{
{
StashID: stashID1,
Endpoint: endpoint1,
@@ -125,7 +155,7 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
StashID: stashID2,
Endpoint: endpoint2,
},
},
}),
},
false,
},
@@ -139,33 +169,33 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
{
"invalid gallery id",
models.Scene{
GalleryIDs: []int{invalidID},
GalleryIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid tag id",
models.Scene{
TagIDs: []int{invalidID},
TagIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid performer id",
models.Scene{
PerformerIDs: []int{invalidID},
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
{
"invalid movie id",
models.Scene{
Movies: []models.MoviesScenes{
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: invalidID,
SceneIndex: &sceneIndex,
},
},
}),
},
true,
},
@@ -197,6 +227,12 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
copy := tt.newObject
copy.ID = s.ID
// load relationships
if err := loadSceneRelationships(ctx, copy, &s); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(copy, s)
// ensure can find the scene
@@ -208,6 +244,12 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
if !assert.NotNil(found) {
return
}
// load relationships
if err := loadSceneRelationships(ctx, copy, found); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(copy, *found)
return
@@ -268,10 +310,10 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
StudioID: &studioIDs[studioIdxWithScene],
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithScene]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
Movies: []models.MoviesScenes{
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: movieIDs[movieIdxWithScene],
SceneIndex: &sceneIndex,
@@ -280,8 +322,8 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
MovieID: movieIDs[movieIdxWithStudio],
SceneIndex: &sceneIndex2,
},
},
StashIDs: []models.StashID{
}),
StashIDs: models.NewRelatedStashIDs([]models.StashID{
{
StashID: stashID1,
Endpoint: endpoint1,
@@ -290,7 +332,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
StashID: stashID2,
Endpoint: endpoint2,
},
},
}),
},
false,
},
@@ -301,11 +343,11 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithSpacedName),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
Movies: []models.MoviesScenes{},
StashIDs: []models.StashID{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
StashIDs: models.NewRelatedStashIDs([]models.StashID{}),
},
false,
},
@@ -316,11 +358,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
Movies: []models.MoviesScenes{},
StashIDs: []models.StashID{},
GalleryIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -331,11 +369,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithTag),
},
TagIDs: []int{},
GalleryIDs: []int{},
PerformerIDs: []int{},
Movies: []models.MoviesScenes{},
StashIDs: []models.StashID{},
TagIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -346,11 +380,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithPerformer),
},
PerformerIDs: []int{},
TagIDs: []int{},
GalleryIDs: []int{},
Movies: []models.MoviesScenes{},
StashIDs: []models.StashID{},
PerformerIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -361,11 +391,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithMovie),
},
Movies: []models.MoviesScenes{},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
StashIDs: []models.StashID{},
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
},
false,
},
@@ -376,12 +402,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
StudioID: &invalidID,
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
Movies: []models.MoviesScenes{},
StashIDs: []models.StashID{},
StudioID: &invalidID,
},
true,
},
@@ -392,7 +413,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
GalleryIDs: []int{invalidID},
GalleryIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
@@ -403,7 +424,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
TagIDs: []int{invalidID},
TagIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
@@ -414,7 +435,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
PerformerIDs: []int{invalidID},
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
},
@@ -425,12 +446,12 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithSpacedName),
},
Movies: []models.MoviesScenes{
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: invalidID,
SceneIndex: &sceneIndex,
},
},
}),
},
true,
},
@@ -456,6 +477,12 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
t.Errorf("sceneQueryBuilder.Find() error = %v", err)
}
// load relationships
if err := loadSceneRelationships(ctx, copy, s); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(copy, *s)
})
}
@@ -571,10 +598,10 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
StudioID: &studioIDs[studioIdxWithScene],
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: []int{galleryIDs[galleryIdxWithScene]},
TagIDs: []int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]},
PerformerIDs: []int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]},
Movies: []models.MoviesScenes{
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithScene], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithScene], performerIDs[performerIdx1WithDupName]}),
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: movieIDs[movieIdxWithScene],
SceneIndex: &sceneIndex,
@@ -583,8 +610,8 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
MovieID: movieIDs[movieIdxWithStudio],
SceneIndex: &sceneIndex2,
},
},
StashIDs: []models.StashID{
}),
StashIDs: models.NewRelatedStashIDs([]models.StashID{
{
StashID: stashID1,
Endpoint: endpoint1,
@@ -593,7 +620,7 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
StashID: stashID2,
Endpoint: endpoint2,
},
},
}),
},
false,
},
@@ -606,11 +633,11 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
Files: []*file.VideoFile{
makeSceneFile(sceneIdxWithSpacedName),
},
GalleryIDs: []int{},
TagIDs: []int{},
PerformerIDs: []int{},
Movies: []models.MoviesScenes{},
StashIDs: []models.StashID{},
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
StashIDs: models.NewRelatedStashIDs([]models.StashID{}),
},
false,
},
@@ -641,6 +668,12 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
// ignore file ids
clearSceneFileIDs(got)
// load relationships
if err := loadSceneRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(tt.want, *got)
s, err := qb.Find(ctx, tt.id)
@@ -651,6 +684,12 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
// ignore file ids
clearSceneFileIDs(s)
// load relationships
if err := loadSceneRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(tt.want, *s)
})
}
@@ -705,10 +744,10 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
GalleryIDs: append(indexesToIDs(galleryIDs, sceneGalleries[sceneIdxWithGallery]),
GalleryIDs: models.NewRelatedIDs(append(indexesToIDs(galleryIDs, sceneGalleries[sceneIdxWithGallery]),
galleryIDs[galleryIdx1WithImage],
galleryIDs[galleryIdx1WithPerformer],
),
)),
},
false,
},
@@ -722,10 +761,10 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
TagIDs: append(indexesToIDs(tagIDs, sceneTags[sceneIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, sceneTags[sceneIdxWithTwoTags]),
tagIDs[tagIdx1WithDupName],
tagIDs[tagIdx1WithGallery],
),
)),
},
false,
},
@@ -739,10 +778,10 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
PerformerIDs: append(indexesToIDs(performerIDs, scenePerformers[sceneIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, scenePerformers[sceneIdxWithTwoPerformers]),
performerIDs[performerIdx1WithDupName],
performerIDs[performerIdx1WithGallery],
),
)),
},
false,
},
@@ -756,11 +795,11 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
Movies: append([]models.MoviesScenes{
Movies: models.NewRelatedMovies(append([]models.MoviesScenes{
{
MovieID: indexesToIDs(movieIDs, sceneMovies[sceneIdxWithMovie])[0],
},
}, movieScenes...),
}, movieScenes...)),
},
false,
},
@@ -774,7 +813,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
StashIDs: append([]models.StashID{sceneStashID(sceneIdxWithSpacedName)}, stashIDs...),
StashIDs: models.NewRelatedStashIDs(append([]models.StashID{sceneStashID(sceneIdxWithSpacedName)}, stashIDs...)),
},
false,
},
@@ -788,9 +827,9 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
GalleryIDs: append(indexesToIDs(galleryIDs, sceneGalleries[sceneIdxWithGallery]),
GalleryIDs: models.NewRelatedIDs(append(indexesToIDs(galleryIDs, sceneGalleries[sceneIdxWithGallery]),
galleryIDs[galleryIdx1WithPerformer],
),
)),
},
false,
},
@@ -804,9 +843,9 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
TagIDs: append(indexesToIDs(tagIDs, sceneTags[sceneIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(append(indexesToIDs(tagIDs, sceneTags[sceneIdxWithTwoTags]),
tagIDs[tagIdx1WithGallery],
),
)),
},
false,
},
@@ -820,9 +859,9 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
PerformerIDs: append(indexesToIDs(performerIDs, scenePerformers[sceneIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(append(indexesToIDs(performerIDs, scenePerformers[sceneIdxWithTwoPerformers]),
performerIDs[performerIdx1WithGallery],
),
)),
},
false,
},
@@ -843,11 +882,11 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
Movies: append([]models.MoviesScenes{
Movies: models.NewRelatedMovies(append([]models.MoviesScenes{
{
MovieID: indexesToIDs(movieIDs, sceneMovies[sceneIdxWithMovie])[0],
},
}, movieScenes...),
}, movieScenes...)),
},
false,
},
@@ -863,7 +902,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
StashIDs: []models.StashID{sceneStashID(sceneIdxWithSpacedName)},
StashIDs: models.NewRelatedStashIDs([]models.StashID{sceneStashID(sceneIdxWithSpacedName)}),
},
false,
},
@@ -929,7 +968,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
GalleryIDs: []int{},
GalleryIDs: models.NewRelatedIDs([]int{}),
},
false,
},
@@ -943,7 +982,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
TagIDs: []int{tagIDs[tagIdx2WithScene]},
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx2WithScene]}),
},
false,
},
@@ -957,7 +996,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
PerformerIDs: []int{performerIDs[performerIdx2WithScene]},
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx2WithScene]}),
},
false,
},
@@ -975,7 +1014,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
Movies: []models.MoviesScenes{},
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
},
false,
},
@@ -989,7 +1028,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
StashIDs: []models.StashID{},
StashIDs: models.NewRelatedStashIDs([]models.StashID{}),
},
false,
},
@@ -1003,7 +1042,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
GalleryIDs: []int{galleryIDs[galleryIdxWithScene]},
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
},
false,
},
@@ -1017,7 +1056,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
TagIDs: indexesToIDs(tagIDs, sceneTags[sceneIdxWithTwoTags]),
TagIDs: models.NewRelatedIDs(indexesToIDs(tagIDs, sceneTags[sceneIdxWithTwoTags])),
},
false,
},
@@ -1031,7 +1070,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
PerformerIDs: indexesToIDs(performerIDs, scenePerformers[sceneIdxWithTwoPerformers]),
PerformerIDs: models.NewRelatedIDs(indexesToIDs(performerIDs, scenePerformers[sceneIdxWithTwoPerformers])),
},
false,
},
@@ -1049,11 +1088,11 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
Movies: []models.MoviesScenes{
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: indexesToIDs(movieIDs, sceneMovies[sceneIdxWithMovie])[0],
},
},
}),
},
false,
},
@@ -1067,7 +1106,7 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
},
},
models.Scene{
StashIDs: []models.StashID{sceneStashID(sceneIdxWithGallery)},
StashIDs: models.NewRelatedStashIDs([]models.StashID{sceneStashID(sceneIdxWithGallery)}),
},
false,
},
@@ -1094,6 +1133,16 @@ func Test_sceneQueryBuilder_UpdatePartialRelationships(t *testing.T) {
t.Errorf("sceneQueryBuilder.Find() error = %v", err)
}
// load relationships
if err := loadSceneRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
if err := loadSceneRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
// only compare fields that were in the partial
if tt.partial.PerformerIDs != nil {
assert.Equal(tt.want.PerformerIDs, got.PerformerIDs)
@@ -1353,6 +1402,12 @@ func Test_sceneQueryBuilder_Find(t *testing.T) {
if got != nil {
clearSceneFileIDs(got)
// load relationships
if err := loadSceneRelationships(ctx, *tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return nil
}
}
assert.Equal(tt.want, got)
@@ -1362,6 +1417,21 @@ func Test_sceneQueryBuilder_Find(t *testing.T) {
}
}
func postFindScenes(ctx context.Context, want []*models.Scene, got []*models.Scene) error {
for i, s := range got {
clearSceneFileIDs(s)
// load relationships
if i < len(want) {
if err := loadSceneRelationships(ctx, *want[i], s); err != nil {
return err
}
}
}
return nil
}
func Test_sceneQueryBuilder_FindMany(t *testing.T) {
tests := []struct {
name string
@@ -1404,8 +1474,9 @@ func Test_sceneQueryBuilder_FindMany(t *testing.T) {
return
}
for _, s := range got {
clearSceneFileIDs(s)
if err := postFindScenes(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -1474,8 +1545,9 @@ func Test_sceneQueryBuilder_FindByChecksum(t *testing.T) {
return nil
}
for _, s := range got {
clearSceneFileIDs(s)
if err := postFindScenes(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return nil
}
assert.Equal(tt.want, got)
@@ -1546,8 +1618,9 @@ func Test_sceneQueryBuilder_FindByOSHash(t *testing.T) {
return nil
}
for _, s := range got {
clearSceneFileIDs(s)
if err := postFindScenes(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return nil
}
if !reflect.DeepEqual(got, tt.want) {
@@ -1620,8 +1693,9 @@ func Test_sceneQueryBuilder_FindByPath(t *testing.T) {
return nil
}
for _, s := range got {
clearSceneFileIDs(s)
if err := postFindScenes(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return nil
}
assert.Equal(tt.want, got)
@@ -1664,8 +1738,9 @@ func Test_sceneQueryBuilder_FindByGalleryID(t *testing.T) {
return
}
for _, s := range got {
clearSceneFileIDs(s)
if err := postFindScenes(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
assert.Equal(tt.want, got)
@@ -3539,7 +3614,11 @@ func verifyScenesTagCount(t *testing.T, tagCountCriterion models.IntCriterionInp
assert.Greater(t, len(scenes), 0)
for _, scene := range scenes {
verifyInt(t, len(scene.TagIDs), tagCountCriterion)
if err := scene.LoadTagIDs(ctx, sqb); err != nil {
t.Errorf("scene.LoadTagIDs() error = %v", err)
return nil
}
verifyInt(t, len(scene.TagIDs.List()), tagCountCriterion)
}
return nil
@@ -3576,7 +3655,12 @@ func verifyScenesPerformerCount(t *testing.T, performerCountCriterion models.Int
assert.Greater(t, len(scenes), 0)
for _, scene := range scenes {
verifyInt(t, len(scene.PerformerIDs), performerCountCriterion)
if err := scene.LoadPerformerIDs(ctx, sqb); err != nil {
t.Errorf("scene.LoadPerformerIDs() error = %v", err)
return nil
}
verifyInt(t, len(scene.PerformerIDs.List()), performerCountCriterion)
}
return nil
@@ -3776,6 +3860,10 @@ func TestSceneStashIDs(t *testing.T) {
return fmt.Errorf("Error creating scene: %s", err.Error())
}
if err := scene.LoadStashIDs(ctx, qb); err != nil {
return err
}
testSceneStashIDs(ctx, t, scene)
return nil
}); err != nil {
@@ -3785,7 +3873,7 @@ func TestSceneStashIDs(t *testing.T) {
func testSceneStashIDs(ctx context.Context, t *testing.T, s *models.Scene) {
// ensure no stash IDs to begin with
assert.Len(t, s.StashIDs, 0)
assert.Len(t, s.StashIDs.List(), 0)
// add stash ids
const stashIDStr = "stashID"
@@ -3809,7 +3897,12 @@ func testSceneStashIDs(ctx context.Context, t *testing.T, s *models.Scene) {
t.Error(err.Error())
}
assert.Equal(t, []models.StashID{stashID}, s.StashIDs)
if err := s.LoadStashIDs(ctx, qb); err != nil {
t.Error(err.Error())
return
}
assert.Equal(t, []models.StashID{stashID}, s.StashIDs.List())
// remove stash ids and ensure was updated
s, err = qb.UpdatePartial(ctx, s.ID, models.ScenePartial{
@@ -3822,7 +3915,12 @@ func testSceneStashIDs(ctx context.Context, t *testing.T, s *models.Scene) {
t.Error(err.Error())
}
assert.Len(t, s.StashIDs, 0)
if err := s.LoadStashIDs(ctx, qb); err != nil {
t.Error(err.Error())
return
}
assert.Len(t, s.StashIDs.List(), 0)
}
func TestSceneQueryQTrim(t *testing.T) {

View File

@@ -975,13 +975,13 @@ func makeScene(i int) *models.Scene {
OCounter: getOCounter(i),
Date: getObjectDateObject(i),
StudioID: studioID,
GalleryIDs: gids,
PerformerIDs: pids,
TagIDs: tids,
Movies: movies,
StashIDs: []models.StashID{
GalleryIDs: models.NewRelatedIDs(gids),
PerformerIDs: models.NewRelatedIDs(pids),
TagIDs: models.NewRelatedIDs(tids),
Movies: models.NewRelatedMovies(movies),
StashIDs: models.NewRelatedStashIDs([]models.StashID{
sceneStashID(i),
},
}),
}
}
@@ -1051,9 +1051,9 @@ func makeImage(i int) *models.Image {
Rating: getIntPtr(getRating(i)),
OCounter: getOCounter(i),
StudioID: studioID,
GalleryIDs: gids,
PerformerIDs: pids,
TagIDs: tids,
GalleryIDs: models.NewRelatedIDs(gids),
PerformerIDs: models.NewRelatedIDs(pids),
TagIDs: models.NewRelatedIDs(tids),
}
}
@@ -1135,12 +1135,12 @@ func makeGallery(i int, includeScenes bool) *models.Gallery {
Rating: getIntPtr(getRating(i)),
Date: getObjectDateObject(i),
StudioID: studioID,
PerformerIDs: pids,
TagIDs: tids,
PerformerIDs: models.NewRelatedIDs(pids),
TagIDs: models.NewRelatedIDs(tids),
}
if includeScenes {
ret.SceneIDs = indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(i))
ret.SceneIDs = models.NewRelatedIDs(indexesToIDs(sceneIDs, sceneGalleries.reverseLookup(i)))
}
return ret

View File

@@ -12,8 +12,8 @@ import (
)
type stashIDReaderWriter interface {
GetStashIDs(ctx context.Context, performerID int) ([]*models.StashID, error)
UpdateStashIDs(ctx context.Context, performerID int, stashIDs []*models.StashID) error
GetStashIDs(ctx context.Context, performerID int) ([]models.StashID, error)
UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error
}
func testStashIDReaderWriter(ctx context.Context, t *testing.T, r stashIDReaderWriter, id int) {
@@ -26,25 +26,25 @@ func testStashIDReaderWriter(ctx context.Context, t *testing.T, r stashIDReaderW
// add stash ids
const stashIDStr = "stashID"
const endpoint = "endpoint"
stashID := &models.StashID{
stashID := models.StashID{
StashID: stashIDStr,
Endpoint: endpoint,
}
// update stash ids and ensure was updated
if err := r.UpdateStashIDs(ctx, id, []*models.StashID{stashID}); err != nil {
if err := r.UpdateStashIDs(ctx, id, []models.StashID{stashID}); err != nil {
t.Error(err.Error())
}
testStashIDs(ctx, t, r, id, []*models.StashID{stashID})
testStashIDs(ctx, t, r, id, []models.StashID{stashID})
// update non-existing id - should return error
if err := r.UpdateStashIDs(ctx, -1, []*models.StashID{stashID}); err == nil {
if err := r.UpdateStashIDs(ctx, -1, []models.StashID{stashID}); err == nil {
t.Error("expected error when updating non-existing id")
}
// remove stash ids and ensure was updated
if err := r.UpdateStashIDs(ctx, id, []*models.StashID{}); err != nil {
if err := r.UpdateStashIDs(ctx, id, []models.StashID{}); err != nil {
t.Error(err.Error())
}
@@ -62,7 +62,7 @@ func testNoStashIDs(ctx context.Context, t *testing.T, r stashIDReaderWriter, id
assert.Len(t, stashIDs, 0)
}
func testStashIDs(ctx context.Context, t *testing.T, r stashIDReaderWriter, id int, expected []*models.StashID) {
func testStashIDs(ctx context.Context, t *testing.T, r stashIDReaderWriter, id int, expected []models.StashID) {
t.Helper()
stashIDs, err := r.GetStashIDs(ctx, id)
if err != nil {

View File

@@ -7,7 +7,10 @@ import (
"fmt"
"strings"
"github.com/doug-martin/goqu/v9"
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/sliceutil/intslice"
)
const studioTable = "studios"
@@ -76,21 +79,45 @@ func (qb *studioQueryBuilder) Find(ctx context.Context, id int) (*models.Studio,
}
func (qb *studioQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Studio, error) {
var studios []*models.Studio
for _, id := range ids {
studio, err := qb.Find(ctx, id)
if err != nil {
return nil, err
}
if studio == nil {
return nil, fmt.Errorf("studio with id %d not found", id)
}
studios = append(studios, studio)
tableMgr := studioTableMgr
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
unsorted, err := qb.getMany(ctx, q)
if err != nil {
return nil, err
}
return studios, nil
ret := make([]*models.Studio, len(ids))
for _, s := range unsorted {
i := intslice.IntIndex(ids, s.ID)
ret[i] = s
}
for i := range ret {
if ret[i] == nil {
return nil, fmt.Errorf("studio with id %d not found", ids[i])
}
}
return ret, nil
}
func (qb *studioQueryBuilder) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Studio, error) {
const single = false
var ret []*models.Studio
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f models.Studio
if err := r.StructScan(&f); err != nil {
return err
}
ret = append(ret, &f)
return nil
}); err != nil {
return nil, err
}
return ret, nil
}
func (qb *studioQueryBuilder) FindChildren(ctx context.Context, id int) ([]*models.Studio, error) {
@@ -258,14 +285,9 @@ func (qb *studioQueryBuilder) Query(ctx context.Context, studioFilter *models.St
return nil, 0, err
}
var studios []*models.Studio
for _, id := range idsResult {
studio, err := qb.Find(ctx, id)
if err != nil {
return nil, 0, err
}
studios = append(studios, studio)
studios, err := qb.FindMany(ctx, idsResult)
if err != nil {
return nil, 0, err
}
return studios, countResult, nil
@@ -425,11 +447,11 @@ func (qb *studioQueryBuilder) stashIDRepository() *stashIDRepository {
}
}
func (qb *studioQueryBuilder) GetStashIDs(ctx context.Context, studioID int) ([]*models.StashID, error) {
func (qb *studioQueryBuilder) GetStashIDs(ctx context.Context, studioID int) ([]models.StashID, error) {
return qb.stashIDRepository().get(ctx, studioID)
}
func (qb *studioQueryBuilder) UpdateStashIDs(ctx context.Context, studioID int, stashIDs []*models.StashID) error {
func (qb *studioQueryBuilder) UpdateStashIDs(ctx context.Context, studioID int, stashIDs []models.StashID) error {
return qb.stashIDRepository().replace(ctx, studioID, stashIDs)
}

View File

@@ -69,6 +69,14 @@ func (t *table) byID(id interface{}) exp.Expression {
return t.idColumn.Eq(id)
}
func (t *table) byIDInts(ids ...int) exp.Expression {
ii := make([]interface{}, len(ids))
for i, id := range ids {
ii[i] = id
}
return t.idColumn.In(ii...)
}
func (t *table) idExists(ctx context.Context, id interface{}) (bool, error) {
q := dialect.Select(goqu.COUNT("*")).From(t.table).Where(t.byID(id))

View File

@@ -174,3 +174,31 @@ var (
idColumn: goqu.T(fingerprintTable).Col(idColumn),
}
)
var (
performerTableMgr = &table{
table: goqu.T(performerTable),
idColumn: goqu.T(performerTable).Col(idColumn),
}
)
var (
studioTableMgr = &table{
table: goqu.T(studioTable),
idColumn: goqu.T(studioTable).Col(idColumn),
}
)
var (
tagTableMgr = &table{
table: goqu.T(tagTable),
idColumn: goqu.T(tagTable).Col(idColumn),
}
)
var (
movieTableMgr = &table{
table: goqu.T(movieTable),
idColumn: goqu.T(movieTable).Col(idColumn),
}
)

View File

@@ -7,7 +7,10 @@ import (
"fmt"
"strings"
"github.com/doug-martin/goqu/v9"
"github.com/jmoiron/sqlx"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/sliceutil/intslice"
)
const tagTable = "tags"
@@ -94,21 +97,45 @@ func (qb *tagQueryBuilder) Find(ctx context.Context, id int) (*models.Tag, error
}
func (qb *tagQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Tag, error) {
var tags []*models.Tag
for _, id := range ids {
tag, err := qb.Find(ctx, id)
if err != nil {
return nil, err
}
if tag == nil {
return nil, fmt.Errorf("tag with id %d not found", id)
}
tags = append(tags, tag)
tableMgr := tagTableMgr
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
unsorted, err := qb.getMany(ctx, q)
if err != nil {
return nil, err
}
return tags, nil
ret := make([]*models.Tag, len(ids))
for _, s := range unsorted {
i := intslice.IntIndex(ids, s.ID)
ret[i] = s
}
for i := range ret {
if ret[i] == nil {
return nil, fmt.Errorf("tag with id %d not found", ids[i])
}
}
return ret, nil
}
func (qb *tagQueryBuilder) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Tag, error) {
const single = false
var ret []*models.Tag
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f models.Tag
if err := r.StructScan(&f); err != nil {
return err
}
ret = append(ret, &f)
return nil
}); err != nil {
return nil, err
}
return ret, nil
}
func (qb *tagQueryBuilder) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Tag, error) {
@@ -343,13 +370,9 @@ func (qb *tagQueryBuilder) Query(ctx context.Context, tagFilter *models.TagFilte
return nil, 0, err
}
var tags []*models.Tag
for _, id := range idsResult {
tag, err := qb.Find(ctx, id)
if err != nil {
return nil, 0, err
}
tags = append(tags, tag)
tags, err := qb.FindMany(ctx, idsResult)
if err != nil {
return nil, 0, err
}
return tags, countResult, nil

View File

@@ -961,7 +961,10 @@ func TestTagMerge(t *testing.T) {
if err != nil {
return err
}
sceneTagIDs := s.TagIDs
if err := s.LoadTagIDs(ctx, db.Scene); err != nil {
return err
}
sceneTagIDs := s.TagIDs.List()
assert.Contains(sceneTagIDs, destID)
@@ -993,8 +996,12 @@ func TestTagMerge(t *testing.T) {
return err
}
if err := g.LoadTagIDs(ctx, db.Gallery); err != nil {
return err
}
// ensure gallery points to new tag
assert.Contains(g.TagIDs, destID)
assert.Contains(g.TagIDs.List(), destID)
// ensure performer points to new tag
performerTagIDs, err := sqlite.PerformerReaderWriter.GetTagIDs(ctx, performerIDs[performerIdxWithTwoTags])