mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
[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:
@@ -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))
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user