[Files Refactor] Performance tuning (#2865)

* Don't load image files by default
* Don't load gallery files by default
* Don't load scene files by default
* Retry locked transactions forever
* Don't show release notes if config not loaded
* Don't translate path slashes in export
This commit is contained in:
WithoutPants
2022-09-01 17:54:34 +10:00
parent 0b534d89c6
commit 273cf0383d
94 changed files with 2611 additions and 981 deletions

View File

@@ -60,21 +60,38 @@ func (r *galleryRow) fromGallery(o models.Gallery) {
r.UpdatedAt = o.UpdatedAt
}
func (r *galleryRow) resolve() *models.Gallery {
return &models.Gallery{
ID: r.ID,
Title: r.Title.String,
URL: r.URL.String,
Date: r.Date.DatePtr(),
Details: r.Details.String,
Rating: nullIntPtr(r.Rating),
Organized: r.Organized,
StudioID: nullIntPtr(r.StudioID),
FolderID: nullIntFolderIDPtr(r.FolderID),
// FolderPath: r.FolderPath.String,
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
type galleryQueryRow struct {
galleryRow
FolderPath zero.String `db:"folder_path"`
PrimaryFileID null.Int `db:"primary_file_id"`
PrimaryFileFolderPath zero.String `db:"primary_file_folder_path"`
PrimaryFileBasename zero.String `db:"primary_file_basename"`
PrimaryFileChecksum zero.String `db:"primary_file_checksum"`
}
func (r *galleryQueryRow) resolve() *models.Gallery {
ret := &models.Gallery{
ID: r.ID,
Title: r.Title.String,
URL: r.URL.String,
Date: r.Date.DatePtr(),
Details: r.Details.String,
Rating: nullIntPtr(r.Rating),
Organized: r.Organized,
StudioID: nullIntPtr(r.StudioID),
FolderID: nullIntFolderIDPtr(r.FolderID),
PrimaryFileID: nullIntFileIDPtr(r.PrimaryFileID),
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
}
if r.PrimaryFileFolderPath.Valid && r.PrimaryFileBasename.Valid {
ret.Path = filepath.Join(r.PrimaryFileFolderPath.String, r.PrimaryFileBasename.String)
} else if r.FolderPath.Valid {
ret.Path = r.FolderPath.String
}
return ret
}
type galleryRowRecord struct {
@@ -184,13 +201,15 @@ func (qb *GalleryStore) Update(ctx context.Context, updatedObject *models.Galler
}
}
fileIDs := make([]file.ID, len(updatedObject.Files))
for i, f := range updatedObject.Files {
fileIDs[i] = f.Base().ID
}
if updatedObject.Files.Loaded() {
fileIDs := make([]file.ID, len(updatedObject.Files.List()))
for i, f := range updatedObject.Files.List() {
fileIDs[i] = f.Base().ID
}
if err := galleriesFilesTableMgr.replaceJoins(ctx, updatedObject.ID, fileIDs); err != nil {
return err
if err := galleriesFilesTableMgr.replaceJoins(ctx, updatedObject.ID, fileIDs); err != nil {
return err
}
}
return nil
@@ -235,7 +254,33 @@ func (qb *GalleryStore) Destroy(ctx context.Context, id int) error {
}
func (qb *GalleryStore) selectDataset() *goqu.SelectDataset {
return dialect.From(qb.table()).Select(qb.table().All())
table := qb.table()
files := fileTableMgr.table
folders := folderTableMgr.table
galleryFolder := folderTableMgr.table.As("gallery_folder")
return dialect.From(table).LeftJoin(
galleriesFilesJoinTable,
goqu.On(
galleriesFilesJoinTable.Col(galleryIDColumn).Eq(table.Col(idColumn)),
galleriesFilesJoinTable.Col("primary").Eq(1),
),
).LeftJoin(
files,
goqu.On(files.Col(idColumn).Eq(galleriesFilesJoinTable.Col(fileIDColumn))),
).LeftJoin(
folders,
goqu.On(folders.Col(idColumn).Eq(files.Col("parent_folder_id"))),
).LeftJoin(
galleryFolder,
goqu.On(galleryFolder.Col(idColumn).Eq(table.Col("folder_id"))),
).Select(
qb.table().All(),
galleriesFilesJoinTable.Col(fileIDColumn).As("primary_file_id"),
folders.Col("path").As("primary_file_folder_path"),
files.Col("basename").As("primary_file_basename"),
galleryFolder.Col("path").As("folder_path"),
)
}
func (qb *GalleryStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Gallery, error) {
@@ -255,7 +300,7 @@ func (qb *GalleryStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*
const single = false
var ret []*models.Gallery
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f galleryRow
var f galleryQueryRow
if err := r.StructScan(&f); err != nil {
return err
}
@@ -268,38 +313,10 @@ func (qb *GalleryStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*
return nil, err
}
for _, s := range ret {
if err := qb.resolveRelationships(ctx, s); err != nil {
return nil, err
}
}
return ret, nil
}
func (qb *GalleryStore) resolveRelationships(ctx context.Context, s *models.Gallery) error {
var err error
// files
s.Files, err = qb.getFiles(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving gallery files: %w", err)
}
// folder
if s.FolderID != nil {
folder, err := qb.folderStore.Find(ctx, *s.FolderID)
if err != nil {
return fmt.Errorf("resolving gallery folder: %w", err)
}
s.FolderPath = folder.Path
}
return nil
}
func (qb *GalleryStore) getFiles(ctx context.Context, id int) ([]file.File, error) {
func (qb *GalleryStore) GetFiles(ctx context.Context, id int) ([]file.File, error) {
fileIDs, err := qb.filesRepository().get(ctx, id)
if err != nil {
return nil, err
@@ -317,6 +334,11 @@ func (qb *GalleryStore) getFiles(ctx context.Context, id int) ([]file.File, erro
return ret, nil
}
func (qb *GalleryStore) GetManyFileIDs(ctx context.Context, ids []int) ([][]file.ID, error) {
const primaryOnly = false
return qb.filesRepository().getMany(ctx, ids, primaryOnly)
}
func (qb *GalleryStore) Find(ctx context.Context, id int) (*models.Gallery, error) {
q := qb.selectDataset().Where(qb.tableMgr.byID(id))

View File

@@ -33,6 +33,19 @@ func loadGalleryRelationships(ctx context.Context, expected models.Gallery, actu
return err
}
}
if expected.Files.Loaded() {
if err := actual.LoadFiles(ctx, db.Gallery); err != nil {
return err
}
}
// clear Path, Checksum, PrimaryFileID
if expected.Path == "" {
actual.Path = ""
}
if expected.PrimaryFileID == nil {
actual.PrimaryFileID = nil
}
return nil
}
@@ -71,7 +84,6 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
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,
},
@@ -85,9 +97,9 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
Rating: &rating,
Organized: true,
StudioID: &studioIDs[studioIdxWithScene],
Files: []file.File{
Files: models.NewRelatedFiles([]file.File{
galleryFile,
},
}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
@@ -134,8 +146,8 @@ func Test_galleryQueryBuilder_Create(t *testing.T) {
s := tt.newObject
var fileIDs []file.ID
if len(s.Files) > 0 {
fileIDs = []file.ID{s.Files[0].Base().ID}
if s.Files.Loaded() {
fileIDs = []file.ID{s.Files.List()[0].Base().ID}
}
if err := qb.Create(ctx, &s, fileIDs); (err != nil) != tt.wantErr {
@@ -217,9 +229,9 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
Rating: &rating,
Organized: true,
StudioID: &studioIDs[studioIdxWithScene],
Files: []file.File{
Files: models.NewRelatedFiles([]file.File{
makeGalleryFileWithID(galleryIdxWithScene),
},
}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdx1WithPerformer], sceneIDs[sceneIdx1WithStudio]}),
@@ -231,10 +243,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"clear nullables",
&models.Gallery{
ID: galleryIDs[galleryIdxWithImage],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithImage),
},
ID: galleryIDs[galleryIdxWithImage],
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -247,10 +256,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"clear scene ids",
&models.Gallery{
ID: galleryIDs[galleryIdxWithScene],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithScene),
},
ID: galleryIDs[galleryIdxWithScene],
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -263,10 +269,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"clear tag ids",
&models.Gallery{
ID: galleryIDs[galleryIdxWithTag],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithTag),
},
ID: galleryIDs[galleryIdxWithTag],
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -279,10 +282,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"clear performer ids",
&models.Gallery{
ID: galleryIDs[galleryIdxWithPerformer],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithPerformer),
},
ID: galleryIDs[galleryIdxWithPerformer],
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -295,10 +295,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"invalid studio id",
&models.Gallery{
ID: galleryIDs[galleryIdxWithImage],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithImage),
},
ID: galleryIDs[galleryIdxWithImage],
Organized: true,
StudioID: &invalidID,
CreatedAt: createdAt,
@@ -309,10 +306,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"invalid scene id",
&models.Gallery{
ID: galleryIDs[galleryIdxWithImage],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithImage),
},
ID: galleryIDs[galleryIdxWithImage],
Organized: true,
SceneIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
@@ -323,10 +317,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"invalid tag id",
&models.Gallery{
ID: galleryIDs[galleryIdxWithImage],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithImage),
},
ID: galleryIDs[galleryIdxWithImage],
Organized: true,
TagIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
@@ -337,10 +328,7 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
{
"invalid performer id",
&models.Gallery{
ID: galleryIDs[galleryIdxWithImage],
Files: []file.File{
makeGalleryFileWithID(galleryIdxWithImage),
},
ID: galleryIDs[galleryIdxWithImage],
Organized: true,
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
@@ -385,8 +373,10 @@ func Test_galleryQueryBuilder_Update(t *testing.T) {
}
func clearGalleryFileIDs(gallery *models.Gallery) {
for _, f := range gallery.Files {
f.Base().ID = 0
if gallery.Files.Loaded() {
for _, f := range gallery.Files.List() {
f.Base().ID = 0
}
}
}
@@ -459,9 +449,9 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
Rating: &rating,
Organized: true,
StudioID: &studioIDs[studioIdxWithGallery],
Files: []file.File{
Files: models.NewRelatedFiles([]file.File{
makeGalleryFile(galleryIdxWithImage),
},
}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
SceneIDs: models.NewRelatedIDs([]int{sceneIDs[sceneIdxWithGallery]}),
@@ -476,9 +466,9 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
clearGalleryPartial(),
models.Gallery{
ID: galleryIDs[galleryIdxWithImage],
Files: []file.File{
Files: models.NewRelatedFiles([]file.File{
makeGalleryFile(galleryIdxWithImage),
},
}),
SceneIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -509,12 +499,12 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
return
}
clearGalleryFileIDs(got)
// load relationships
if err := loadGalleryRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
clearGalleryFileIDs(got)
assert.Equal(tt.want, *got)
s, err := qb.Find(ctx, tt.id)
@@ -522,12 +512,12 @@ func Test_galleryQueryBuilder_UpdatePartial(t *testing.T) {
t.Errorf("galleryQueryBuilder.Find() error = %v", err)
}
clearGalleryFileIDs(s)
// load relationships
if err := loadGalleryRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadGalleryRelationships() error = %v", err)
return
}
clearGalleryFileIDs(s)
assert.Equal(tt.want, *s)
})
}
@@ -858,7 +848,7 @@ func makeGalleryWithID(index int) *models.Gallery {
ret.Date = nil
}
ret.Files = []file.File{makeGalleryFile(index)}
ret.Files = models.NewRelatedFiles([]file.File{makeGalleryFile(index)})
return ret
}
@@ -908,13 +898,12 @@ 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
}
clearGalleryFileIDs(got)
}
assert.Equal(tt.want, got)
})
@@ -923,14 +912,13 @@ func Test_galleryQueryBuilder_Find(t *testing.T) {
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
}
}
clearGalleryFileIDs(s)
}
return nil
@@ -1490,7 +1478,7 @@ func TestGalleryQueryPath(t *testing.T) {
assert.NotEqual(t, 0, count)
for _, gallery := range got {
verifyString(t, gallery.Path(), tt.input)
verifyString(t, gallery.Path, tt.input)
}
})
}
@@ -1508,7 +1496,7 @@ func verifyGalleriesPath(ctx context.Context, t *testing.T, pathCriterion models
}
for _, gallery := range galleries {
verifyString(t, gallery.Path(), pathCriterion)
verifyString(t, gallery.Path, pathCriterion)
}
}
@@ -1541,8 +1529,8 @@ func TestGalleryQueryPathOr(t *testing.T) {
return nil
}
assert.Equal(t, gallery1Path, galleries[0].Path())
assert.Equal(t, gallery2Path, galleries[1].Path())
assert.Equal(t, gallery1Path, galleries[0].Path)
assert.Equal(t, gallery2Path, galleries[1].Path)
return nil
})
@@ -1575,7 +1563,7 @@ func TestGalleryQueryPathAndRating(t *testing.T) {
return nil
}
assert.Equal(t, galleryPath, galleries[0].Path())
assert.Equal(t, galleryPath, galleries[0].Path)
assert.Equal(t, *galleryRating, *galleries[0].Rating)
return nil
@@ -1610,7 +1598,7 @@ func TestGalleryQueryPathNotRating(t *testing.T) {
galleries := queryGallery(ctx, t, sqb, &galleryFilter, nil)
for _, gallery := range galleries {
verifyString(t, gallery.Path(), pathCriterion)
verifyString(t, gallery.Path, pathCriterion)
ratingCriterion.Modifier = models.CriterionModifierNotEquals
verifyIntPtr(t, gallery.Rating, ratingCriterion)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"path/filepath"
"time"
"github.com/jmoiron/sqlx"
@@ -48,17 +49,35 @@ func (r *imageRow) fromImage(i models.Image) {
r.UpdatedAt = i.UpdatedAt
}
func (r *imageRow) resolve() *models.Image {
return &models.Image{
type imageQueryRow struct {
imageRow
PrimaryFileID null.Int `db:"primary_file_id"`
PrimaryFileFolderPath zero.String `db:"primary_file_folder_path"`
PrimaryFileBasename zero.String `db:"primary_file_basename"`
PrimaryFileChecksum zero.String `db:"primary_file_checksum"`
}
func (r *imageQueryRow) resolve() *models.Image {
ret := &models.Image{
ID: r.ID,
Title: r.Title.String,
Rating: nullIntPtr(r.Rating),
Organized: r.Organized,
OCounter: r.OCounter,
StudioID: nullIntPtr(r.StudioID),
PrimaryFileID: nullIntFileIDPtr(r.PrimaryFileID),
Checksum: r.PrimaryFileChecksum.String,
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
}
if r.PrimaryFileFolderPath.Valid && r.PrimaryFileBasename.Valid {
ret.Path = filepath.Join(r.PrimaryFileFolderPath.String, r.PrimaryFileBasename.String)
}
return ret
}
type imageRowRecord struct {
@@ -203,15 +222,16 @@ func (qb *ImageStore) Update(ctx context.Context, updatedObject *models.Image) e
}
}
fileIDs := make([]file.ID, len(updatedObject.Files))
for i, f := range updatedObject.Files {
fileIDs[i] = f.ID
}
if updatedObject.Files.Loaded() {
fileIDs := make([]file.ID, len(updatedObject.Files.List()))
for i, f := range updatedObject.Files.List() {
fileIDs[i] = f.ID
}
if err := imagesFilesTableMgr.replaceJoins(ctx, updatedObject.ID, fileIDs); err != nil {
return err
if err := imagesFilesTableMgr.replaceJoins(ctx, updatedObject.ID, fileIDs); err != nil {
return err
}
}
return nil
}
@@ -247,7 +267,36 @@ func (qb *ImageStore) FindMany(ctx context.Context, ids []int) ([]*models.Image,
}
func (qb *ImageStore) selectDataset() *goqu.SelectDataset {
return dialect.From(qb.table()).Select(qb.table().All())
table := qb.table()
files := fileTableMgr.table
folders := folderTableMgr.table
checksum := fingerprintTableMgr.table
return dialect.From(table).LeftJoin(
imagesFilesJoinTable,
goqu.On(
imagesFilesJoinTable.Col(imageIDColumn).Eq(table.Col(idColumn)),
imagesFilesJoinTable.Col("primary").Eq(1),
),
).LeftJoin(
files,
goqu.On(files.Col(idColumn).Eq(imagesFilesJoinTable.Col(fileIDColumn))),
).LeftJoin(
folders,
goqu.On(folders.Col(idColumn).Eq(files.Col("parent_folder_id"))),
).LeftJoin(
checksum,
goqu.On(
checksum.Col(fileIDColumn).Eq(imagesFilesJoinTable.Col(fileIDColumn)),
checksum.Col("type").Eq(file.FingerprintTypeMD5),
),
).Select(
qb.table().All(),
imagesFilesJoinTable.Col(fileIDColumn).As("primary_file_id"),
folders.Col("path").As("primary_file_folder_path"),
files.Col("basename").As("primary_file_basename"),
checksum.Col("fingerprint").As("primary_file_checksum"),
)
}
func (qb *ImageStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Image, error) {
@@ -267,7 +316,7 @@ func (qb *ImageStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
const single = false
var ret []*models.Image
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f imageRow
var f imageQueryRow
if err := r.StructScan(&f); err != nil {
return err
}
@@ -280,28 +329,10 @@ func (qb *ImageStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
return nil, err
}
for _, i := range ret {
if err := qb.resolveRelationships(ctx, i); err != nil {
return nil, err
}
}
return ret, nil
}
func (qb *ImageStore) resolveRelationships(ctx context.Context, i *models.Image) error {
var err error
// files
i.Files, err = qb.getFiles(ctx, i.ID)
if err != nil {
return fmt.Errorf("resolving image files: %w", err)
}
return nil
}
func (qb *ImageStore) getFiles(ctx context.Context, id int) ([]*file.ImageFile, error) {
func (qb *ImageStore) GetFiles(ctx context.Context, id int) ([]*file.ImageFile, error) {
fileIDs, err := qb.filesRepository().get(ctx, id)
if err != nil {
return nil, err
@@ -325,6 +356,11 @@ func (qb *ImageStore) getFiles(ctx context.Context, id int) ([]*file.ImageFile,
return ret, nil
}
func (qb *ImageStore) GetManyFileIDs(ctx context.Context, ids []int) ([][]file.ID, error) {
const primaryOnly = false
return qb.filesRepository().getMany(ctx, ids, primaryOnly)
}
func (qb *ImageStore) find(ctx context.Context, id int) (*models.Image, error) {
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
@@ -428,16 +464,7 @@ func (qb *ImageStore) FindByGalleryID(ctx context.Context, galleryID int) ([]*mo
galleriesImagesJoinTable.Col("gallery_id").Eq(galleryID),
)
q := qb.selectDataset().Prepared(true).LeftJoin(
imagesFilesJoinTable,
goqu.On(imagesFilesJoinTable.Col(imageIDColumn).Eq(table.Col(idColumn))),
).LeftJoin(
fileTable,
goqu.On(fileTable.Col(idColumn).Eq(imagesFilesJoinTable.Col(fileIDColumn))),
).LeftJoin(
folderTable,
goqu.On(folderTable.Col(idColumn).Eq(fileTable.Col("parent_folder_id"))),
).Where(
q := qb.selectDataset().Prepared(true).Where(
table.Col(idColumn).Eq(
sq,
),

View File

@@ -31,6 +31,22 @@ func loadImageRelationships(ctx context.Context, expected models.Image, actual *
return err
}
}
if expected.Files.Loaded() {
if err := actual.LoadFiles(ctx, db.Image); err != nil {
return err
}
}
// clear Path, Checksum, PrimaryFileID
if expected.Path == "" {
actual.Path = ""
}
if expected.Checksum == "" {
actual.Checksum = ""
}
if expected.PrimaryFileID == nil {
actual.PrimaryFileID = nil
}
return nil
}
@@ -64,7 +80,6 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
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,
},
@@ -76,14 +91,16 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
Organized: true,
OCounter: ocounter,
StudioID: &studioIDs[studioIdxWithImage],
Files: []*file.ImageFile{
Files: models.NewRelatedImageFiles([]*file.ImageFile{
imageFile.(*file.ImageFile),
},
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]}),
}),
PrimaryFileID: &imageFile.Base().ID,
Path: imageFile.Base().Path,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithImage], tagIDs[tagIdx1WithDupName]}),
PerformerIDs: models.NewRelatedIDs([]int{performerIDs[performerIdx1WithImage], performerIDs[performerIdx1WithDupName]}),
},
false,
},
@@ -124,10 +141,11 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
assert := assert.New(t)
var fileIDs []file.ID
for _, f := range tt.newObject.Files {
fileIDs = append(fileIDs, f.ID)
if tt.newObject.Files.Loaded() {
for _, f := range tt.newObject.Files.List() {
fileIDs = append(fileIDs, f.ID)
}
}
s := tt.newObject
if err := qb.Create(ctx, &models.ImageCreateInput{
Image: &s,
@@ -174,8 +192,10 @@ func Test_imageQueryBuilder_Create(t *testing.T) {
}
func clearImageFileIDs(image *models.Image) {
for _, f := range image.Files {
f.Base().ID = 0
if image.Files.Loaded() {
for _, f := range image.Files.List() {
f.Base().ID = 0
}
}
}
@@ -202,15 +222,12 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"full",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Title: title,
Rating: &rating,
Organized: true,
OCounter: ocounter,
StudioID: &studioIDs[studioIdxWithImage],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
Title: title,
Rating: &rating,
Organized: true,
OCounter: ocounter,
StudioID: &studioIDs[studioIdxWithImage],
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
@@ -222,10 +239,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"clear nullables",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -238,10 +252,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"clear gallery ids",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -254,10 +265,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"clear tag ids",
&models.Image{
ID: imageIDs[imageIdxWithTag],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithTag),
},
ID: imageIDs[imageIdxWithTag],
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -270,10 +278,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"clear performer ids",
&models.Image{
ID: imageIDs[imageIdxWithPerformer],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithPerformer),
},
ID: imageIDs[imageIdxWithPerformer],
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -286,10 +291,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"invalid studio id",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
Organized: true,
StudioID: &invalidID,
CreatedAt: createdAt,
@@ -300,10 +302,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"invalid gallery id",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
Organized: true,
GalleryIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
@@ -314,10 +313,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"invalid tag id",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
Organized: true,
TagIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
@@ -328,10 +324,7 @@ func Test_imageQueryBuilder_Update(t *testing.T) {
{
"invalid performer id",
&models.Image{
ID: imageIDs[imageIdxWithGallery],
Files: []*file.ImageFile{
makeImageFileWithID(imageIdxWithGallery),
},
ID: imageIDs[imageIdxWithGallery],
Organized: true,
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
CreatedAt: createdAt,
@@ -433,9 +426,9 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
Organized: true,
OCounter: ocounter,
StudioID: &studioIDs[studioIdxWithImage],
Files: []*file.ImageFile{
Files: models.NewRelatedImageFiles([]*file.ImageFile{
makeImageFile(imageIdx1WithGallery),
},
}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithImage]}),
@@ -451,9 +444,9 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
models.Image{
ID: imageIDs[imageIdx1WithGallery],
OCounter: getOCounter(imageIdx1WithGallery),
Files: []*file.ImageFile{
Files: models.NewRelatedImageFiles([]*file.ImageFile{
makeImageFile(imageIdx1WithGallery),
},
}),
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -484,12 +477,12 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
return
}
clearImageFileIDs(got)
// load relationships
if err := loadImageRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
clearImageFileIDs(got)
assert.Equal(tt.want, *got)
@@ -498,12 +491,12 @@ func Test_imageQueryBuilder_UpdatePartial(t *testing.T) {
t.Errorf("imageQueryBuilder.Find() error = %v", err)
}
clearImageFileIDs(s)
// load relationships
if err := loadImageRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadImageRelationships() error = %v", err)
return
}
clearImageFileIDs(s)
assert.Equal(tt.want, *s)
})
}
@@ -952,7 +945,7 @@ func makeImageWithID(index int) *models.Image {
ret := makeImage(index)
ret.ID = imageIDs[index]
ret.Files = []*file.ImageFile{makeImageFile(index)}
ret.Files = models.NewRelatedImageFiles([]*file.ImageFile{makeImageFile(index)})
return ret
}
@@ -1002,13 +995,12 @@ 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
}
clearImageFileIDs(got)
}
assert.Equal(tt.want, got)
})
@@ -1017,14 +1009,13 @@ func Test_imageQueryBuilder_Find(t *testing.T) {
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
}
}
clearImageFileIDs(s)
}
return nil
@@ -1546,7 +1537,7 @@ func verifyImagePath(t *testing.T, pathCriterion models.StringCriterionInput, ex
assert.Equal(t, expected, len(images), "number of returned images")
for _, image := range images {
verifyString(t, image.Path(), pathCriterion)
verifyString(t, image.Path, pathCriterion)
}
return nil
@@ -1582,8 +1573,8 @@ func TestImageQueryPathOr(t *testing.T) {
return nil
}
assert.Equal(t, image1Path, images[0].Path())
assert.Equal(t, image2Path, images[1].Path())
assert.Equal(t, image1Path, images[0].Path)
assert.Equal(t, image2Path, images[1].Path)
return nil
})
@@ -1613,7 +1604,7 @@ func TestImageQueryPathAndRating(t *testing.T) {
images := queryImages(ctx, t, sqb, &imageFilter, nil)
assert.Len(t, images, 1)
assert.Equal(t, imagePath, images[0].Path())
assert.Equal(t, imagePath, images[0].Path)
assert.Equal(t, int(imageRating.Int64), *images[0].Rating)
return nil
@@ -1648,7 +1639,7 @@ func TestImageQueryPathNotRating(t *testing.T) {
images := queryImages(ctx, t, sqb, &imageFilter, nil)
for _, image := range images {
verifyString(t, image.Path(), pathCriterion)
verifyString(t, image.Path, pathCriterion)
ratingCriterion.Modifier = models.CriterionModifierNotEquals
verifyIntPtr(t, image.Rating, ratingCriterion)
}
@@ -1802,7 +1793,12 @@ func verifyImagesResolution(t *testing.T, resolution models.ResolutionEnum) {
}
for _, image := range images {
verifyImageResolution(t, image.Files[0].Height, resolution)
if err := image.LoadPrimaryFile(ctx, db.File); err != nil {
t.Errorf("Error loading primary file: %s", err.Error())
return nil
}
verifyImageResolution(t, image.Files.Primary().Height, resolution)
}
return nil

View File

@@ -477,6 +477,61 @@ type filesRepository struct {
repository
}
type relatedFileRow struct {
ID int `db:"id"`
FileID file.ID `db:"file_id"`
Primary bool `db:"primary"`
}
func (r *filesRepository) getMany(ctx context.Context, ids []int, primaryOnly bool) ([][]file.ID, error) {
var primaryClause string
if primaryOnly {
primaryClause = " AND `primary` = 1"
}
query := fmt.Sprintf("SELECT %s as id, file_id, `primary` from %s WHERE %[1]s IN %[3]s%s", r.idColumn, r.tableName, getInBinding(len(ids)), primaryClause)
idi := make([]interface{}, len(ids))
for i, id := range ids {
idi[i] = id
}
var fileRows []relatedFileRow
if err := r.queryFunc(ctx, query, idi, false, func(rows *sqlx.Rows) error {
var f relatedFileRow
if err := rows.StructScan(&f); err != nil {
return err
}
fileRows = append(fileRows, f)
return nil
}); err != nil {
return nil, err
}
ret := make([][]file.ID, len(ids))
idToIndex := make(map[int]int)
for i, id := range ids {
idToIndex[id] = i
}
for _, row := range fileRows {
id := row.ID
fileID := row.FileID
if row.Primary {
// prepend to list
ret[idToIndex[id]] = append([]file.ID{fileID}, ret[idToIndex[id]]...)
} else {
ret[idToIndex[id]] = append(ret[idToIndex[id]], row.FileID)
}
}
return ret, nil
}
func (r *filesRepository) get(ctx context.Context, id int) ([]file.ID, error) {
query := fmt.Sprintf("SELECT file_id, `primary` from %s WHERE %s = ?", r.tableName, r.idColumn)

View File

@@ -82,8 +82,17 @@ func (r *sceneRow) fromScene(o models.Scene) {
r.UpdatedAt = o.UpdatedAt
}
func (r *sceneRow) resolve() *models.Scene {
return &models.Scene{
type sceneQueryRow struct {
sceneRow
PrimaryFileID null.Int `db:"primary_file_id"`
PrimaryFileFolderPath zero.String `db:"primary_file_folder_path"`
PrimaryFileBasename zero.String `db:"primary_file_basename"`
PrimaryFileOshash zero.String `db:"primary_file_oshash"`
PrimaryFileChecksum zero.String `db:"primary_file_checksum"`
}
func (r *sceneQueryRow) resolve() *models.Scene {
ret := &models.Scene{
ID: r.ID,
Title: r.Title.String,
Details: r.Details.String,
@@ -93,9 +102,20 @@ func (r *sceneRow) resolve() *models.Scene {
Organized: r.Organized,
OCounter: r.OCounter,
StudioID: nullIntPtr(r.StudioID),
PrimaryFileID: nullIntFileIDPtr(r.PrimaryFileID),
OSHash: r.PrimaryFileOshash.String,
Checksum: r.PrimaryFileChecksum.String,
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
}
if r.PrimaryFileFolderPath.Valid && r.PrimaryFileBasename.Valid {
ret.Path = filepath.Join(r.PrimaryFileFolderPath.String, r.PrimaryFileBasename.String)
}
return ret
}
type sceneRowRecord struct {
@@ -278,13 +298,15 @@ func (qb *SceneStore) Update(ctx context.Context, updatedObject *models.Scene) e
}
}
fileIDs := make([]file.ID, len(updatedObject.Files))
for i, f := range updatedObject.Files {
fileIDs[i] = f.ID
}
if updatedObject.Files.Loaded() {
fileIDs := make([]file.ID, len(updatedObject.Files.List()))
for i, f := range updatedObject.Files.List() {
fileIDs[i] = f.ID
}
if err := scenesFilesTableMgr.replaceJoins(ctx, updatedObject.ID, fileIDs); err != nil {
return err
if err := scenesFilesTableMgr.replaceJoins(ctx, updatedObject.ID, fileIDs); err != nil {
return err
}
}
return nil
@@ -333,7 +355,43 @@ func (qb *SceneStore) FindMany(ctx context.Context, ids []int) ([]*models.Scene,
func (qb *SceneStore) selectDataset() *goqu.SelectDataset {
table := qb.table()
return dialect.From(table).Select(table.All())
files := fileTableMgr.table
folders := folderTableMgr.table
checksum := fingerprintTableMgr.table.As("fingerprint_md5")
oshash := fingerprintTableMgr.table.As("fingerprint_oshash")
return dialect.From(table).LeftJoin(
scenesFilesJoinTable,
goqu.On(
scenesFilesJoinTable.Col(sceneIDColumn).Eq(table.Col(idColumn)),
scenesFilesJoinTable.Col("primary").Eq(1),
),
).LeftJoin(
files,
goqu.On(files.Col(idColumn).Eq(scenesFilesJoinTable.Col(fileIDColumn))),
).LeftJoin(
folders,
goqu.On(folders.Col(idColumn).Eq(files.Col("parent_folder_id"))),
).LeftJoin(
checksum,
goqu.On(
checksum.Col(fileIDColumn).Eq(scenesFilesJoinTable.Col(fileIDColumn)),
checksum.Col("type").Eq(file.FingerprintTypeMD5),
),
).LeftJoin(
oshash,
goqu.On(
oshash.Col(fileIDColumn).Eq(scenesFilesJoinTable.Col(fileIDColumn)),
oshash.Col("type").Eq(file.FingerprintTypeOshash),
),
).Select(
qb.table().All(),
scenesFilesJoinTable.Col(fileIDColumn).As("primary_file_id"),
folders.Col("path").As("primary_file_folder_path"),
files.Col("basename").As("primary_file_basename"),
checksum.Col("fingerprint").As("primary_file_checksum"),
oshash.Col("fingerprint").As("primary_file_oshash"),
)
}
func (qb *SceneStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Scene, error) {
@@ -353,7 +411,7 @@ func (qb *SceneStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
const single = false
var ret []*models.Scene
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
var f sceneRow
var f sceneQueryRow
if err := r.StructScan(&f); err != nil {
return err
}
@@ -366,28 +424,10 @@ func (qb *SceneStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*mo
return nil, err
}
for _, s := range ret {
if err := qb.resolveRelationships(ctx, s); err != nil {
return nil, err
}
}
return ret, nil
}
func (qb *SceneStore) resolveRelationships(ctx context.Context, s *models.Scene) error {
var err error
// files
s.Files, err = qb.getFiles(ctx, s.ID)
if err != nil {
return fmt.Errorf("resolving scene files: %w", err)
}
return nil
}
func (qb *SceneStore) getFiles(ctx context.Context, id int) ([]*file.VideoFile, error) {
func (qb *SceneStore) GetFiles(ctx context.Context, id int) ([]*file.VideoFile, error) {
fileIDs, err := qb.filesRepository().get(ctx, id)
if err != nil {
return nil, err
@@ -411,6 +451,11 @@ func (qb *SceneStore) getFiles(ctx context.Context, id int) ([]*file.VideoFile,
return ret, nil
}
func (qb *SceneStore) GetManyFileIDs(ctx context.Context, ids []int) ([][]file.ID, error) {
const primaryOnly = false
return qb.filesRepository().getMany(ctx, ids, primaryOnly)
}
func (qb *SceneStore) find(ctx context.Context, id int) (*models.Scene, error) {
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
@@ -680,16 +725,8 @@ func (qb *SceneStore) All(ctx context.Context) ([]*models.Scene, error) {
table := qb.table()
fileTable := fileTableMgr.table
folderTable := folderTableMgr.table
return qb.getMany(ctx, qb.selectDataset().LeftJoin(
scenesFilesJoinTable,
goqu.On(scenesFilesJoinTable.Col(sceneIDColumn).Eq(table.Col(idColumn))),
).LeftJoin(
fileTable,
goqu.On(fileTable.Col(idColumn).Eq(scenesFilesJoinTable.Col(fileIDColumn))),
).LeftJoin(
folderTable,
goqu.On(folderTable.Col(idColumn).Eq(fileTable.Col("parent_folder_id"))),
).Order(
return qb.getMany(ctx, qb.selectDataset().Order(
folderTable.Col("path").Asc(),
fileTable.Col("basename").Asc(),
table.Col("date").Asc(),

View File

@@ -47,6 +47,25 @@ func loadSceneRelationships(ctx context.Context, expected models.Scene, actual *
return err
}
}
if expected.Files.Loaded() {
if err := actual.LoadFiles(ctx, db.Scene); err != nil {
return err
}
}
// clear Path, Checksum, PrimaryFileID
if expected.Path == "" {
actual.Path = ""
}
if expected.Checksum == "" {
actual.Checksum = ""
}
if expected.OSHash == "" {
actual.OSHash = ""
}
if expected.PrimaryFileID == nil {
actual.PrimaryFileID = nil
}
return nil
}
@@ -113,7 +132,6 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
Endpoint: endpoint2,
},
}),
Files: []*file.VideoFile{},
},
false,
},
@@ -128,9 +146,9 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
Organized: true,
OCounter: ocounter,
StudioID: &studioIDs[studioIdxWithScene],
Files: []*file.VideoFile{
Files: models.NewRelatedVideoFiles([]*file.VideoFile{
videoFile.(*file.VideoFile),
},
}),
CreatedAt: createdAt,
UpdatedAt: updatedAt,
GalleryIDs: models.NewRelatedIDs([]int{galleryIDs[galleryIdxWithScene]}),
@@ -208,8 +226,10 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
assert := assert.New(t)
var fileIDs []file.ID
for _, f := range tt.newObject.Files {
fileIDs = append(fileIDs, f.ID)
if tt.newObject.Files.Loaded() {
for _, f := range tt.newObject.Files.List() {
fileIDs = append(fileIDs, f.ID)
}
}
s := tt.newObject
@@ -258,8 +278,10 @@ func Test_sceneQueryBuilder_Create(t *testing.T) {
}
func clearSceneFileIDs(scene *models.Scene) {
for _, f := range scene.Files {
f.Base().ID = 0
if scene.Files.Loaded() {
for _, f := range scene.Files.List() {
f.Base().ID = 0
}
}
}
@@ -296,10 +318,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"full",
&models.Scene{
ID: sceneIDs[sceneIdxWithGallery],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
ID: sceneIDs[sceneIdxWithGallery],
Title: title,
Details: details,
URL: url,
@@ -339,10 +358,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"clear nullables",
&models.Scene{
ID: sceneIDs[sceneIdxWithSpacedName],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithSpacedName),
},
ID: sceneIDs[sceneIdxWithSpacedName],
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -354,10 +370,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"clear gallery ids",
&models.Scene{
ID: sceneIDs[sceneIdxWithGallery],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
ID: sceneIDs[sceneIdxWithGallery],
GalleryIDs: models.NewRelatedIDs([]int{}),
},
false,
@@ -365,10 +378,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"clear tag ids",
&models.Scene{
ID: sceneIDs[sceneIdxWithTag],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithTag),
},
ID: sceneIDs[sceneIdxWithTag],
TagIDs: models.NewRelatedIDs([]int{}),
},
false,
@@ -376,10 +386,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"clear performer ids",
&models.Scene{
ID: sceneIDs[sceneIdxWithPerformer],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithPerformer),
},
ID: sceneIDs[sceneIdxWithPerformer],
PerformerIDs: models.NewRelatedIDs([]int{}),
},
false,
@@ -387,10 +394,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"clear movies",
&models.Scene{
ID: sceneIDs[sceneIdxWithMovie],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithMovie),
},
ID: sceneIDs[sceneIdxWithMovie],
Movies: models.NewRelatedMovies([]models.MoviesScenes{}),
},
false,
@@ -398,10 +402,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"invalid studio id",
&models.Scene{
ID: sceneIDs[sceneIdxWithGallery],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
ID: sceneIDs[sceneIdxWithGallery],
StudioID: &invalidID,
},
true,
@@ -409,10 +410,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"invalid gallery id",
&models.Scene{
ID: sceneIDs[sceneIdxWithGallery],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
ID: sceneIDs[sceneIdxWithGallery],
GalleryIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
@@ -420,10 +418,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"invalid tag id",
&models.Scene{
ID: sceneIDs[sceneIdxWithGallery],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
ID: sceneIDs[sceneIdxWithGallery],
TagIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
@@ -431,10 +426,7 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
{
"invalid performer id",
&models.Scene{
ID: sceneIDs[sceneIdxWithGallery],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithGallery),
},
ID: sceneIDs[sceneIdxWithGallery],
PerformerIDs: models.NewRelatedIDs([]int{invalidID}),
},
true,
@@ -443,9 +435,6 @@ func Test_sceneQueryBuilder_Update(t *testing.T) {
"invalid movie id",
&models.Scene{
ID: sceneIDs[sceneIdxWithSpacedName],
Files: []*file.VideoFile{
makeSceneFileWithID(sceneIdxWithSpacedName),
},
Movies: models.NewRelatedMovies([]models.MoviesScenes{
{
MovieID: invalidID,
@@ -585,9 +574,9 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
},
models.Scene{
ID: sceneIDs[sceneIdxWithSpacedName],
Files: []*file.VideoFile{
Files: models.NewRelatedVideoFiles([]*file.VideoFile{
makeSceneFile(sceneIdxWithSpacedName),
},
}),
Title: title,
Details: details,
URL: url,
@@ -630,9 +619,9 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
clearScenePartial(),
models.Scene{
ID: sceneIDs[sceneIdxWithSpacedName],
Files: []*file.VideoFile{
Files: models.NewRelatedVideoFiles([]*file.VideoFile{
makeSceneFile(sceneIdxWithSpacedName),
},
}),
GalleryIDs: models.NewRelatedIDs([]int{}),
TagIDs: models.NewRelatedIDs([]int{}),
PerformerIDs: models.NewRelatedIDs([]int{}),
@@ -665,15 +654,15 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
return
}
// ignore file ids
clearSceneFileIDs(got)
// load relationships
if err := loadSceneRelationships(ctx, tt.want, got); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
// ignore file ids
clearSceneFileIDs(got)
assert.Equal(tt.want, *got)
s, err := qb.Find(ctx, tt.id)
@@ -681,14 +670,13 @@ func Test_sceneQueryBuilder_UpdatePartial(t *testing.T) {
t.Errorf("sceneQueryBuilder.Find() error = %v", err)
}
// ignore file ids
clearSceneFileIDs(s)
// load relationships
if err := loadSceneRelationships(ctx, tt.want, s); err != nil {
t.Errorf("loadSceneRelationships() error = %v", err)
return
}
// ignore file ids
clearSceneFileIDs(s)
assert.Equal(tt.want, *s)
})
@@ -1338,7 +1326,7 @@ func makeSceneWithID(index int) *models.Scene {
ret.Date = nil
}
ret.Files = []*file.VideoFile{makeSceneFile(index)}
ret.Files = models.NewRelatedVideoFiles([]*file.VideoFile{makeSceneFile(index)})
return ret
}
@@ -1401,13 +1389,13 @@ 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
}
clearSceneFileIDs(got)
}
assert.Equal(tt.want, got)
@@ -1419,14 +1407,13 @@ 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
}
}
clearSceneFileIDs(s)
}
return nil
@@ -1935,7 +1922,7 @@ func TestSceneWall(t *testing.T) {
scene := scenes[0]
assert.Equal(t, sceneIDs[sceneIdx], scene.ID)
scenePath := getFilePath(folderIdxWithSceneFiles, getSceneBasename(sceneIdx))
assert.Equal(t, scenePath, scene.Path())
assert.Equal(t, scenePath, scene.Path)
wallQuery = "not exist"
scenes, err = sqb.Wall(ctx, &wallQuery)
@@ -2248,8 +2235,8 @@ func TestSceneQueryPathOr(t *testing.T) {
if !assert.Len(t, scenes, 2) {
return nil
}
assert.Equal(t, scene1Path, scenes[0].Path())
assert.Equal(t, scene2Path, scenes[1].Path())
assert.Equal(t, scene1Path, scenes[0].Path)
assert.Equal(t, scene2Path, scenes[1].Path)
return nil
})
@@ -2281,7 +2268,7 @@ func TestSceneQueryPathAndRating(t *testing.T) {
if !assert.Len(t, scenes, 1) {
return nil
}
assert.Equal(t, scenePath, scenes[0].Path())
assert.Equal(t, scenePath, scenes[0].Path)
assert.Equal(t, sceneRating, *scenes[0].Rating)
return nil
@@ -2316,7 +2303,7 @@ func TestSceneQueryPathNotRating(t *testing.T) {
scenes := queryScene(ctx, t, sqb, &sceneFilter, nil)
for _, scene := range scenes {
verifyString(t, scene.Path(), pathCriterion)
verifyString(t, scene.Path, pathCriterion)
ratingCriterion.Modifier = models.CriterionModifierNotEquals
verifyIntPtr(t, scene.Rating, ratingCriterion)
}
@@ -2394,7 +2381,7 @@ func verifyScenesPath(t *testing.T, pathCriterion models.StringCriterionInput) {
scenes := queryScene(ctx, t, sqb, &sceneFilter, nil)
for _, scene := range scenes {
verifyString(t, scene.Path(), pathCriterion)
verifyString(t, scene.Path, pathCriterion)
}
return nil
@@ -2662,7 +2649,12 @@ func verifyScenesDuration(t *testing.T, durationCriterion models.IntCriterionInp
scenes := queryScene(ctx, t, sqb, &sceneFilter, nil)
for _, scene := range scenes {
duration := scene.Duration()
if err := scene.LoadPrimaryFile(ctx, db.File); err != nil {
t.Errorf("Error querying scene files: %v", err)
return nil
}
duration := scene.Files.Primary().Duration
if durationCriterion.Modifier == models.CriterionModifierEquals {
assert.True(t, duration >= float64(durationCriterion.Value) && duration < float64(durationCriterion.Value+1))
} else if durationCriterion.Modifier == models.CriterionModifierNotEquals {
@@ -2732,7 +2724,11 @@ func verifyScenesResolution(t *testing.T, resolution models.ResolutionEnum) {
scenes := queryScene(ctx, t, sqb, &sceneFilter, nil)
for _, scene := range scenes {
f := scene.PrimaryFile()
if err := scene.LoadPrimaryFile(ctx, db.File); err != nil {
t.Errorf("Error querying scene files: %v", err)
return nil
}
f := scene.Files.Primary()
height := 0
if f != nil {
height = f.Height