mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Model refactor, part 2 (#4092)
* Move conversions into changesetTranslator * Improve mutation error messages * Use models.New and models.NewPartial everywhere * Replace getStashIDsFor functions * Remove ImageCreateInput * Remove unused parameters * Refactor matching functions --------- Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/models"
|
||||
"github.com/stashapp/stash/pkg/performer"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"github.com/stashapp/stash/pkg/utils"
|
||||
)
|
||||
|
||||
// used to refetch performer after hooks run
|
||||
func (r *mutationResolver) getPerformer(ctx context.Context, id int) (ret *models.Performer, err error) {
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
ret, err = r.repository.Performer.Find(ctx, id)
|
||||
@@ -24,62 +24,45 @@ func (r *mutationResolver) getPerformer(ctx context.Context, id int) (ret *model
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func stashIDPtrSliceToSlice(v []*models.StashID) []models.StashID {
|
||||
ret := make([]models.StashID, len(v))
|
||||
for i, vv := range v {
|
||||
c := vv
|
||||
ret[i] = *c
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerCreateInput) (*models.Performer, error) {
|
||||
func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.PerformerCreateInput) (*models.Performer, error) {
|
||||
translator := changesetTranslator{
|
||||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
tagIDs, err := stringslice.StringSliceToIntSlice(input.TagIds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
// Populate a new performer from the input
|
||||
currentTime := time.Now()
|
||||
newPerformer := models.Performer{
|
||||
Name: input.Name,
|
||||
Disambiguation: translator.string(input.Disambiguation, "disambiguation"),
|
||||
URL: translator.string(input.URL, "url"),
|
||||
Gender: input.Gender,
|
||||
Ethnicity: translator.string(input.Ethnicity, "ethnicity"),
|
||||
Country: translator.string(input.Country, "country"),
|
||||
EyeColor: translator.string(input.EyeColor, "eye_color"),
|
||||
Measurements: translator.string(input.Measurements, "measurements"),
|
||||
FakeTits: translator.string(input.FakeTits, "fake_tits"),
|
||||
PenisLength: input.PenisLength,
|
||||
Circumcised: input.Circumcised,
|
||||
CareerLength: translator.string(input.CareerLength, "career_length"),
|
||||
Tattoos: translator.string(input.Tattoos, "tattoos"),
|
||||
Piercings: translator.string(input.Piercings, "piercings"),
|
||||
Twitter: translator.string(input.Twitter, "twitter"),
|
||||
Instagram: translator.string(input.Instagram, "instagram"),
|
||||
Favorite: translator.bool(input.Favorite, "favorite"),
|
||||
Rating: translator.ratingConversionInt(input.Rating, input.Rating100),
|
||||
Details: translator.string(input.Details, "details"),
|
||||
HairColor: translator.string(input.HairColor, "hair_color"),
|
||||
Weight: input.Weight,
|
||||
IgnoreAutoTag: translator.bool(input.IgnoreAutoTag, "ignore_auto_tag"),
|
||||
CreatedAt: currentTime,
|
||||
UpdatedAt: currentTime,
|
||||
TagIDs: models.NewRelatedIDs(tagIDs),
|
||||
StashIDs: models.NewRelatedStashIDs(stashIDPtrSliceToSlice(input.StashIds)),
|
||||
}
|
||||
newPerformer := models.NewPerformer()
|
||||
|
||||
newPerformer.Birthdate, err = translator.datePtr(input.Birthdate, "birthdate")
|
||||
newPerformer.Name = input.Name
|
||||
newPerformer.Disambiguation = translator.string(input.Disambiguation)
|
||||
newPerformer.URL = translator.string(input.URL)
|
||||
newPerformer.Gender = input.Gender
|
||||
newPerformer.Ethnicity = translator.string(input.Ethnicity)
|
||||
newPerformer.Country = translator.string(input.Country)
|
||||
newPerformer.EyeColor = translator.string(input.EyeColor)
|
||||
newPerformer.Measurements = translator.string(input.Measurements)
|
||||
newPerformer.FakeTits = translator.string(input.FakeTits)
|
||||
newPerformer.PenisLength = input.PenisLength
|
||||
newPerformer.Circumcised = input.Circumcised
|
||||
newPerformer.CareerLength = translator.string(input.CareerLength)
|
||||
newPerformer.Tattoos = translator.string(input.Tattoos)
|
||||
newPerformer.Piercings = translator.string(input.Piercings)
|
||||
newPerformer.Twitter = translator.string(input.Twitter)
|
||||
newPerformer.Instagram = translator.string(input.Instagram)
|
||||
newPerformer.Favorite = translator.bool(input.Favorite)
|
||||
newPerformer.Rating = translator.ratingConversion(input.Rating, input.Rating100)
|
||||
newPerformer.Details = translator.string(input.Details)
|
||||
newPerformer.HairColor = translator.string(input.HairColor)
|
||||
newPerformer.Weight = input.Weight
|
||||
newPerformer.IgnoreAutoTag = translator.bool(input.IgnoreAutoTag)
|
||||
newPerformer.StashIDs = models.NewRelatedStashIDs(input.StashIds)
|
||||
|
||||
var err error
|
||||
|
||||
newPerformer.Birthdate, err = translator.datePtr(input.Birthdate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting birthdate: %w", err)
|
||||
}
|
||||
newPerformer.DeathDate, err = translator.datePtr(input.DeathDate, "death_date")
|
||||
newPerformer.DeathDate, err = translator.datePtr(input.DeathDate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting death date: %w", err)
|
||||
}
|
||||
@@ -88,18 +71,24 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||
if input.HeightCm != nil {
|
||||
newPerformer.Height = input.HeightCm
|
||||
} else {
|
||||
newPerformer.Height, err = translator.intPtrFromString(input.Height, "height")
|
||||
newPerformer.Height, err = translator.intPtrFromString(input.Height)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting height: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// prefer alias_list over aliases
|
||||
if input.AliasList != nil {
|
||||
newPerformer.Aliases = models.NewRelatedStrings(input.AliasList)
|
||||
} else if input.Aliases != nil {
|
||||
newPerformer.Aliases = models.NewRelatedStrings(stringslice.FromString(*input.Aliases, ","))
|
||||
}
|
||||
|
||||
newPerformer.TagIDs, err = translator.relatedIds(input.TagIds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
if err := performer.ValidateDeathDate(nil, input.Birthdate, input.DeathDate); err != nil {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -111,7 +100,7 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||
if input.Image != nil {
|
||||
imageData, err = utils.ProcessImageInput(ctx, *input.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("processing image: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,42 +129,27 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||
return r.getPerformer(ctx, newPerformer.ID)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerUpdateInput) (*models.Performer, error) {
|
||||
func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.PerformerUpdateInput) (*models.Performer, error) {
|
||||
performerID, err := strconv.Atoi(input.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("converting id: %w", err)
|
||||
}
|
||||
|
||||
// Populate performer from the input
|
||||
translator := changesetTranslator{
|
||||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate performer from the input
|
||||
updatedPerformer := models.NewPerformerPartial()
|
||||
|
||||
updatedPerformer.Name = translator.optionalString(input.Name, "name")
|
||||
updatedPerformer.Disambiguation = translator.optionalString(input.Disambiguation, "disambiguation")
|
||||
updatedPerformer.URL = translator.optionalString(input.URL, "url")
|
||||
updatedPerformer.Gender = translator.optionalString((*string)(input.Gender), "gender")
|
||||
updatedPerformer.Birthdate, err = translator.optionalDate(input.Birthdate, "birthdate")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting birthdate: %w", err)
|
||||
}
|
||||
updatedPerformer.Ethnicity = translator.optionalString(input.Ethnicity, "ethnicity")
|
||||
updatedPerformer.Country = translator.optionalString(input.Country, "country")
|
||||
updatedPerformer.EyeColor = translator.optionalString(input.EyeColor, "eye_color")
|
||||
updatedPerformer.Measurements = translator.optionalString(input.Measurements, "measurements")
|
||||
|
||||
// prefer height_cm over height
|
||||
if translator.hasField("height_cm") {
|
||||
updatedPerformer.Height = translator.optionalInt(input.HeightCm, "height_cm")
|
||||
} else if translator.hasField("height") {
|
||||
updatedPerformer.Height, err = translator.optionalIntFromString(input.Height, "height")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
updatedPerformer.FakeTits = translator.optionalString(input.FakeTits, "fake_tits")
|
||||
updatedPerformer.PenisLength = translator.optionalFloat64(input.PenisLength, "penis_length")
|
||||
updatedPerformer.Circumcised = translator.optionalString((*string)(input.Circumcised), "circumcised")
|
||||
@@ -185,45 +159,46 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||
updatedPerformer.Twitter = translator.optionalString(input.Twitter, "twitter")
|
||||
updatedPerformer.Instagram = translator.optionalString(input.Instagram, "instagram")
|
||||
updatedPerformer.Favorite = translator.optionalBool(input.Favorite, "favorite")
|
||||
updatedPerformer.Rating = translator.ratingConversionOptional(input.Rating, input.Rating100)
|
||||
updatedPerformer.Rating = translator.optionalRatingConversion(input.Rating, input.Rating100)
|
||||
updatedPerformer.Details = translator.optionalString(input.Details, "details")
|
||||
updatedPerformer.HairColor = translator.optionalString(input.HairColor, "hair_color")
|
||||
updatedPerformer.Weight = translator.optionalInt(input.Weight, "weight")
|
||||
updatedPerformer.IgnoreAutoTag = translator.optionalBool(input.IgnoreAutoTag, "ignore_auto_tag")
|
||||
updatedPerformer.StashIDs = translator.updateStashIDs(input.StashIds, "stash_ids")
|
||||
|
||||
updatedPerformer.Birthdate, err = translator.optionalDate(input.Birthdate, "birthdate")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting birthdate: %w", err)
|
||||
}
|
||||
updatedPerformer.DeathDate, err = translator.optionalDate(input.DeathDate, "death_date")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting death date: %w", err)
|
||||
}
|
||||
updatedPerformer.HairColor = translator.optionalString(input.HairColor, "hair_color")
|
||||
updatedPerformer.Weight = translator.optionalInt(input.Weight, "weight")
|
||||
updatedPerformer.IgnoreAutoTag = translator.optionalBool(input.IgnoreAutoTag, "ignore_auto_tag")
|
||||
|
||||
if translator.hasField("alias_list") {
|
||||
updatedPerformer.Aliases = &models.UpdateStrings{
|
||||
Values: input.AliasList,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
} else if translator.hasField("aliases") {
|
||||
var values []string
|
||||
if input.Aliases != nil {
|
||||
values = stringslice.FromString(*input.Aliases, ",")
|
||||
}
|
||||
updatedPerformer.Aliases = &models.UpdateStrings{
|
||||
Values: values,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
}
|
||||
|
||||
if translator.hasField("tag_ids") {
|
||||
updatedPerformer.TagIDs, err = translateUpdateIDs(input.TagIds, models.RelationshipUpdateModeSet)
|
||||
// prefer height_cm over height
|
||||
if translator.hasField("height_cm") {
|
||||
updatedPerformer.Height = translator.optionalInt(input.HeightCm, "height_cm")
|
||||
} else if translator.hasField("height") {
|
||||
updatedPerformer.Height, err = translator.optionalIntFromString(input.Height, "height")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
return nil, fmt.Errorf("converting height: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Save the stash_ids
|
||||
if translator.hasField("stash_ids") {
|
||||
updatedPerformer.StashIDs = &models.UpdateStashIDs{
|
||||
StashIDs: stashIDPtrSliceToSlice(input.StashIds),
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
// prefer alias_list over aliases
|
||||
if translator.hasField("alias_list") {
|
||||
updatedPerformer.Aliases = translator.updateStrings(input.AliasList, "alias_list")
|
||||
} else if translator.hasField("aliases") {
|
||||
var aliasList []string
|
||||
if input.Aliases != nil {
|
||||
aliasList = stringslice.FromString(*input.Aliases, ",")
|
||||
}
|
||||
updatedPerformer.Aliases = translator.updateStrings(aliasList, "aliases")
|
||||
}
|
||||
|
||||
updatedPerformer.TagIDs, err = translator.updateIds(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
var imageData []byte
|
||||
@@ -231,7 +206,7 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||
if input.Image != nil {
|
||||
imageData, err = utils.ProcessImageInput(ctx, *input.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("processing image: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,9 +225,7 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||
}
|
||||
|
||||
if err := performer.ValidateDeathDate(existing, input.Birthdate, input.DeathDate); err != nil {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = qb.UpdatePartial(ctx, performerID, updatedPerformer)
|
||||
@@ -279,37 +252,22 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||
func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPerformerUpdateInput) ([]*models.Performer, error) {
|
||||
performerIDs, err := stringslice.StringSliceToIntSlice(input.Ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("converting ids: %w", err)
|
||||
}
|
||||
|
||||
// Populate performer from the input
|
||||
translator := changesetTranslator{
|
||||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate performer from the input
|
||||
updatedPerformer := models.NewPerformerPartial()
|
||||
|
||||
updatedPerformer.Disambiguation = translator.optionalString(input.Disambiguation, "disambiguation")
|
||||
updatedPerformer.URL = translator.optionalString(input.URL, "url")
|
||||
updatedPerformer.Gender = translator.optionalString((*string)(input.Gender), "gender")
|
||||
updatedPerformer.Birthdate, err = translator.optionalDate(input.Birthdate, "birthdate")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting birthdate: %w", err)
|
||||
}
|
||||
updatedPerformer.Ethnicity = translator.optionalString(input.Ethnicity, "ethnicity")
|
||||
updatedPerformer.Country = translator.optionalString(input.Country, "country")
|
||||
updatedPerformer.EyeColor = translator.optionalString(input.EyeColor, "eye_color")
|
||||
|
||||
// prefer height_cm over height
|
||||
if translator.hasField("height_cm") {
|
||||
updatedPerformer.Height = translator.optionalInt(input.HeightCm, "height_cm")
|
||||
} else if translator.hasField("height") {
|
||||
updatedPerformer.Height, err = translator.optionalIntFromString(input.Height, "height")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
updatedPerformer.Measurements = translator.optionalString(input.Measurements, "measurements")
|
||||
updatedPerformer.FakeTits = translator.optionalString(input.FakeTits, "fake_tits")
|
||||
updatedPerformer.PenisLength = translator.optionalFloat64(input.PenisLength, "penis_length")
|
||||
@@ -320,37 +278,45 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
|
||||
updatedPerformer.Twitter = translator.optionalString(input.Twitter, "twitter")
|
||||
updatedPerformer.Instagram = translator.optionalString(input.Instagram, "instagram")
|
||||
updatedPerformer.Favorite = translator.optionalBool(input.Favorite, "favorite")
|
||||
updatedPerformer.Rating = translator.ratingConversionOptional(input.Rating, input.Rating100)
|
||||
updatedPerformer.Rating = translator.optionalRatingConversion(input.Rating, input.Rating100)
|
||||
updatedPerformer.Details = translator.optionalString(input.Details, "details")
|
||||
updatedPerformer.DeathDate, err = translator.optionalDate(input.DeathDate, "death_date")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting death date: %w", err)
|
||||
}
|
||||
updatedPerformer.HairColor = translator.optionalString(input.HairColor, "hair_color")
|
||||
updatedPerformer.Weight = translator.optionalInt(input.Weight, "weight")
|
||||
updatedPerformer.IgnoreAutoTag = translator.optionalBool(input.IgnoreAutoTag, "ignore_auto_tag")
|
||||
|
||||
if translator.hasField("alias_list") {
|
||||
updatedPerformer.Aliases = &models.UpdateStrings{
|
||||
Values: input.AliasList.Values,
|
||||
Mode: input.AliasList.Mode,
|
||||
}
|
||||
} else if translator.hasField("aliases") {
|
||||
var values []string
|
||||
if input.Aliases != nil {
|
||||
values = stringslice.FromString(*input.Aliases, ",")
|
||||
}
|
||||
updatedPerformer.Aliases = &models.UpdateStrings{
|
||||
Values: values,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
updatedPerformer.Birthdate, err = translator.optionalDate(input.Birthdate, "birthdate")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting birthdate: %w", err)
|
||||
}
|
||||
updatedPerformer.DeathDate, err = translator.optionalDate(input.DeathDate, "death_date")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting death date: %w", err)
|
||||
}
|
||||
|
||||
// prefer height_cm over height
|
||||
if translator.hasField("height_cm") {
|
||||
updatedPerformer.Height = translator.optionalInt(input.HeightCm, "height_cm")
|
||||
} else if translator.hasField("height") {
|
||||
updatedPerformer.Height, err = translator.optionalIntFromString(input.Height, "height")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting height: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if translator.hasField("tag_ids") {
|
||||
updatedPerformer.TagIDs, err = translateUpdateIDs(input.TagIds.Ids, input.TagIds.Mode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
// prefer alias_list over aliases
|
||||
if translator.hasField("alias_list") {
|
||||
updatedPerformer.Aliases = translator.updateStringsBulk(input.AliasList, "alias_list")
|
||||
} else if translator.hasField("aliases") {
|
||||
var aliasList []string
|
||||
if input.Aliases != nil {
|
||||
aliasList = stringslice.FromString(*input.Aliases, ",")
|
||||
}
|
||||
updatedPerformer.Aliases = translator.updateStrings(aliasList, "aliases")
|
||||
}
|
||||
|
||||
updatedPerformer.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
ret := []*models.Performer{}
|
||||
@@ -370,7 +336,8 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
|
||||
return fmt.Errorf("performer with id %d not found", performerID)
|
||||
}
|
||||
|
||||
if err := performer.ValidateDeathDate(existing, input.Birthdate, input.DeathDate); err != nil {
|
||||
err = performer.ValidateDeathDate(existing, input.Birthdate, input.DeathDate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -406,7 +373,7 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
|
||||
func (r *mutationResolver) PerformerDestroy(ctx context.Context, input PerformerDestroyInput) (bool, error) {
|
||||
id, err := strconv.Atoi(input.ID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, fmt.Errorf("converting id: %w", err)
|
||||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
@@ -423,7 +390,7 @@ func (r *mutationResolver) PerformerDestroy(ctx context.Context, input Performer
|
||||
func (r *mutationResolver) PerformersDestroy(ctx context.Context, performerIDs []string) (bool, error) {
|
||||
ids, err := stringslice.StringSliceToIntSlice(performerIDs)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, fmt.Errorf("converting ids: %w", err)
|
||||
}
|
||||
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
|
||||
Reference in New Issue
Block a user