File storage rewrite (#2676)

* Restructure data layer part 2 (#2599)
* Refactor and separate image model
* Refactor image query builder
* Handle relationships in image query builder
* Remove relationship management methods
* Refactor gallery model/query builder
* Add scenes to gallery model
* Convert scene model
* Refactor scene models
* Remove unused methods
* Add unit tests for gallery
* Add image tests
* Add scene tests
* Convert unnecessary scene value pointers to values
* Convert unnecessary pointer values to values
* Refactor scene partial
* Add scene partial tests
* Refactor ImagePartial
* Add image partial tests
* Refactor gallery partial update
* Add partial gallery update tests
* Use zero/null package for null values
* Add files and scan system
* Add sqlite implementation for files/folders
* Add unit tests for files/folders
* Image refactors
* Update image data layer
* Refactor gallery model and creation
* Refactor scene model
* Refactor scenes
* Don't set title from filename
* Allow galleries to freely add/remove images
* Add multiple scene file support to graphql and UI
* Add multiple file support for images in graphql/UI
* Add multiple file for galleries in graphql/UI
* Remove use of some deprecated fields
* Remove scene path usage
* Remove gallery path usage
* Remove path from image
* Move funscript to video file
* Refactor caption detection
* Migrate existing data
* Add post commit/rollback hook system
* Lint. Comment out import/export tests
* Add WithDatabase read only wrapper
* Prepend tasks to list
* Add 32 pre-migration
* Add warnings in release and migration notes
This commit is contained in:
WithoutPants
2022-07-13 16:30:54 +10:00
parent 30877c75fb
commit 5495d72849
359 changed files with 43690 additions and 16000 deletions

View File

@@ -2,24 +2,91 @@ package api
import (
"context"
"strconv"
"time"
"github.com/stashapp/stash/pkg/file"
"github.com/stashapp/stash/pkg/image"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/utils"
)
func (r *galleryResolver) Path(ctx context.Context, obj *models.Gallery) (*string, error) {
if obj.Path.Valid {
return &obj.Path.String, nil
func (r *galleryResolver) Files(ctx context.Context, obj *models.Gallery) ([]*GalleryFile, error) {
ret := make([]*GalleryFile, len(obj.Files))
for i, f := range obj.Files {
base := f.Base()
ret[i] = &GalleryFile{
ID: strconv.Itoa(int(base.ID)),
Path: base.Path,
Basename: base.Basename,
ParentFolderID: strconv.Itoa(int(base.ParentFolderID)),
ModTime: base.ModTime,
Size: base.Size,
CreatedAt: base.CreatedAt,
UpdatedAt: base.UpdatedAt,
Fingerprints: resolveFingerprints(base),
}
if base.ZipFileID != nil {
zipFileID := strconv.Itoa(int(*base.ZipFileID))
ret[i].ZipFileID = &zipFileID
}
}
return nil, nil
return ret, nil
}
func (r *galleryResolver) Title(ctx context.Context, obj *models.Gallery) (*string, error) {
if obj.Title.Valid {
return &obj.Title.String, nil
func (r *galleryResolver) Folder(ctx context.Context, obj *models.Gallery) (*Folder, error) {
if obj.FolderID == nil {
return nil, nil
}
var ret *file.Folder
if err := r.withTxn(ctx, func(ctx context.Context) error {
var err error
ret, err = r.repository.Folder.Find(ctx, *obj.FolderID)
if err != nil {
return err
}
return err
}); err != nil {
return nil, err
}
if ret == nil {
return nil, nil
}
rr := &Folder{
ID: ret.ID.String(),
Path: ret.Path,
ModTime: ret.ModTime,
CreatedAt: ret.CreatedAt,
UpdatedAt: ret.UpdatedAt,
}
if ret.ParentFolderID != nil {
pfidStr := ret.ParentFolderID.String()
rr.ParentFolderID = &pfidStr
}
if ret.ZipFileID != nil {
zfidStr := ret.ZipFileID.String()
rr.ZipFileID = &zfidStr
}
return rr, nil
}
func (r *galleryResolver) FileModTime(ctx context.Context, obj *models.Gallery) (*time.Time, error) {
f := obj.PrimaryFile()
if f != nil {
return &f.Base().ModTime, nil
}
return nil, nil
}
@@ -70,35 +137,13 @@ func (r *galleryResolver) Cover(ctx context.Context, obj *models.Gallery) (ret *
}
func (r *galleryResolver) Date(ctx context.Context, obj *models.Gallery) (*string, error) {
if obj.Date.Valid {
result := utils.GetYMDFromDatabaseDate(obj.Date.String)
if obj.Date != nil {
result := obj.Date.String()
return &result, nil
}
return nil, nil
}
func (r *galleryResolver) URL(ctx context.Context, obj *models.Gallery) (*string, error) {
if obj.URL.Valid {
return &obj.URL.String, nil
}
return nil, nil
}
func (r *galleryResolver) Details(ctx context.Context, obj *models.Gallery) (*string, error) {
if obj.Details.Valid {
return &obj.Details.String, nil
}
return nil, nil
}
func (r *galleryResolver) Rating(ctx context.Context, obj *models.Gallery) (*int, error) {
if obj.Rating.Valid {
rating := int(obj.Rating.Int64)
return &rating, nil
}
return nil, nil
}
func (r *galleryResolver) Scenes(ctx context.Context, obj *models.Gallery) (ret []*models.Scene, err error) {
if err := r.withTxn(ctx, func(ctx context.Context) error {
var err error
@@ -112,13 +157,13 @@ func (r *galleryResolver) Scenes(ctx context.Context, obj *models.Gallery) (ret
}
func (r *galleryResolver) Studio(ctx context.Context, obj *models.Gallery) (ret *models.Studio, err error) {
if !obj.StudioID.Valid {
if obj.StudioID == nil {
return nil, nil
}
if err := r.withTxn(ctx, func(ctx context.Context) error {
var err error
ret, err = r.repository.Studio.Find(ctx, int(obj.StudioID.Int64))
ret, err = r.repository.Studio.Find(ctx, *obj.StudioID)
return err
}); err != nil {
return nil, err
@@ -162,15 +207,3 @@ func (r *galleryResolver) ImageCount(ctx context.Context, obj *models.Gallery) (
return ret, nil
}
func (r *galleryResolver) CreatedAt(ctx context.Context, obj *models.Gallery) (*time.Time, error) {
return &obj.CreatedAt.Timestamp, nil
}
func (r *galleryResolver) UpdatedAt(ctx context.Context, obj *models.Gallery) (*time.Time, error) {
return &obj.UpdatedAt.Timestamp, nil
}
func (r *galleryResolver) FileModTime(ctx context.Context, obj *models.Gallery) (*time.Time, error) {
return &obj.FileModTime.Timestamp, nil
}