SQLite model refactoring (#3791)

* Remove ID from PerformerPartial
* Separate studio model from sqlite model
* Separate movie model from sqlite model
* Separate tag model from sqlite model
* Separate saved filter model from sqlite model
* Separate scene marker model from sqlite model
* Separate gallery chapter model from sqlite model
* Move ErrNoRows checks into sqlite, improve empty result error messages
* Move SQLiteDate and SQLiteTimestamp to sqlite
* Use changesetTranslator everywhere, refactor for consistency
* Make PerformerStore.DestroyImage private
* Fix rating on movie create
This commit is contained in:
DingDongSoLong4
2023-06-15 04:46:09 +02:00
committed by GitHub
parent 9180a68c45
commit 1c13c9e1b1
150 changed files with 3279 additions and 3129 deletions

View File

@@ -2,7 +2,6 @@ package api
import (
"context"
"database/sql"
"fmt"
"strconv"
"time"
@@ -26,13 +25,36 @@ func (r *mutationResolver) getMovie(ctx context.Context, id int) (ret *models.Mo
}
func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInput) (*models.Movie, error) {
translator := changesetTranslator{
inputMap: getUpdateInputMap(ctx),
}
// generate checksum from movie name rather than image
checksum := md5.FromString(input.Name)
var frontimageData []byte
var backimageData []byte
// Populate a new movie from the input
currentTime := time.Now()
newMovie := models.Movie{
Checksum: checksum,
Name: input.Name,
CreatedAt: currentTime,
UpdatedAt: currentTime,
Aliases: translator.string(input.Aliases, "aliases"),
Duration: input.Duration,
Date: translator.datePtr(input.Date, "date"),
Rating: translator.ratingConversionInt(input.Rating, input.Rating100),
Director: translator.string(input.Director, "director"),
Synopsis: translator.string(input.Synopsis, "synopsis"),
URL: translator.string(input.URL, "url"),
}
var err error
newMovie.StudioID, err = translator.intPtrFromString(input.StudioID, "studio_id")
if err != nil {
return nil, fmt.Errorf("converting studio id: %w", err)
}
// HACK: if back image is being set, set the front image to the default.
// This is because we can't have a null front image with a non-null back image.
if input.FrontImage == nil && input.BackImage != nil {
@@ -40,6 +62,7 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
}
// Process the base 64 encoded image string
var frontimageData []byte
if input.FrontImage != nil {
frontimageData, err = utils.ProcessImageInput(ctx, *input.FrontImage)
if err != nil {
@@ -48,6 +71,7 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
}
// Process the base 64 encoded image string
var backimageData []byte
if input.BackImage != nil {
backimageData, err = utils.ProcessImageInput(ctx, *input.BackImage)
if err != nil {
@@ -55,69 +79,24 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
}
}
// Populate a new movie from the input
currentTime := time.Now()
newMovie := models.Movie{
Checksum: checksum,
Name: sql.NullString{String: input.Name, Valid: true},
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
}
if input.Aliases != nil {
newMovie.Aliases = sql.NullString{String: *input.Aliases, Valid: true}
}
if input.Duration != nil {
duration := int64(*input.Duration)
newMovie.Duration = sql.NullInt64{Int64: duration, Valid: true}
}
if input.Date != nil {
newMovie.Date = models.SQLiteDate{String: *input.Date, Valid: true}
}
if input.Rating100 != nil {
newMovie.Rating = sql.NullInt64{Int64: int64(*input.Rating100), Valid: true}
} else if input.Rating != nil {
rating := models.Rating5To100(*input.Rating)
newMovie.Rating = sql.NullInt64{Int64: int64(rating), Valid: true}
}
if input.StudioID != nil {
studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64)
newMovie.StudioID = sql.NullInt64{Int64: studioID, Valid: true}
}
if input.Director != nil {
newMovie.Director = sql.NullString{String: *input.Director, Valid: true}
}
if input.Synopsis != nil {
newMovie.Synopsis = sql.NullString{String: *input.Synopsis, Valid: true}
}
if input.URL != nil {
newMovie.URL = sql.NullString{String: *input.URL, Valid: true}
}
// Start the transaction and save the movie
var movie *models.Movie
if err := r.withTxn(ctx, func(ctx context.Context) error {
qb := r.repository.Movie
movie, err = qb.Create(ctx, newMovie)
err = qb.Create(ctx, &newMovie)
if err != nil {
return err
}
// update image table
if len(frontimageData) > 0 {
if err := qb.UpdateFrontImage(ctx, movie.ID, frontimageData); err != nil {
if err := qb.UpdateFrontImage(ctx, newMovie.ID, frontimageData); err != nil {
return err
}
}
if len(backimageData) > 0 {
if err := qb.UpdateBackImage(ctx, movie.ID, backimageData); err != nil {
if err := qb.UpdateBackImage(ctx, newMovie.ID, backimageData); err != nil {
return err
}
}
@@ -127,26 +106,42 @@ func (r *mutationResolver) MovieCreate(ctx context.Context, input MovieCreateInp
return nil, err
}
r.hookExecutor.ExecutePostHooks(ctx, movie.ID, plugin.MovieCreatePost, input, nil)
return r.getMovie(ctx, movie.ID)
r.hookExecutor.ExecutePostHooks(ctx, newMovie.ID, plugin.MovieCreatePost, input, nil)
return r.getMovie(ctx, newMovie.ID)
}
func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInput) (*models.Movie, error) {
// Populate movie from the input
movieID, err := strconv.Atoi(input.ID)
if err != nil {
return nil, err
}
updatedMovie := models.MoviePartial{
ID: movieID,
UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()},
}
translator := changesetTranslator{
inputMap: getUpdateInputMap(ctx),
}
// Populate movie from the input
updatedMovie := models.NewMoviePartial()
if input.Name != nil {
// generate checksum from movie name rather than image
checksum := md5.FromString(*input.Name)
updatedMovie.Name = models.NewOptionalString(*input.Name)
updatedMovie.Checksum = models.NewOptionalString(checksum)
}
updatedMovie.Aliases = translator.optionalString(input.Aliases, "aliases")
updatedMovie.Duration = translator.optionalInt(input.Duration, "duration")
updatedMovie.Date = translator.optionalDate(input.Date, "date")
updatedMovie.Rating = translator.ratingConversionOptional(input.Rating, input.Rating100)
updatedMovie.Director = translator.optionalString(input.Director, "director")
updatedMovie.Synopsis = translator.optionalString(input.Synopsis, "synopsis")
updatedMovie.URL = translator.optionalString(input.URL, "url")
updatedMovie.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
if err != nil {
return nil, fmt.Errorf("converting studio id: %w", err)
}
var frontimageData []byte
frontImageIncluded := translator.hasField("front_image")
if input.FrontImage != nil {
@@ -155,8 +150,9 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInp
return nil, err
}
}
backImageIncluded := translator.hasField("back_image")
var backimageData []byte
backImageIncluded := translator.hasField("back_image")
if input.BackImage != nil {
backimageData, err = utils.ProcessImageInput(ctx, *input.BackImage)
if err != nil {
@@ -164,27 +160,11 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input MovieUpdateInp
}
}
if input.Name != nil {
// generate checksum from movie name rather than image
checksum := md5.FromString(*input.Name)
updatedMovie.Name = &sql.NullString{String: *input.Name, Valid: true}
updatedMovie.Checksum = &checksum
}
updatedMovie.Aliases = translator.nullString(input.Aliases, "aliases")
updatedMovie.Duration = translator.nullInt64(input.Duration, "duration")
updatedMovie.Date = translator.sqliteDate(input.Date, "date")
updatedMovie.Rating = translator.ratingConversion(input.Rating, input.Rating100)
updatedMovie.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id")
updatedMovie.Director = translator.nullString(input.Director, "director")
updatedMovie.Synopsis = translator.nullString(input.Synopsis, "synopsis")
updatedMovie.URL = translator.nullString(input.URL, "url")
// Start the transaction and save the movie
var movie *models.Movie
if err := r.withTxn(ctx, func(ctx context.Context) error {
qb := r.repository.Movie
movie, err = qb.Update(ctx, updatedMovie)
movie, err = qb.UpdatePartial(ctx, movieID, updatedMovie)
if err != nil {
return err
}
@@ -217,19 +197,19 @@ func (r *mutationResolver) BulkMovieUpdate(ctx context.Context, input BulkMovieU
return nil, err
}
updatedTime := time.Now()
translator := changesetTranslator{
inputMap: getUpdateInputMap(ctx),
}
updatedMovie := models.MoviePartial{
UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime},
}
// populate movie from the input
updatedMovie := models.NewMoviePartial()
updatedMovie.Rating = translator.ratingConversion(input.Rating, input.Rating100)
updatedMovie.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id")
updatedMovie.Director = translator.nullString(input.Director, "director")
updatedMovie.Rating = translator.ratingConversionOptional(input.Rating, input.Rating100)
updatedMovie.Director = translator.optionalString(input.Director, "director")
updatedMovie.StudioID, err = translator.optionalIntFromString(input.StudioID, "studio_id")
if err != nil {
return nil, fmt.Errorf("converting studio id: %w", err)
}
ret := []*models.Movie{}
@@ -237,18 +217,7 @@ func (r *mutationResolver) BulkMovieUpdate(ctx context.Context, input BulkMovieU
qb := r.repository.Movie
for _, movieID := range movieIDs {
updatedMovie.ID = movieID
existing, err := qb.Find(ctx, movieID)
if err != nil {
return err
}
if existing == nil {
return fmt.Errorf("movie with id %d not found", movieID)
}
movie, err := qb.Update(ctx, updatedMovie)
movie, err := qb.UpdatePartial(ctx, movieID, updatedMovie)
if err != nil {
return err
}