mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
* Support Is (not) null for all multi criterions Add support for the Is null and Is not null modifiers for all cases of the MultiCriterionInput and HierarchicalMultiCriterionInput. This partially overlaps the "X Count" filter which sometimes is available (because it would be the same as "X Count equals 0" and "X Count greater than 0") but this also enables it for other criterions like the "Parent Studio" filter for studios or just the "Studios" filter for scenes / images / galleries, the "Movies" filter for scenes etc. * Don't crash UI on bad saved filter * Add missing code for tag parent/child Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
1318 lines
34 KiB
Go
1318 lines
34 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package sqlite_test
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stashapp/stash/pkg/database"
|
|
"github.com/stashapp/stash/pkg/gallery"
|
|
"github.com/stashapp/stash/pkg/models"
|
|
"github.com/stashapp/stash/pkg/scene"
|
|
"github.com/stashapp/stash/pkg/sqlite"
|
|
"github.com/stashapp/stash/pkg/utils"
|
|
)
|
|
|
|
const (
|
|
spacedSceneTitle = "zzz yyy xxx"
|
|
)
|
|
|
|
const (
|
|
sceneIdxWithMovie = iota
|
|
sceneIdxWithGallery
|
|
sceneIdxWithPerformer
|
|
sceneIdx1WithPerformer
|
|
sceneIdx2WithPerformer
|
|
sceneIdxWithTwoPerformers
|
|
sceneIdxWithTag
|
|
sceneIdxWithTwoTags
|
|
sceneIdxWithMarkerAndTag
|
|
sceneIdxWithStudio
|
|
sceneIdx1WithStudio
|
|
sceneIdx2WithStudio
|
|
sceneIdxWithMarkers
|
|
sceneIdxWithPerformerTag
|
|
sceneIdxWithPerformerTwoTags
|
|
sceneIdxWithSpacedName
|
|
sceneIdxWithStudioPerformer
|
|
sceneIdxWithGrandChildStudio
|
|
// new indexes above
|
|
lastSceneIdx
|
|
|
|
totalScenes = lastSceneIdx + 3
|
|
)
|
|
|
|
const (
|
|
imageIdxWithGallery = iota
|
|
imageIdx1WithGallery
|
|
imageIdx2WithGallery
|
|
imageIdxWithTwoGalleries
|
|
imageIdxWithPerformer
|
|
imageIdx1WithPerformer
|
|
imageIdx2WithPerformer
|
|
imageIdxWithTwoPerformers
|
|
imageIdxWithTag
|
|
imageIdxWithTwoTags
|
|
imageIdxWithStudio
|
|
imageIdx1WithStudio
|
|
imageIdx2WithStudio
|
|
imageIdxWithStudioPerformer
|
|
imageIdxInZip // TODO - not implemented
|
|
imageIdxWithPerformerTag
|
|
imageIdxWithPerformerTwoTags
|
|
imageIdxWithGrandChildStudio
|
|
// new indexes above
|
|
totalImages
|
|
)
|
|
|
|
const (
|
|
performerIdxWithScene = iota
|
|
performerIdx1WithScene
|
|
performerIdx2WithScene
|
|
performerIdxWithTwoScenes
|
|
performerIdxWithImage
|
|
performerIdxWithTwoImages
|
|
performerIdx1WithImage
|
|
performerIdx2WithImage
|
|
performerIdxWithTag
|
|
performerIdxWithTwoTags
|
|
performerIdxWithGallery
|
|
performerIdxWithTwoGalleries
|
|
performerIdx1WithGallery
|
|
performerIdx2WithGallery
|
|
performerIdxWithSceneStudio
|
|
performerIdxWithImageStudio
|
|
performerIdxWithGalleryStudio
|
|
// new indexes above
|
|
// performers with dup names start from the end
|
|
performerIdx1WithDupName
|
|
performerIdxWithDupName
|
|
|
|
performersNameCase = performerIdx1WithDupName
|
|
performersNameNoCase = 2
|
|
)
|
|
|
|
const (
|
|
movieIdxWithScene = iota
|
|
movieIdxWithStudio
|
|
// movies with dup names start from the end
|
|
// create 10 more basic movies (can remove this if we add more indexes)
|
|
movieIdxWithDupName = movieIdxWithStudio + 10
|
|
|
|
moviesNameCase = movieIdxWithDupName
|
|
moviesNameNoCase = 1
|
|
)
|
|
|
|
const (
|
|
galleryIdxWithScene = iota
|
|
galleryIdxWithImage
|
|
galleryIdx1WithImage
|
|
galleryIdx2WithImage
|
|
galleryIdxWithTwoImages
|
|
galleryIdxWithPerformer
|
|
galleryIdx1WithPerformer
|
|
galleryIdx2WithPerformer
|
|
galleryIdxWithTwoPerformers
|
|
galleryIdxWithTag
|
|
galleryIdxWithTwoTags
|
|
galleryIdxWithStudio
|
|
galleryIdx1WithStudio
|
|
galleryIdx2WithStudio
|
|
galleryIdxWithPerformerTag
|
|
galleryIdxWithPerformerTwoTags
|
|
galleryIdxWithStudioPerformer
|
|
galleryIdxWithGrandChildStudio
|
|
// new indexes above
|
|
lastGalleryIdx
|
|
|
|
totalGalleries = lastGalleryIdx + 1
|
|
)
|
|
|
|
const (
|
|
tagIdxWithScene = iota
|
|
tagIdx1WithScene
|
|
tagIdx2WithScene
|
|
tagIdx3WithScene
|
|
tagIdxWithPrimaryMarkers
|
|
tagIdxWithMarkers
|
|
tagIdxWithCoverImage
|
|
tagIdxWithImage
|
|
tagIdx1WithImage
|
|
tagIdx2WithImage
|
|
tagIdxWithPerformer
|
|
tagIdx1WithPerformer
|
|
tagIdx2WithPerformer
|
|
tagIdxWithGallery
|
|
tagIdx1WithGallery
|
|
tagIdx2WithGallery
|
|
tagIdxWithChildTag
|
|
tagIdxWithParentTag
|
|
tagIdxWithGrandChild
|
|
tagIdxWithParentAndChild
|
|
tagIdxWithGrandParent
|
|
// new indexes above
|
|
// tags with dup names start from the end
|
|
tagIdx1WithDupName
|
|
tagIdxWithDupName
|
|
|
|
tagsNameNoCase = 2
|
|
tagsNameCase = tagIdx1WithDupName
|
|
)
|
|
|
|
const (
|
|
studioIdxWithScene = iota
|
|
studioIdxWithTwoScenes
|
|
studioIdxWithMovie
|
|
studioIdxWithChildStudio
|
|
studioIdxWithParentStudio
|
|
studioIdxWithImage
|
|
studioIdxWithTwoImages
|
|
studioIdxWithGallery
|
|
studioIdxWithTwoGalleries
|
|
studioIdxWithScenePerformer
|
|
studioIdxWithImagePerformer
|
|
studioIdxWithGalleryPerformer
|
|
studioIdxWithGrandChild
|
|
studioIdxWithParentAndChild
|
|
studioIdxWithGrandParent
|
|
// new indexes above
|
|
// studios with dup names start from the end
|
|
studioIdxWithDupName
|
|
|
|
studiosNameCase = studioIdxWithDupName
|
|
studiosNameNoCase = 1
|
|
)
|
|
|
|
const (
|
|
markerIdxWithScene = iota
|
|
markerIdxWithTag
|
|
markerIdxWithSceneTag
|
|
totalMarkers
|
|
)
|
|
|
|
const (
|
|
savedFilterIdxDefaultScene = iota
|
|
savedFilterIdxDefaultImage
|
|
savedFilterIdxScene
|
|
savedFilterIdxImage
|
|
|
|
// new indexes above
|
|
totalSavedFilters
|
|
)
|
|
|
|
const (
|
|
pathField = "Path"
|
|
checksumField = "Checksum"
|
|
titleField = "Title"
|
|
urlField = "URL"
|
|
zipPath = "zipPath.zip"
|
|
firstSavedFilterName = "firstSavedFilterName"
|
|
)
|
|
|
|
var (
|
|
sceneIDs []int
|
|
imageIDs []int
|
|
performerIDs []int
|
|
movieIDs []int
|
|
galleryIDs []int
|
|
tagIDs []int
|
|
studioIDs []int
|
|
markerIDs []int
|
|
savedFilterIDs []int
|
|
|
|
tagNames []string
|
|
studioNames []string
|
|
movieNames []string
|
|
performerNames []string
|
|
)
|
|
|
|
type idAssociation struct {
|
|
first int
|
|
second int
|
|
}
|
|
|
|
var (
|
|
sceneTagLinks = [][2]int{
|
|
{sceneIdxWithTag, tagIdxWithScene},
|
|
{sceneIdxWithTwoTags, tagIdx1WithScene},
|
|
{sceneIdxWithTwoTags, tagIdx2WithScene},
|
|
{sceneIdxWithMarkerAndTag, tagIdx3WithScene},
|
|
}
|
|
|
|
scenePerformerLinks = [][2]int{
|
|
{sceneIdxWithPerformer, performerIdxWithScene},
|
|
{sceneIdxWithTwoPerformers, performerIdx1WithScene},
|
|
{sceneIdxWithTwoPerformers, performerIdx2WithScene},
|
|
{sceneIdxWithPerformerTag, performerIdxWithTag},
|
|
{sceneIdxWithPerformerTwoTags, performerIdxWithTwoTags},
|
|
{sceneIdx1WithPerformer, performerIdxWithTwoScenes},
|
|
{sceneIdx2WithPerformer, performerIdxWithTwoScenes},
|
|
{sceneIdxWithStudioPerformer, performerIdxWithSceneStudio},
|
|
}
|
|
|
|
sceneGalleryLinks = [][2]int{
|
|
{sceneIdxWithGallery, galleryIdxWithScene},
|
|
}
|
|
|
|
sceneMovieLinks = [][2]int{
|
|
{sceneIdxWithMovie, movieIdxWithScene},
|
|
}
|
|
|
|
sceneStudioLinks = [][2]int{
|
|
{sceneIdxWithStudio, studioIdxWithScene},
|
|
{sceneIdx1WithStudio, studioIdxWithTwoScenes},
|
|
{sceneIdx2WithStudio, studioIdxWithTwoScenes},
|
|
{sceneIdxWithStudioPerformer, studioIdxWithScenePerformer},
|
|
{sceneIdxWithGrandChildStudio, studioIdxWithGrandParent},
|
|
}
|
|
)
|
|
|
|
type markerSpec struct {
|
|
sceneIdx int
|
|
primaryTagIdx int
|
|
tagIdxs []int
|
|
}
|
|
|
|
var (
|
|
// indexed by marker
|
|
markerSpecs = []markerSpec{
|
|
{sceneIdxWithMarkers, tagIdxWithPrimaryMarkers, nil},
|
|
{sceneIdxWithMarkers, tagIdxWithPrimaryMarkers, []int{tagIdxWithMarkers}},
|
|
{sceneIdxWithMarkerAndTag, tagIdxWithPrimaryMarkers, nil},
|
|
}
|
|
)
|
|
|
|
var (
|
|
imageGalleryLinks = [][2]int{
|
|
{imageIdxWithGallery, galleryIdxWithImage},
|
|
{imageIdx1WithGallery, galleryIdxWithTwoImages},
|
|
{imageIdx2WithGallery, galleryIdxWithTwoImages},
|
|
{imageIdxWithTwoGalleries, galleryIdx1WithImage},
|
|
{imageIdxWithTwoGalleries, galleryIdx2WithImage},
|
|
}
|
|
imageStudioLinks = [][2]int{
|
|
{imageIdxWithStudio, studioIdxWithImage},
|
|
{imageIdx1WithStudio, studioIdxWithTwoImages},
|
|
{imageIdx2WithStudio, studioIdxWithTwoImages},
|
|
{imageIdxWithStudioPerformer, studioIdxWithImagePerformer},
|
|
{imageIdxWithGrandChildStudio, studioIdxWithGrandParent},
|
|
}
|
|
imageTagLinks = [][2]int{
|
|
{imageIdxWithTag, tagIdxWithImage},
|
|
{imageIdxWithTwoTags, tagIdx1WithImage},
|
|
{imageIdxWithTwoTags, tagIdx2WithImage},
|
|
}
|
|
imagePerformerLinks = [][2]int{
|
|
{imageIdxWithPerformer, performerIdxWithImage},
|
|
{imageIdxWithTwoPerformers, performerIdx1WithImage},
|
|
{imageIdxWithTwoPerformers, performerIdx2WithImage},
|
|
{imageIdxWithPerformerTag, performerIdxWithTag},
|
|
{imageIdxWithPerformerTwoTags, performerIdxWithTwoTags},
|
|
{imageIdx1WithPerformer, performerIdxWithTwoImages},
|
|
{imageIdx2WithPerformer, performerIdxWithTwoImages},
|
|
{imageIdxWithStudioPerformer, performerIdxWithImageStudio},
|
|
}
|
|
)
|
|
|
|
var (
|
|
galleryPerformerLinks = [][2]int{
|
|
{galleryIdxWithPerformer, performerIdxWithGallery},
|
|
{galleryIdxWithTwoPerformers, performerIdx1WithGallery},
|
|
{galleryIdxWithTwoPerformers, performerIdx2WithGallery},
|
|
{galleryIdxWithPerformerTag, performerIdxWithTag},
|
|
{galleryIdxWithPerformerTwoTags, performerIdxWithTwoTags},
|
|
{galleryIdx1WithPerformer, performerIdxWithTwoGalleries},
|
|
{galleryIdx2WithPerformer, performerIdxWithTwoGalleries},
|
|
{galleryIdxWithStudioPerformer, performerIdxWithGalleryStudio},
|
|
}
|
|
|
|
galleryStudioLinks = [][2]int{
|
|
{galleryIdxWithStudio, studioIdxWithGallery},
|
|
{galleryIdx1WithStudio, studioIdxWithTwoGalleries},
|
|
{galleryIdx2WithStudio, studioIdxWithTwoGalleries},
|
|
{galleryIdxWithStudioPerformer, studioIdxWithGalleryPerformer},
|
|
{galleryIdxWithGrandChildStudio, studioIdxWithGrandParent},
|
|
}
|
|
|
|
galleryTagLinks = [][2]int{
|
|
{galleryIdxWithTag, tagIdxWithGallery},
|
|
{galleryIdxWithTwoTags, tagIdx1WithGallery},
|
|
{galleryIdxWithTwoTags, tagIdx2WithGallery},
|
|
}
|
|
)
|
|
|
|
var (
|
|
movieStudioLinks = [][2]int{
|
|
{movieIdxWithStudio, studioIdxWithMovie},
|
|
}
|
|
)
|
|
|
|
var (
|
|
studioParentLinks = [][2]int{
|
|
{studioIdxWithChildStudio, studioIdxWithParentStudio},
|
|
{studioIdxWithGrandChild, studioIdxWithParentAndChild},
|
|
{studioIdxWithParentAndChild, studioIdxWithGrandParent},
|
|
}
|
|
)
|
|
|
|
var (
|
|
performerTagLinks = [][2]int{
|
|
{performerIdxWithTag, tagIdxWithPerformer},
|
|
{performerIdxWithTwoTags, tagIdx1WithPerformer},
|
|
{performerIdxWithTwoTags, tagIdx2WithPerformer},
|
|
}
|
|
)
|
|
|
|
var (
|
|
tagParentLinks = [][2]int{
|
|
{tagIdxWithChildTag, tagIdxWithParentTag},
|
|
{tagIdxWithGrandChild, tagIdxWithParentAndChild},
|
|
{tagIdxWithParentAndChild, tagIdxWithGrandParent},
|
|
}
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
ret := runTests(m)
|
|
os.Exit(ret)
|
|
}
|
|
|
|
func withTxn(f func(r models.Repository) error) error {
|
|
t := sqlite.NewTransactionManager()
|
|
return t.WithTxn(context.TODO(), f)
|
|
}
|
|
|
|
func withRollbackTxn(f func(r models.Repository) error) error {
|
|
var ret error
|
|
withTxn(func(repo models.Repository) error {
|
|
ret = f(repo)
|
|
return errors.New("fake error for rollback")
|
|
})
|
|
|
|
return ret
|
|
}
|
|
|
|
func testTeardown(databaseFile string) {
|
|
err := database.DB.Close()
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = os.Remove(databaseFile)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func runTests(m *testing.M) int {
|
|
// create the database file
|
|
f, err := os.CreateTemp("", "*.sqlite")
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Could not create temporary file: %s", err.Error()))
|
|
}
|
|
|
|
f.Close()
|
|
databaseFile := f.Name()
|
|
database.Initialize(databaseFile)
|
|
|
|
// defer close and delete the database
|
|
defer testTeardown(databaseFile)
|
|
|
|
err = populateDB()
|
|
if err != nil {
|
|
panic(fmt.Sprintf("Could not populate database: %s", err.Error()))
|
|
} else {
|
|
// run the tests
|
|
return m.Run()
|
|
}
|
|
}
|
|
|
|
func populateDB() error {
|
|
if err := withTxn(func(r models.Repository) error {
|
|
if err := createScenes(r.Scene(), totalScenes); err != nil {
|
|
return fmt.Errorf("error creating scenes: %s", err.Error())
|
|
}
|
|
|
|
if err := createImages(r.Image(), totalImages); err != nil {
|
|
return fmt.Errorf("error creating images: %s", err.Error())
|
|
}
|
|
|
|
if err := createGalleries(r.Gallery(), totalGalleries); err != nil {
|
|
return fmt.Errorf("error creating galleries: %s", err.Error())
|
|
}
|
|
|
|
if err := createMovies(r.Movie(), moviesNameCase, moviesNameNoCase); err != nil {
|
|
return fmt.Errorf("error creating movies: %s", err.Error())
|
|
}
|
|
|
|
if err := createPerformers(r.Performer(), performersNameCase, performersNameNoCase); err != nil {
|
|
return fmt.Errorf("error creating performers: %s", err.Error())
|
|
}
|
|
|
|
if err := createTags(r.Tag(), tagsNameCase, tagsNameNoCase); err != nil {
|
|
return fmt.Errorf("error creating tags: %s", err.Error())
|
|
}
|
|
|
|
if err := addTagImage(r.Tag(), tagIdxWithCoverImage); err != nil {
|
|
return fmt.Errorf("error adding tag image: %s", err.Error())
|
|
}
|
|
|
|
if err := createStudios(r.Studio(), studiosNameCase, studiosNameNoCase); err != nil {
|
|
return fmt.Errorf("error creating studios: %s", err.Error())
|
|
}
|
|
|
|
if err := createSavedFilters(r.SavedFilter(), totalSavedFilters); err != nil {
|
|
return fmt.Errorf("error creating saved filters: %s", err.Error())
|
|
}
|
|
|
|
if err := linkPerformerTags(r.Performer()); err != nil {
|
|
return fmt.Errorf("error linking performer tags: %s", err.Error())
|
|
}
|
|
|
|
if err := linkSceneGalleries(r.Scene()); err != nil {
|
|
return fmt.Errorf("error linking scenes to galleries: %s", err.Error())
|
|
}
|
|
|
|
if err := linkSceneMovies(r.Scene()); err != nil {
|
|
return fmt.Errorf("error linking scenes to movies: %s", err.Error())
|
|
}
|
|
|
|
if err := linkScenePerformers(r.Scene()); err != nil {
|
|
return fmt.Errorf("error linking scene performers: %s", err.Error())
|
|
}
|
|
|
|
if err := linkSceneTags(r.Scene()); err != nil {
|
|
return fmt.Errorf("error linking scene tags: %s", err.Error())
|
|
}
|
|
|
|
if err := linkSceneStudios(r.Scene()); err != nil {
|
|
return fmt.Errorf("error linking scene studios: %s", err.Error())
|
|
}
|
|
|
|
if err := linkImageGalleries(r.Gallery()); err != nil {
|
|
return fmt.Errorf("error linking gallery images: %s", err.Error())
|
|
}
|
|
|
|
if err := linkImagePerformers(r.Image()); err != nil {
|
|
return fmt.Errorf("error linking image performers: %s", err.Error())
|
|
}
|
|
|
|
if err := linkImageTags(r.Image()); err != nil {
|
|
return fmt.Errorf("error linking image tags: %s", err.Error())
|
|
}
|
|
|
|
if err := linkImageStudios(r.Image()); err != nil {
|
|
return fmt.Errorf("error linking image studio: %s", err.Error())
|
|
}
|
|
|
|
if err := linkMovieStudios(r.Movie()); err != nil {
|
|
return fmt.Errorf("error linking movie studios: %s", err.Error())
|
|
}
|
|
|
|
if err := linkStudiosParent(r.Studio()); err != nil {
|
|
return fmt.Errorf("error linking studios parent: %s", err.Error())
|
|
}
|
|
|
|
if err := linkGalleryPerformers(r.Gallery()); err != nil {
|
|
return fmt.Errorf("error linking gallery performers: %s", err.Error())
|
|
}
|
|
|
|
if err := linkGalleryTags(r.Gallery()); err != nil {
|
|
return fmt.Errorf("error linking gallery tags: %s", err.Error())
|
|
}
|
|
|
|
if err := linkGalleryStudios(r.Gallery()); err != nil {
|
|
return fmt.Errorf("error linking gallery studios: %s", err.Error())
|
|
}
|
|
|
|
if err := linkTagsParent(r.Tag()); err != nil {
|
|
return fmt.Errorf("error linking tags parent: %s", err.Error())
|
|
}
|
|
|
|
for _, ms := range markerSpecs {
|
|
if err := createMarker(r.SceneMarker(), ms); err != nil {
|
|
return fmt.Errorf("error creating scene marker: %s", err.Error())
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getPrefixedStringValue(prefix string, index int, field string) string {
|
|
return fmt.Sprintf("%s_%04d_%s", prefix, index, field)
|
|
}
|
|
|
|
func getPrefixedNullStringValue(prefix string, index int, field string) sql.NullString {
|
|
if index > 0 && index%5 == 0 {
|
|
return sql.NullString{}
|
|
}
|
|
if index > 0 && index%6 == 0 {
|
|
return sql.NullString{
|
|
String: "",
|
|
Valid: true,
|
|
}
|
|
}
|
|
return sql.NullString{
|
|
String: getPrefixedStringValue(prefix, index, field),
|
|
Valid: true,
|
|
}
|
|
}
|
|
|
|
func getSceneStringValue(index int, field string) string {
|
|
return getPrefixedStringValue("scene", index, field)
|
|
}
|
|
|
|
func getSceneNullStringValue(index int, field string) sql.NullString {
|
|
return getPrefixedNullStringValue("scene", index, field)
|
|
}
|
|
|
|
func getSceneTitle(index int) string {
|
|
switch index {
|
|
case sceneIdxWithSpacedName:
|
|
return spacedSceneTitle
|
|
default:
|
|
return getSceneStringValue(index, titleField)
|
|
}
|
|
}
|
|
|
|
func getRating(index int) sql.NullInt64 {
|
|
rating := index % 6
|
|
return sql.NullInt64{Int64: int64(rating), Valid: rating > 0}
|
|
}
|
|
|
|
func getOCounter(index int) int {
|
|
return index % 3
|
|
}
|
|
|
|
func getSceneDuration(index int) sql.NullFloat64 {
|
|
duration := index % 4
|
|
duration = duration * 100
|
|
|
|
return sql.NullFloat64{
|
|
Float64: float64(duration) + 0.432,
|
|
Valid: duration != 0,
|
|
}
|
|
}
|
|
|
|
func getHeight(index int) sql.NullInt64 {
|
|
heights := []int64{0, 200, 240, 300, 480, 700, 720, 800, 1080, 1500, 2160, 3000}
|
|
height := heights[index%len(heights)]
|
|
return sql.NullInt64{
|
|
Int64: height,
|
|
Valid: height != 0,
|
|
}
|
|
}
|
|
|
|
func getWidth(index int) sql.NullInt64 {
|
|
height := getHeight(index)
|
|
return sql.NullInt64{
|
|
Int64: height.Int64 * 2,
|
|
Valid: height.Valid,
|
|
}
|
|
}
|
|
|
|
func getSceneDate(index int) models.SQLiteDate {
|
|
dates := []string{"null", "", "0001-01-01", "2001-02-03"}
|
|
date := dates[index%len(dates)]
|
|
return models.SQLiteDate{
|
|
String: date,
|
|
Valid: date != "null",
|
|
}
|
|
}
|
|
|
|
func createScenes(sqb models.SceneReaderWriter, n int) error {
|
|
for i := 0; i < n; i++ {
|
|
scene := models.Scene{
|
|
Path: getSceneStringValue(i, pathField),
|
|
Title: sql.NullString{String: getSceneTitle(i), Valid: true},
|
|
Checksum: sql.NullString{String: getSceneStringValue(i, checksumField), Valid: true},
|
|
Details: sql.NullString{String: getSceneStringValue(i, "Details"), Valid: true},
|
|
URL: getSceneNullStringValue(i, urlField),
|
|
Rating: getRating(i),
|
|
OCounter: getOCounter(i),
|
|
Duration: getSceneDuration(i),
|
|
Height: getHeight(i),
|
|
Width: getWidth(i),
|
|
Date: getSceneDate(i),
|
|
}
|
|
|
|
created, err := sqb.Create(scene)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating scene %v+: %s", scene, err.Error())
|
|
}
|
|
|
|
sceneIDs = append(sceneIDs, created.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getImageStringValue(index int, field string) string {
|
|
return fmt.Sprintf("image_%04d_%s", index, field)
|
|
}
|
|
|
|
func getImagePath(index int) string {
|
|
// TODO - currently not working
|
|
// if index == imageIdxInZip {
|
|
// return image.ZipFilename(zipPath, "image_0001_Path")
|
|
// }
|
|
|
|
return getImageStringValue(index, pathField)
|
|
}
|
|
|
|
func createImages(qb models.ImageReaderWriter, n int) error {
|
|
for i := 0; i < n; i++ {
|
|
image := models.Image{
|
|
Path: getImagePath(i),
|
|
Title: sql.NullString{String: getImageStringValue(i, titleField), Valid: true},
|
|
Checksum: getImageStringValue(i, checksumField),
|
|
Rating: getRating(i),
|
|
OCounter: getOCounter(i),
|
|
Height: getHeight(i),
|
|
Width: getWidth(i),
|
|
}
|
|
|
|
created, err := qb.Create(image)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating image %v+: %s", image, err.Error())
|
|
}
|
|
|
|
imageIDs = append(imageIDs, created.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getGalleryStringValue(index int, field string) string {
|
|
return getPrefixedStringValue("gallery", index, field)
|
|
}
|
|
|
|
func getGalleryNullStringValue(index int, field string) sql.NullString {
|
|
return getPrefixedNullStringValue("gallery", index, field)
|
|
}
|
|
|
|
func createGalleries(gqb models.GalleryReaderWriter, n int) error {
|
|
for i := 0; i < n; i++ {
|
|
gallery := models.Gallery{
|
|
Path: models.NullString(getGalleryStringValue(i, pathField)),
|
|
Title: models.NullString(getGalleryStringValue(i, titleField)),
|
|
URL: getGalleryNullStringValue(i, urlField),
|
|
Checksum: getGalleryStringValue(i, checksumField),
|
|
Rating: getRating(i),
|
|
}
|
|
|
|
created, err := gqb.Create(gallery)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating gallery %v+: %s", gallery, err.Error())
|
|
}
|
|
|
|
galleryIDs = append(galleryIDs, created.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getMovieStringValue(index int, field string) string {
|
|
return getPrefixedStringValue("movie", index, field)
|
|
}
|
|
|
|
func getMovieNullStringValue(index int, field string) sql.NullString {
|
|
return getPrefixedNullStringValue("movie", index, field)
|
|
}
|
|
|
|
// createMoviees creates n movies with plain Name and o movies with camel cased NaMe included
|
|
func createMovies(mqb models.MovieReaderWriter, n int, o int) error {
|
|
const namePlain = "Name"
|
|
const nameNoCase = "NaMe"
|
|
|
|
for i := 0; i < n+o; i++ {
|
|
index := i
|
|
name := namePlain
|
|
|
|
if i >= n { // i<n tags get normal names
|
|
name = nameNoCase // i>=n movies get dup names if case is not checked
|
|
index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also
|
|
} // so count backwards to 0 as needed
|
|
// movies [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
|
|
|
name = getMovieStringValue(index, name)
|
|
movie := models.Movie{
|
|
Name: sql.NullString{String: name, Valid: true},
|
|
URL: getMovieNullStringValue(index, urlField),
|
|
Checksum: utils.MD5FromString(name),
|
|
}
|
|
|
|
created, err := mqb.Create(movie)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating movie [%d] %v+: %s", i, movie, err.Error())
|
|
}
|
|
|
|
movieIDs = append(movieIDs, created.ID)
|
|
movieNames = append(movieNames, created.Name.String)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getPerformerStringValue(index int, field string) string {
|
|
return getPrefixedStringValue("performer", index, field)
|
|
}
|
|
|
|
func getPerformerNullStringValue(index int, field string) sql.NullString {
|
|
return getPrefixedNullStringValue("performer", index, field)
|
|
}
|
|
|
|
func getPerformerBoolValue(index int) bool {
|
|
index = index % 2
|
|
return index == 1
|
|
}
|
|
|
|
func getPerformerBirthdate(index int) string {
|
|
const minAge = 18
|
|
birthdate := time.Now()
|
|
birthdate = birthdate.AddDate(-minAge-index, -1, -1)
|
|
return birthdate.Format("2006-01-02")
|
|
}
|
|
|
|
func getPerformerDeathDate(index int) models.SQLiteDate {
|
|
if index != 5 {
|
|
return models.SQLiteDate{}
|
|
}
|
|
|
|
deathDate := time.Now()
|
|
deathDate = deathDate.AddDate(-index+1, -1, -1)
|
|
return models.SQLiteDate{
|
|
String: deathDate.Format("2006-01-02"),
|
|
Valid: true,
|
|
}
|
|
}
|
|
|
|
func getPerformerCareerLength(index int) *string {
|
|
if index%5 == 0 {
|
|
return nil
|
|
}
|
|
|
|
ret := fmt.Sprintf("20%2d", index)
|
|
return &ret
|
|
}
|
|
|
|
// createPerformers creates n performers with plain Name and o performers with camel cased NaMe included
|
|
func createPerformers(pqb models.PerformerReaderWriter, n int, o int) error {
|
|
const namePlain = "Name"
|
|
const nameNoCase = "NaMe"
|
|
|
|
name := namePlain
|
|
|
|
for i := 0; i < n+o; i++ {
|
|
index := i
|
|
|
|
if i >= n { // i<n tags get normal names
|
|
name = nameNoCase // i>=n performers get dup names if case is not checked
|
|
index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also
|
|
} // so count backwards to 0 as needed
|
|
// performers [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
|
|
|
performer := models.Performer{
|
|
Name: sql.NullString{String: getPerformerStringValue(index, name), Valid: true},
|
|
Checksum: getPerformerStringValue(i, checksumField),
|
|
URL: getPerformerNullStringValue(i, urlField),
|
|
Favorite: sql.NullBool{Bool: getPerformerBoolValue(i), Valid: true},
|
|
Birthdate: models.SQLiteDate{
|
|
String: getPerformerBirthdate(i),
|
|
Valid: true,
|
|
},
|
|
DeathDate: getPerformerDeathDate(i),
|
|
Details: sql.NullString{String: getPerformerStringValue(i, "Details"), Valid: true},
|
|
Ethnicity: sql.NullString{String: getPerformerStringValue(i, "Ethnicity"), Valid: true},
|
|
Rating: getRating(i),
|
|
}
|
|
|
|
careerLength := getPerformerCareerLength(i)
|
|
if careerLength != nil {
|
|
performer.CareerLength = models.NullString(*careerLength)
|
|
}
|
|
|
|
created, err := pqb.Create(performer)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating performer %v+: %s", performer, err.Error())
|
|
}
|
|
|
|
performerIDs = append(performerIDs, created.ID)
|
|
performerNames = append(performerNames, created.Name.String)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getTagStringValue(index int, field string) string {
|
|
return "tag_" + strconv.FormatInt(int64(index), 10) + "_" + field
|
|
}
|
|
|
|
func getTagSceneCount(id int) int {
|
|
if id == tagIDs[tagIdx1WithScene] || id == tagIDs[tagIdx2WithScene] || id == tagIDs[tagIdxWithScene] || id == tagIDs[tagIdx3WithScene] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func getTagMarkerCount(id int) int {
|
|
if id == tagIDs[tagIdxWithPrimaryMarkers] {
|
|
return 3
|
|
}
|
|
|
|
if id == tagIDs[tagIdxWithMarkers] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func getTagImageCount(id int) int {
|
|
if id == tagIDs[tagIdx1WithImage] || id == tagIDs[tagIdx2WithImage] || id == tagIDs[tagIdxWithImage] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func getTagGalleryCount(id int) int {
|
|
if id == tagIDs[tagIdx1WithGallery] || id == tagIDs[tagIdx2WithGallery] || id == tagIDs[tagIdxWithGallery] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func getTagPerformerCount(id int) int {
|
|
if id == tagIDs[tagIdx1WithPerformer] || id == tagIDs[tagIdx2WithPerformer] || id == tagIDs[tagIdxWithPerformer] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func getTagParentCount(id int) int {
|
|
if id == tagIDs[tagIdxWithParentTag] || id == tagIDs[tagIdxWithGrandParent] || id == tagIDs[tagIdxWithParentAndChild] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func getTagChildCount(id int) int {
|
|
if id == tagIDs[tagIdxWithChildTag] || id == tagIDs[tagIdxWithGrandChild] || id == tagIDs[tagIdxWithParentAndChild] {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
//createTags creates n tags with plain Name and o tags with camel cased NaMe included
|
|
func createTags(tqb models.TagReaderWriter, n int, o int) error {
|
|
const namePlain = "Name"
|
|
const nameNoCase = "NaMe"
|
|
|
|
name := namePlain
|
|
|
|
for i := 0; i < n+o; i++ {
|
|
index := i
|
|
|
|
if i >= n { // i<n tags get normal names
|
|
name = nameNoCase // i>=n tags get dup names if case is not checked
|
|
index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also
|
|
} // so count backwards to 0 as needed
|
|
// tags [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
|
|
|
tag := models.Tag{
|
|
Name: getTagStringValue(index, name),
|
|
}
|
|
|
|
created, err := tqb.Create(tag)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating tag %v+: %s", tag, err.Error())
|
|
}
|
|
|
|
// add alias
|
|
alias := getTagStringValue(i, "Alias")
|
|
if err := tqb.UpdateAliases(created.ID, []string{alias}); err != nil {
|
|
return fmt.Errorf("error setting tag alias: %s", err.Error())
|
|
}
|
|
|
|
tagIDs = append(tagIDs, created.ID)
|
|
tagNames = append(tagNames, created.Name)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getStudioStringValue(index int, field string) string {
|
|
return getPrefixedStringValue("studio", index, field)
|
|
}
|
|
|
|
func getStudioNullStringValue(index int, field string) sql.NullString {
|
|
return getPrefixedNullStringValue("studio", index, field)
|
|
}
|
|
|
|
func createStudio(sqb models.StudioReaderWriter, name string, parentID *int64) (*models.Studio, error) {
|
|
studio := models.Studio{
|
|
Name: sql.NullString{String: name, Valid: true},
|
|
Checksum: utils.MD5FromString(name),
|
|
}
|
|
|
|
if parentID != nil {
|
|
studio.ParentID = sql.NullInt64{Int64: *parentID, Valid: true}
|
|
}
|
|
|
|
return createStudioFromModel(sqb, studio)
|
|
}
|
|
|
|
func createStudioFromModel(sqb models.StudioReaderWriter, studio models.Studio) (*models.Studio, error) {
|
|
created, err := sqb.Create(studio)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error creating studio %v+: %s", studio, err.Error())
|
|
}
|
|
|
|
return created, nil
|
|
}
|
|
|
|
// createStudios creates n studios with plain Name and o studios with camel cased NaMe included
|
|
func createStudios(sqb models.StudioReaderWriter, n int, o int) error {
|
|
const namePlain = "Name"
|
|
const nameNoCase = "NaMe"
|
|
|
|
for i := 0; i < n+o; i++ {
|
|
index := i
|
|
name := namePlain
|
|
|
|
if i >= n { // i<n studios get normal names
|
|
name = nameNoCase // i>=n studios get dup names if case is not checked
|
|
index = n + o - (i + 1) // for the name to be the same the number (index) must be the same also
|
|
} // so count backwards to 0 as needed
|
|
// studios [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
|
|
|
name = getStudioStringValue(index, name)
|
|
studio := models.Studio{
|
|
Name: sql.NullString{String: name, Valid: true},
|
|
Checksum: utils.MD5FromString(name),
|
|
URL: getStudioNullStringValue(index, urlField),
|
|
}
|
|
created, err := createStudioFromModel(sqb, studio)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// add alias
|
|
alias := getStudioStringValue(i, "Alias")
|
|
if err := sqb.UpdateAliases(created.ID, []string{alias}); err != nil {
|
|
return fmt.Errorf("error setting studio alias: %s", err.Error())
|
|
}
|
|
|
|
studioIDs = append(studioIDs, created.ID)
|
|
studioNames = append(studioNames, created.Name.String)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func createMarker(mqb models.SceneMarkerReaderWriter, markerSpec markerSpec) error {
|
|
marker := models.SceneMarker{
|
|
SceneID: sql.NullInt64{Int64: int64(sceneIDs[markerSpec.sceneIdx]), Valid: true},
|
|
PrimaryTagID: tagIDs[markerSpec.primaryTagIdx],
|
|
}
|
|
|
|
created, err := mqb.Create(marker)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("error creating marker %v+: %w", marker, err)
|
|
}
|
|
|
|
markerIDs = append(markerIDs, created.ID)
|
|
|
|
if len(markerSpec.tagIdxs) > 0 {
|
|
newTagIDs := []int{}
|
|
|
|
for _, tagIdx := range markerSpec.tagIdxs {
|
|
newTagIDs = append(newTagIDs, tagIDs[tagIdx])
|
|
}
|
|
|
|
if err := mqb.UpdateTags(created.ID, newTagIDs); err != nil {
|
|
return fmt.Errorf("error creating marker/tag join: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getSavedFilterMode(index int) models.FilterMode {
|
|
switch index {
|
|
case savedFilterIdxScene, savedFilterIdxDefaultScene:
|
|
return models.FilterModeScenes
|
|
case savedFilterIdxImage, savedFilterIdxDefaultImage:
|
|
return models.FilterModeImages
|
|
default:
|
|
return models.FilterModeScenes
|
|
}
|
|
}
|
|
|
|
func getSavedFilterName(index int) string {
|
|
if index <= savedFilterIdxDefaultImage {
|
|
// empty string for default filters
|
|
return ""
|
|
}
|
|
|
|
if index <= savedFilterIdxImage {
|
|
// use the same name for the first two - should be possible
|
|
return firstSavedFilterName
|
|
}
|
|
|
|
return getPrefixedStringValue("savedFilter", index, "Name")
|
|
}
|
|
|
|
func createSavedFilters(qb models.SavedFilterReaderWriter, n int) error {
|
|
for i := 0; i < n; i++ {
|
|
savedFilter := models.SavedFilter{
|
|
Mode: getSavedFilterMode(i),
|
|
Name: getSavedFilterName(i),
|
|
Filter: getPrefixedStringValue("savedFilter", i, "Filter"),
|
|
}
|
|
|
|
created, err := qb.Create(savedFilter)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating saved filter %v+: %s", savedFilter, err.Error())
|
|
}
|
|
|
|
savedFilterIDs = append(savedFilterIDs, created.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func doLinks(links [][2]int, fn func(idx1, idx2 int) error) error {
|
|
for _, l := range links {
|
|
if err := fn(l[0], l[1]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func linkPerformerTags(qb models.PerformerReaderWriter) error {
|
|
return doLinks(performerTagLinks, func(performerIndex, tagIndex int) error {
|
|
performerID := performerIDs[performerIndex]
|
|
tagID := tagIDs[tagIndex]
|
|
tagIDs, err := qb.GetTagIDs(performerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tagIDs = utils.IntAppendUnique(tagIDs, tagID)
|
|
|
|
return qb.UpdateTags(performerID, tagIDs)
|
|
})
|
|
}
|
|
|
|
func linkSceneMovies(qb models.SceneReaderWriter) error {
|
|
return doLinks(sceneMovieLinks, func(sceneIndex, movieIndex int) error {
|
|
sceneID := sceneIDs[sceneIndex]
|
|
movies, err := qb.GetMovies(sceneID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
movies = append(movies, models.MoviesScenes{
|
|
MovieID: movieIDs[movieIndex],
|
|
SceneID: sceneID,
|
|
})
|
|
return qb.UpdateMovies(sceneID, movies)
|
|
})
|
|
}
|
|
|
|
func linkScenePerformers(qb models.SceneReaderWriter) error {
|
|
return doLinks(scenePerformerLinks, func(sceneIndex, performerIndex int) error {
|
|
_, err := scene.AddPerformer(qb, sceneIDs[sceneIndex], performerIDs[performerIndex])
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkSceneGalleries(qb models.SceneReaderWriter) error {
|
|
return doLinks(sceneGalleryLinks, func(sceneIndex, galleryIndex int) error {
|
|
_, err := scene.AddGallery(qb, sceneIDs[sceneIndex], galleryIDs[galleryIndex])
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkSceneTags(qb models.SceneReaderWriter) error {
|
|
return doLinks(sceneTagLinks, func(sceneIndex, tagIndex int) error {
|
|
_, err := scene.AddTag(qb, sceneIDs[sceneIndex], tagIDs[tagIndex])
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkSceneStudios(sqb models.SceneWriter) error {
|
|
return doLinks(sceneStudioLinks, func(sceneIndex, studioIndex int) error {
|
|
scene := models.ScenePartial{
|
|
ID: sceneIDs[sceneIndex],
|
|
StudioID: &sql.NullInt64{Int64: int64(studioIDs[studioIndex]), Valid: true},
|
|
}
|
|
_, err := sqb.Update(scene)
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkImageGalleries(gqb models.GalleryReaderWriter) error {
|
|
return doLinks(imageGalleryLinks, func(imageIndex, galleryIndex int) error {
|
|
return gallery.AddImage(gqb, galleryIDs[galleryIndex], imageIDs[imageIndex])
|
|
})
|
|
}
|
|
|
|
func linkImageTags(iqb models.ImageReaderWriter) error {
|
|
return doLinks(imageTagLinks, func(imageIndex, tagIndex int) error {
|
|
imageID := imageIDs[imageIndex]
|
|
tags, err := iqb.GetTagIDs(imageID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tags = append(tags, tagIDs[tagIndex])
|
|
|
|
return iqb.UpdateTags(imageID, tags)
|
|
})
|
|
}
|
|
|
|
func linkImageStudios(qb models.ImageWriter) error {
|
|
return doLinks(imageStudioLinks, func(imageIndex, studioIndex int) error {
|
|
image := models.ImagePartial{
|
|
ID: imageIDs[imageIndex],
|
|
StudioID: &sql.NullInt64{Int64: int64(studioIDs[studioIndex]), Valid: true},
|
|
}
|
|
_, err := qb.Update(image)
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkImagePerformers(qb models.ImageReaderWriter) error {
|
|
return doLinks(imagePerformerLinks, func(imageIndex, performerIndex int) error {
|
|
imageID := imageIDs[imageIndex]
|
|
performers, err := qb.GetPerformerIDs(imageID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
performers = append(performers, performerIDs[performerIndex])
|
|
|
|
return qb.UpdatePerformers(imageID, performers)
|
|
})
|
|
}
|
|
|
|
func linkGalleryPerformers(qb models.GalleryReaderWriter) error {
|
|
return doLinks(galleryPerformerLinks, func(galleryIndex, performerIndex int) error {
|
|
galleryID := galleryIDs[galleryIndex]
|
|
performers, err := qb.GetPerformerIDs(galleryID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
performers = append(performers, performerIDs[performerIndex])
|
|
|
|
return qb.UpdatePerformers(galleryID, performers)
|
|
})
|
|
}
|
|
|
|
func linkGalleryStudios(qb models.GalleryReaderWriter) error {
|
|
return doLinks(galleryStudioLinks, func(galleryIndex, studioIndex int) error {
|
|
gallery := models.GalleryPartial{
|
|
ID: galleryIDs[galleryIndex],
|
|
StudioID: &sql.NullInt64{Int64: int64(studioIDs[studioIndex]), Valid: true},
|
|
}
|
|
_, err := qb.UpdatePartial(gallery)
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkGalleryTags(qb models.GalleryReaderWriter) error {
|
|
return doLinks(galleryTagLinks, func(galleryIndex, tagIndex int) error {
|
|
galleryID := galleryIDs[galleryIndex]
|
|
tags, err := qb.GetTagIDs(galleryID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
tags = append(tags, tagIDs[tagIndex])
|
|
|
|
return qb.UpdateTags(galleryID, tags)
|
|
})
|
|
}
|
|
|
|
func linkMovieStudios(mqb models.MovieWriter) error {
|
|
return doLinks(movieStudioLinks, func(movieIndex, studioIndex int) error {
|
|
movie := models.MoviePartial{
|
|
ID: movieIDs[movieIndex],
|
|
StudioID: &sql.NullInt64{Int64: int64(studioIDs[studioIndex]), Valid: true},
|
|
}
|
|
_, err := mqb.Update(movie)
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkStudiosParent(qb models.StudioWriter) error {
|
|
return doLinks(studioParentLinks, func(parentIndex, childIndex int) error {
|
|
studio := models.StudioPartial{
|
|
ID: studioIDs[childIndex],
|
|
ParentID: &sql.NullInt64{Int64: int64(studioIDs[parentIndex]), Valid: true},
|
|
}
|
|
_, err := qb.Update(studio)
|
|
|
|
return err
|
|
})
|
|
}
|
|
|
|
func linkTagsParent(qb models.TagReaderWriter) error {
|
|
return doLinks(tagParentLinks, func(parentIndex, childIndex int) error {
|
|
tagID := tagIDs[childIndex]
|
|
parentTags, err := qb.FindByChildTagID(tagID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var parentIDs []int
|
|
for _, parentTag := range parentTags {
|
|
parentIDs = append(parentIDs, parentTag.ID)
|
|
}
|
|
|
|
parentIDs = append(parentIDs, tagIDs[parentIndex])
|
|
|
|
return qb.UpdateParentTags(tagID, parentIDs)
|
|
})
|
|
}
|
|
|
|
func addTagImage(qb models.TagWriter, tagIndex int) error {
|
|
return qb.UpdateImage(tagIDs[tagIndex], models.DefaultTagImage)
|
|
}
|