mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Decouple galleries from scenes (#1057)
This commit is contained in:
@@ -3,7 +3,6 @@ package sqlite
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
@@ -14,6 +13,7 @@ const galleryTable = "galleries"
|
||||
const performersGalleriesTable = "performers_galleries"
|
||||
const galleriesTagsTable = "galleries_tags"
|
||||
const galleriesImagesTable = "galleries_images"
|
||||
const galleriesScenesTable = "scenes_galleries"
|
||||
const galleryIDColumn = "gallery_id"
|
||||
|
||||
type galleryQueryBuilder struct {
|
||||
@@ -73,23 +73,6 @@ func (qb *galleryQueryBuilder) Destroy(id int) error {
|
||||
return qb.destroyExisting([]int{id})
|
||||
}
|
||||
|
||||
type GalleryNullSceneID struct {
|
||||
SceneID sql.NullInt64
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) ClearGalleryId(sceneID int) error {
|
||||
_, err := qb.tx.NamedExec(
|
||||
`UPDATE galleries SET scene_id = null WHERE scene_id = :sceneid`,
|
||||
GalleryNullSceneID{
|
||||
SceneID: sql.NullInt64{
|
||||
Int64: int64(sceneID),
|
||||
Valid: true,
|
||||
},
|
||||
},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) Find(id int) (*models.Gallery, error) {
|
||||
var ret models.Gallery
|
||||
if err := qb.get(id, &ret); err != nil {
|
||||
@@ -125,22 +108,29 @@ func (qb *galleryQueryBuilder) FindByChecksum(checksum string) (*models.Gallery,
|
||||
return qb.queryGallery(query, args)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) FindByChecksums(checksums []string) ([]*models.Gallery, error) {
|
||||
query := "SELECT * FROM galleries WHERE checksum IN " + getInBinding(len(checksums))
|
||||
var args []interface{}
|
||||
for _, checksum := range checksums {
|
||||
args = append(args, checksum)
|
||||
}
|
||||
return qb.queryGalleries(query, args)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) FindByPath(path string) (*models.Gallery, error) {
|
||||
query := "SELECT * FROM galleries WHERE path = ? LIMIT 1"
|
||||
args := []interface{}{path}
|
||||
return qb.queryGallery(query, args)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) FindBySceneID(sceneID int) (*models.Gallery, error) {
|
||||
query := "SELECT galleries.* FROM galleries WHERE galleries.scene_id = ? LIMIT 1"
|
||||
func (qb *galleryQueryBuilder) FindBySceneID(sceneID int) ([]*models.Gallery, error) {
|
||||
query := selectAll(galleryTable) + `
|
||||
LEFT JOIN scenes_galleries as scenes_join on scenes_join.gallery_id = galleries.id
|
||||
WHERE scenes_join.scene_id = ?
|
||||
GROUP BY galleries.id
|
||||
`
|
||||
args := []interface{}{sceneID}
|
||||
return qb.queryGallery(query, args)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) ValidGalleriesForScenePath(scenePath string) ([]*models.Gallery, error) {
|
||||
sceneDirPath := filepath.Dir(scenePath)
|
||||
query := "SELECT galleries.* FROM galleries WHERE galleries.scene_id IS NULL AND galleries.path LIKE '" + sceneDirPath + "%' ORDER BY path ASC"
|
||||
return qb.queryGalleries(query, nil)
|
||||
return qb.queryGalleries(query, args)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) FindByImageID(imageID int) ([]*models.Gallery, error) {
|
||||
@@ -182,6 +172,7 @@ func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, fi
|
||||
query.body = selectDistinctIDs("galleries")
|
||||
query.body += `
|
||||
left join performers_galleries as performers_join on performers_join.gallery_id = galleries.id
|
||||
left join scenes_galleries as scenes_join on scenes_join.gallery_id = galleries.id
|
||||
left join studios as studio on studio.id = galleries.studio_id
|
||||
left join galleries_tags as tags_join on tags_join.gallery_id = galleries.id
|
||||
left join galleries_images as images_join on images_join.gallery_id = galleries.id
|
||||
@@ -189,7 +180,7 @@ func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, fi
|
||||
`
|
||||
|
||||
if q := findFilter.Q; q != nil && *q != "" {
|
||||
searchColumns := []string{"galleries.path", "galleries.checksum"}
|
||||
searchColumns := []string{"galleries.title", "galleries.path", "galleries.checksum"}
|
||||
clause, thisArgs := getSearchBinding(searchColumns, *q, false)
|
||||
query.addWhere(clause)
|
||||
query.addArg(thisArgs...)
|
||||
@@ -221,8 +212,8 @@ func (qb *galleryQueryBuilder) Query(galleryFilter *models.GalleryFilterType, fi
|
||||
|
||||
if isMissingFilter := galleryFilter.IsMissing; isMissingFilter != nil && *isMissingFilter != "" {
|
||||
switch *isMissingFilter {
|
||||
case "scene":
|
||||
query.addWhere("galleries.scene_id IS NULL")
|
||||
case "scenes":
|
||||
query.addWhere("scenes_join.gallery_id IS NULL")
|
||||
case "studio":
|
||||
query.addWhere("galleries.studio_id IS NULL")
|
||||
case "performers":
|
||||
@@ -442,3 +433,23 @@ func (qb *galleryQueryBuilder) UpdateImages(galleryID int, imageIDs []int) error
|
||||
// Delete the existing joins and then create new ones
|
||||
return qb.imagesRepository().replace(galleryID, imageIDs)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) scenesRepository() *joinRepository {
|
||||
return &joinRepository{
|
||||
repository: repository{
|
||||
tx: qb.tx,
|
||||
tableName: galleriesScenesTable,
|
||||
idColumn: galleryIDColumn,
|
||||
},
|
||||
fkColumn: sceneIDColumn,
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) GetSceneIDs(galleryID int) ([]int, error) {
|
||||
return qb.scenesRepository().getIDs(galleryID)
|
||||
}
|
||||
|
||||
func (qb *galleryQueryBuilder) UpdateScenes(galleryID int, sceneIDs []int) error {
|
||||
// Delete the existing joins and then create new ones
|
||||
return qb.scenesRepository().replace(galleryID, sceneIDs)
|
||||
}
|
||||
|
||||
@@ -94,21 +94,21 @@ func TestGalleryFindBySceneID(t *testing.T) {
|
||||
gqb := r.Gallery()
|
||||
|
||||
sceneID := sceneIDs[sceneIdxWithGallery]
|
||||
gallery, err := gqb.FindBySceneID(sceneID)
|
||||
galleries, err := gqb.FindBySceneID(sceneID)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding gallery: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Equal(t, getGalleryStringValue(galleryIdxWithScene, "Path"), gallery.Path.String)
|
||||
assert.Equal(t, getGalleryStringValue(galleryIdxWithScene, "Path"), galleries[0].Path.String)
|
||||
|
||||
gallery, err = gqb.FindBySceneID(0)
|
||||
galleries, err = gqb.FindBySceneID(0)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error finding gallery: %s", err.Error())
|
||||
}
|
||||
|
||||
assert.Nil(t, gallery)
|
||||
assert.Nil(t, galleries)
|
||||
|
||||
return nil
|
||||
})
|
||||
@@ -233,7 +233,7 @@ func verifyGalleriesRating(t *testing.T, ratingCriterion models.IntCriterionInpu
|
||||
func TestGalleryQueryIsMissingScene(t *testing.T) {
|
||||
withTxn(func(r models.Repository) error {
|
||||
qb := r.Gallery()
|
||||
isMissing := "scene"
|
||||
isMissing := "scenes"
|
||||
galleryFilter := models.GalleryFilterType{
|
||||
IsMissing: &isMissing,
|
||||
}
|
||||
@@ -265,10 +265,8 @@ func TestGalleryQueryIsMissingScene(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO ValidGalleriesForScenePath
|
||||
// TODO Count
|
||||
// TODO All
|
||||
// TODO Query
|
||||
// TODO Update
|
||||
// TODO Destroy
|
||||
// TODO ClearGalleryId
|
||||
|
||||
@@ -13,6 +13,7 @@ const sceneTable = "scenes"
|
||||
const sceneIDColumn = "scene_id"
|
||||
const performersScenesTable = "performers_scenes"
|
||||
const scenesTagsTable = "scenes_tags"
|
||||
const scenesGalleriesTable = "scenes_galleries"
|
||||
const moviesScenesTable = "movies_scenes"
|
||||
|
||||
var scenesForPerformerQuery = selectAll(sceneTable) + `
|
||||
@@ -44,6 +45,12 @@ WHERE scenes_tags.tag_id = ?
|
||||
GROUP BY scenes_tags.scene_id
|
||||
`
|
||||
|
||||
var scenesForGalleryQuery = selectAll(sceneTable) + `
|
||||
LEFT JOIN scenes_galleries as galleries_join on galleries_join.scene_id = scenes.id
|
||||
WHERE galleries_join.gallery_id = ?
|
||||
GROUP BY scenes.id
|
||||
`
|
||||
|
||||
var countScenesForMissingChecksumQuery = `
|
||||
SELECT id FROM scenes
|
||||
WHERE scenes.checksum is null
|
||||
@@ -221,6 +228,11 @@ func (qb *sceneQueryBuilder) FindByPerformerID(performerID int) ([]*models.Scene
|
||||
return qb.queryScenes(scenesForPerformerQuery, args)
|
||||
}
|
||||
|
||||
func (qb *sceneQueryBuilder) FindByGalleryID(galleryID int) ([]*models.Scene, error) {
|
||||
args := []interface{}{galleryID}
|
||||
return qb.queryScenes(scenesForGalleryQuery, args)
|
||||
}
|
||||
|
||||
func (qb *sceneQueryBuilder) CountByPerformerID(performerID int) (int, error) {
|
||||
args := []interface{}{performerID}
|
||||
return qb.runCountQuery(qb.buildCountQuery(countScenesForPerformerQuery), args)
|
||||
@@ -293,7 +305,7 @@ func (qb *sceneQueryBuilder) Query(sceneFilter *models.SceneFilterType, findFilt
|
||||
left join performers_scenes as performers_join on performers_join.scene_id = scenes.id
|
||||
left join movies_scenes as movies_join on movies_join.scene_id = scenes.id
|
||||
left join studios as studio on studio.id = scenes.studio_id
|
||||
left join galleries as gallery on gallery.scene_id = scenes.id
|
||||
left join scenes_galleries as galleries_join on galleries_join.scene_id = scenes.id
|
||||
left join scenes_tags as tags_join on tags_join.scene_id = scenes.id
|
||||
left join scene_stash_ids on scene_stash_ids.scene_id = scenes.id
|
||||
`
|
||||
@@ -368,8 +380,8 @@ func (qb *sceneQueryBuilder) Query(sceneFilter *models.SceneFilterType, findFilt
|
||||
|
||||
if isMissingFilter := sceneFilter.IsMissing; isMissingFilter != nil && *isMissingFilter != "" {
|
||||
switch *isMissingFilter {
|
||||
case "gallery":
|
||||
query.addWhere("gallery.scene_id IS NULL")
|
||||
case "galleries":
|
||||
query.addWhere("galleries_join.scene_id IS NULL")
|
||||
case "studio":
|
||||
query.addWhere("scenes.studio_id IS NULL")
|
||||
case "movie":
|
||||
@@ -683,6 +695,26 @@ func (qb *sceneQueryBuilder) UpdateTags(id int, tagIDs []int) error {
|
||||
return qb.tagsRepository().replace(id, tagIDs)
|
||||
}
|
||||
|
||||
func (qb *sceneQueryBuilder) galleriesRepository() *joinRepository {
|
||||
return &joinRepository{
|
||||
repository: repository{
|
||||
tx: qb.tx,
|
||||
tableName: scenesGalleriesTable,
|
||||
idColumn: sceneIDColumn,
|
||||
},
|
||||
fkColumn: galleryIDColumn,
|
||||
}
|
||||
}
|
||||
|
||||
func (qb *sceneQueryBuilder) GetGalleryIDs(id int) ([]int, error) {
|
||||
return qb.galleriesRepository().getIDs(id)
|
||||
}
|
||||
|
||||
func (qb *sceneQueryBuilder) UpdateGalleries(id int, galleryIDs []int) error {
|
||||
// Delete the existing joins and then create new ones
|
||||
return qb.galleriesRepository().replace(id, galleryIDs)
|
||||
}
|
||||
|
||||
func (qb *sceneQueryBuilder) stashIDRepository() *stashIDRepository {
|
||||
return &stashIDRepository{
|
||||
repository{
|
||||
|
||||
@@ -494,7 +494,7 @@ func TestSceneQueryHasMarkers(t *testing.T) {
|
||||
func TestSceneQueryIsMissingGallery(t *testing.T) {
|
||||
withTxn(func(r models.Repository) error {
|
||||
sqb := r.Scene()
|
||||
isMissing := "gallery"
|
||||
isMissing := "galleries"
|
||||
sceneFilter := models.SceneFilterType{
|
||||
IsMissing: &isMissing,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ package sqlite_test
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -192,7 +191,7 @@ func populateDB() error {
|
||||
return fmt.Errorf("error creating studios: %s", err.Error())
|
||||
}
|
||||
|
||||
if err := linkSceneGallery(r.Gallery(), sceneIdxWithGallery, galleryIdxWithScene); err != nil {
|
||||
if err := linkSceneGallery(r.Scene(), sceneIdxWithGallery, galleryIdxWithScene); err != nil {
|
||||
return fmt.Errorf("error linking scene to gallery: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -623,20 +622,8 @@ func linkScenePerformer(qb models.SceneReaderWriter, sceneIndex, performerIndex
|
||||
return err
|
||||
}
|
||||
|
||||
func linkSceneGallery(gqb models.GalleryReaderWriter, sceneIndex, galleryIndex int) error {
|
||||
gallery, err := gqb.Find(galleryIDs[galleryIndex])
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error finding gallery: %s", err.Error())
|
||||
}
|
||||
|
||||
if gallery == nil {
|
||||
return errors.New("gallery is nil")
|
||||
}
|
||||
|
||||
gallery.SceneID = sql.NullInt64{Int64: int64(sceneIDs[sceneIndex]), Valid: true}
|
||||
_, err = gqb.Update(*gallery)
|
||||
|
||||
func linkSceneGallery(qb models.SceneReaderWriter, sceneIndex, galleryIndex int) error {
|
||||
_, err := scene.AddGallery(qb, sceneIDs[sceneIndex], galleryIDs[galleryIndex])
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user