mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Performer refactor (#3057)
* Separate performer model from sqlite model * Use GenderEnum for gender
This commit is contained in:
parent
b1fa933868
commit
270bc317cb
45 changed files with 1558 additions and 1226 deletions
|
|
@ -185,21 +185,6 @@ func (t changesetTranslator) optionalIntFromString(value *string, field string)
|
||||||
return models.NewOptionalInt(vv), nil
|
return models.NewOptionalInt(vv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t changesetTranslator) nullBool(value *bool, field string) *sql.NullBool {
|
|
||||||
if !t.hasField(field) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := &sql.NullBool{}
|
|
||||||
|
|
||||||
if value != nil {
|
|
||||||
ret.Bool = *value
|
|
||||||
ret.Valid = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t changesetTranslator) optionalBool(value *bool, field string) models.OptionalBool {
|
func (t changesetTranslator) optionalBool(value *bool, field string) models.OptionalBool {
|
||||||
if !t.hasField(field) {
|
if !t.hasField(field) {
|
||||||
return models.OptionalBool{}
|
return models.OptionalBool{}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/stashapp/stash/internal/static"
|
"github.com/stashapp/stash/internal/static"
|
||||||
"github.com/stashapp/stash/pkg/hash"
|
"github.com/stashapp/stash/pkg/hash"
|
||||||
"github.com/stashapp/stash/pkg/logger"
|
"github.com/stashapp/stash/pkg/logger"
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type imageBox struct {
|
type imageBox struct {
|
||||||
|
|
@ -86,7 +87,7 @@ func initialiseCustomImages() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRandomPerformerImageUsingName(name, gender, customPath string) ([]byte, error) {
|
func getRandomPerformerImageUsingName(name string, gender models.GenderEnum, customPath string) ([]byte, error) {
|
||||||
var box *imageBox
|
var box *imageBox
|
||||||
|
|
||||||
// If we have a custom path, we should return a new box in the given path.
|
// If we have a custom path, we should return a new box in the given path.
|
||||||
|
|
@ -95,10 +96,10 @@ func getRandomPerformerImageUsingName(name, gender, customPath string) ([]byte,
|
||||||
}
|
}
|
||||||
|
|
||||||
if box == nil {
|
if box == nil {
|
||||||
switch strings.ToUpper(gender) {
|
switch gender {
|
||||||
case "FEMALE":
|
case models.GenderEnumFemale:
|
||||||
box = performerBox
|
box = performerBox
|
||||||
case "MALE":
|
case models.GenderEnumMale:
|
||||||
box = performerBoxMale
|
box = performerBoxMale
|
||||||
default:
|
default:
|
||||||
box = performerBox
|
box = performerBox
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stashapp/stash/internal/api/urlbuilders"
|
"github.com/stashapp/stash/internal/api/urlbuilders"
|
||||||
"github.com/stashapp/stash/pkg/gallery"
|
"github.com/stashapp/stash/pkg/gallery"
|
||||||
|
|
@ -10,131 +9,14 @@ import (
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *performerResolver) Name(ctx context.Context, obj *models.Performer) (*string, error) {
|
func (r *performerResolver) Birthdate(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||||
if obj.Name.Valid {
|
if obj.Birthdate != nil {
|
||||||
return &obj.Name.String, nil
|
ret := obj.Birthdate.String()
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) URL(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.URL.Valid {
|
|
||||||
return &obj.URL.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Gender(ctx context.Context, obj *models.Performer) (*models.GenderEnum, error) {
|
|
||||||
var ret models.GenderEnum
|
|
||||||
|
|
||||||
if obj.Gender.Valid {
|
|
||||||
ret = models.GenderEnum(obj.Gender.String)
|
|
||||||
if ret.IsValid() {
|
|
||||||
return &ret, nil
|
return &ret, nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *performerResolver) Twitter(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Twitter.Valid {
|
|
||||||
return &obj.Twitter.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Instagram(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Instagram.Valid {
|
|
||||||
return &obj.Instagram.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Birthdate(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Birthdate.Valid {
|
|
||||||
return &obj.Birthdate.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Ethnicity(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Ethnicity.Valid {
|
|
||||||
return &obj.Ethnicity.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Country(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Country.Valid {
|
|
||||||
return &obj.Country.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) EyeColor(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.EyeColor.Valid {
|
|
||||||
return &obj.EyeColor.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Height(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Height.Valid {
|
|
||||||
return &obj.Height.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Measurements(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Measurements.Valid {
|
|
||||||
return &obj.Measurements.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) FakeTits(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.FakeTits.Valid {
|
|
||||||
return &obj.FakeTits.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) CareerLength(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.CareerLength.Valid {
|
|
||||||
return &obj.CareerLength.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Tattoos(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Tattoos.Valid {
|
|
||||||
return &obj.Tattoos.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Piercings(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Piercings.Valid {
|
|
||||||
return &obj.Piercings.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Aliases(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Aliases.Valid {
|
|
||||||
return &obj.Aliases.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Favorite(ctx context.Context, obj *models.Performer) (bool, error) {
|
|
||||||
if obj.Favorite.Valid {
|
|
||||||
return obj.Favorite.Bool, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) ImagePath(ctx context.Context, obj *models.Performer) (*string, error) {
|
func (r *performerResolver) ImagePath(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||||
imagePath := urlbuilders.NewPerformerURLBuilder(baseURL, obj).GetPerformerImageURL()
|
imagePath := urlbuilders.NewPerformerURLBuilder(baseURL, obj).GetPerformerImageURL()
|
||||||
|
|
@ -212,51 +94,14 @@ func (r *performerResolver) StashIds(ctx context.Context, obj *models.Performer)
|
||||||
return stashIDsSliceToPtrSlice(ret), nil
|
return stashIDsSliceToPtrSlice(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *performerResolver) Rating(ctx context.Context, obj *models.Performer) (*int, error) {
|
|
||||||
if obj.Rating.Valid {
|
|
||||||
rating := int(obj.Rating.Int64)
|
|
||||||
return &rating, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Details(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.Details.Valid {
|
|
||||||
return &obj.Details.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) DeathDate(ctx context.Context, obj *models.Performer) (*string, error) {
|
func (r *performerResolver) DeathDate(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||||
if obj.DeathDate.Valid {
|
if obj.DeathDate != nil {
|
||||||
return &obj.DeathDate.String, nil
|
ret := obj.DeathDate.String()
|
||||||
|
return &ret, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *performerResolver) HairColor(ctx context.Context, obj *models.Performer) (*string, error) {
|
|
||||||
if obj.HairColor.Valid {
|
|
||||||
return &obj.HairColor.String, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Weight(ctx context.Context, obj *models.Performer) (*int, error) {
|
|
||||||
if obj.Weight.Valid {
|
|
||||||
weight := int(obj.Weight.Int64)
|
|
||||||
return &weight, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) CreatedAt(ctx context.Context, obj *models.Performer) (*time.Time, error) {
|
|
||||||
return &obj.CreatedAt.Timestamp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) UpdatedAt(ctx context.Context, obj *models.Performer) (*time.Time, error) {
|
|
||||||
return &obj.UpdatedAt.Timestamp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
func (r *performerResolver) Movies(ctx context.Context, obj *models.Performer) (ret []*models.Movie, err error) {
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||||
ret, err = r.repository.Movie.FindByPerformerID(ctx, obj.ID)
|
ret, err = r.repository.Movie.FindByPerformerID(ctx, obj.ID)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -54,78 +53,75 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||||
// Populate a new performer from the input
|
// Populate a new performer from the input
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
newPerformer := models.Performer{
|
newPerformer := models.Performer{
|
||||||
|
Name: input.Name,
|
||||||
Checksum: checksum,
|
Checksum: checksum,
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: currentTime,
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
UpdatedAt: currentTime,
|
||||||
}
|
}
|
||||||
newPerformer.Name = sql.NullString{String: input.Name, Valid: true}
|
|
||||||
if input.URL != nil {
|
if input.URL != nil {
|
||||||
newPerformer.URL = sql.NullString{String: *input.URL, Valid: true}
|
newPerformer.URL = *input.URL
|
||||||
}
|
}
|
||||||
if input.Gender != nil {
|
if input.Gender != nil {
|
||||||
newPerformer.Gender = sql.NullString{String: input.Gender.String(), Valid: true}
|
newPerformer.Gender = *input.Gender
|
||||||
}
|
}
|
||||||
if input.Birthdate != nil {
|
if input.Birthdate != nil {
|
||||||
newPerformer.Birthdate = models.SQLiteDate{String: *input.Birthdate, Valid: true}
|
d := models.NewDate(*input.Birthdate)
|
||||||
|
newPerformer.Birthdate = &d
|
||||||
}
|
}
|
||||||
if input.Ethnicity != nil {
|
if input.Ethnicity != nil {
|
||||||
newPerformer.Ethnicity = sql.NullString{String: *input.Ethnicity, Valid: true}
|
newPerformer.Ethnicity = *input.Ethnicity
|
||||||
}
|
}
|
||||||
if input.Country != nil {
|
if input.Country != nil {
|
||||||
newPerformer.Country = sql.NullString{String: *input.Country, Valid: true}
|
newPerformer.Country = *input.Country
|
||||||
}
|
}
|
||||||
if input.EyeColor != nil {
|
if input.EyeColor != nil {
|
||||||
newPerformer.EyeColor = sql.NullString{String: *input.EyeColor, Valid: true}
|
newPerformer.EyeColor = *input.EyeColor
|
||||||
}
|
}
|
||||||
if input.Height != nil {
|
if input.Height != nil {
|
||||||
newPerformer.Height = sql.NullString{String: *input.Height, Valid: true}
|
newPerformer.Height = *input.Height
|
||||||
}
|
}
|
||||||
if input.Measurements != nil {
|
if input.Measurements != nil {
|
||||||
newPerformer.Measurements = sql.NullString{String: *input.Measurements, Valid: true}
|
newPerformer.Measurements = *input.Measurements
|
||||||
}
|
}
|
||||||
if input.FakeTits != nil {
|
if input.FakeTits != nil {
|
||||||
newPerformer.FakeTits = sql.NullString{String: *input.FakeTits, Valid: true}
|
newPerformer.FakeTits = *input.FakeTits
|
||||||
}
|
}
|
||||||
if input.CareerLength != nil {
|
if input.CareerLength != nil {
|
||||||
newPerformer.CareerLength = sql.NullString{String: *input.CareerLength, Valid: true}
|
newPerformer.CareerLength = *input.CareerLength
|
||||||
}
|
}
|
||||||
if input.Tattoos != nil {
|
if input.Tattoos != nil {
|
||||||
newPerformer.Tattoos = sql.NullString{String: *input.Tattoos, Valid: true}
|
newPerformer.Tattoos = *input.Tattoos
|
||||||
}
|
}
|
||||||
if input.Piercings != nil {
|
if input.Piercings != nil {
|
||||||
newPerformer.Piercings = sql.NullString{String: *input.Piercings, Valid: true}
|
newPerformer.Piercings = *input.Piercings
|
||||||
}
|
}
|
||||||
if input.Aliases != nil {
|
if input.Aliases != nil {
|
||||||
newPerformer.Aliases = sql.NullString{String: *input.Aliases, Valid: true}
|
newPerformer.Aliases = *input.Aliases
|
||||||
}
|
}
|
||||||
if input.Twitter != nil {
|
if input.Twitter != nil {
|
||||||
newPerformer.Twitter = sql.NullString{String: *input.Twitter, Valid: true}
|
newPerformer.Twitter = *input.Twitter
|
||||||
}
|
}
|
||||||
if input.Instagram != nil {
|
if input.Instagram != nil {
|
||||||
newPerformer.Instagram = sql.NullString{String: *input.Instagram, Valid: true}
|
newPerformer.Instagram = *input.Instagram
|
||||||
}
|
}
|
||||||
if input.Favorite != nil {
|
if input.Favorite != nil {
|
||||||
newPerformer.Favorite = sql.NullBool{Bool: *input.Favorite, Valid: true}
|
newPerformer.Favorite = *input.Favorite
|
||||||
} else {
|
|
||||||
newPerformer.Favorite = sql.NullBool{Bool: false, Valid: true}
|
|
||||||
}
|
}
|
||||||
if input.Rating != nil {
|
if input.Rating != nil {
|
||||||
newPerformer.Rating = sql.NullInt64{Int64: int64(*input.Rating), Valid: true}
|
newPerformer.Rating = input.Rating
|
||||||
} else {
|
|
||||||
newPerformer.Rating = sql.NullInt64{Valid: false}
|
|
||||||
}
|
}
|
||||||
if input.Details != nil {
|
if input.Details != nil {
|
||||||
newPerformer.Details = sql.NullString{String: *input.Details, Valid: true}
|
newPerformer.Details = *input.Details
|
||||||
}
|
}
|
||||||
if input.DeathDate != nil {
|
if input.DeathDate != nil {
|
||||||
newPerformer.DeathDate = models.SQLiteDate{String: *input.DeathDate, Valid: true}
|
d := models.NewDate(*input.DeathDate)
|
||||||
|
newPerformer.DeathDate = &d
|
||||||
}
|
}
|
||||||
if input.HairColor != nil {
|
if input.HairColor != nil {
|
||||||
newPerformer.HairColor = sql.NullString{String: *input.HairColor, Valid: true}
|
newPerformer.HairColor = *input.HairColor
|
||||||
}
|
}
|
||||||
if input.Weight != nil {
|
if input.Weight != nil {
|
||||||
weight := int64(*input.Weight)
|
newPerformer.Weight = input.Weight
|
||||||
newPerformer.Weight = sql.NullInt64{Int64: weight, Valid: true}
|
|
||||||
}
|
}
|
||||||
if input.IgnoreAutoTag != nil {
|
if input.IgnoreAutoTag != nil {
|
||||||
newPerformer.IgnoreAutoTag = *input.IgnoreAutoTag
|
newPerformer.IgnoreAutoTag = *input.IgnoreAutoTag
|
||||||
|
|
@ -138,24 +134,23 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the transaction and save the performer
|
// Start the transaction and save the performer
|
||||||
var performer *models.Performer
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Performer
|
qb := r.repository.Performer
|
||||||
|
|
||||||
performer, err = qb.Create(ctx, newPerformer)
|
err = qb.Create(ctx, &newPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(input.TagIds) > 0 {
|
if len(input.TagIds) > 0 {
|
||||||
if err := r.updatePerformerTags(ctx, performer.ID, input.TagIds); err != nil {
|
if err := r.updatePerformerTags(ctx, newPerformer.ID, input.TagIds); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update image table
|
// update image table
|
||||||
if len(imageData) > 0 {
|
if len(imageData) > 0 {
|
||||||
if err := qb.UpdateImage(ctx, performer.ID, imageData); err != nil {
|
if err := qb.UpdateImage(ctx, newPerformer.ID, imageData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +158,7 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||||
// Save the stash_ids
|
// Save the stash_ids
|
||||||
if input.StashIds != nil {
|
if input.StashIds != nil {
|
||||||
stashIDJoins := stashIDPtrSliceToSlice(input.StashIds)
|
stashIDJoins := stashIDPtrSliceToSlice(input.StashIds)
|
||||||
if err := qb.UpdateStashIDs(ctx, performer.ID, stashIDJoins); err != nil {
|
if err := qb.UpdateStashIDs(ctx, newPerformer.ID, stashIDJoins); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,17 +168,14 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input PerformerC
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.hookExecutor.ExecutePostHooks(ctx, performer.ID, plugin.PerformerCreatePost, input, nil)
|
r.hookExecutor.ExecutePostHooks(ctx, newPerformer.ID, plugin.PerformerCreatePost, input, nil)
|
||||||
return r.getPerformer(ctx, performer.ID)
|
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 PerformerUpdateInput) (*models.Performer, error) {
|
||||||
// Populate performer from the input
|
// Populate performer from the input
|
||||||
performerID, _ := strconv.Atoi(input.ID)
|
performerID, _ := strconv.Atoi(input.ID)
|
||||||
updatedPerformer := models.PerformerPartial{
|
updatedPerformer := models.NewPerformerPartial()
|
||||||
ID: performerID,
|
|
||||||
UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()},
|
|
||||||
}
|
|
||||||
|
|
||||||
translator := changesetTranslator{
|
translator := changesetTranslator{
|
||||||
inputMap: getUpdateInputMap(ctx),
|
inputMap: getUpdateInputMap(ctx),
|
||||||
|
|
@ -203,54 +195,53 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||||
// generate checksum from performer name rather than image
|
// generate checksum from performer name rather than image
|
||||||
checksum := md5.FromString(*input.Name)
|
checksum := md5.FromString(*input.Name)
|
||||||
|
|
||||||
updatedPerformer.Name = &sql.NullString{String: *input.Name, Valid: true}
|
updatedPerformer.Name = models.NewOptionalString(*input.Name)
|
||||||
updatedPerformer.Checksum = &checksum
|
updatedPerformer.Checksum = models.NewOptionalString(checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedPerformer.URL = translator.nullString(input.URL, "url")
|
updatedPerformer.URL = translator.optionalString(input.URL, "url")
|
||||||
|
|
||||||
if translator.hasField("gender") {
|
if translator.hasField("gender") {
|
||||||
if input.Gender != nil {
|
if input.Gender != nil {
|
||||||
updatedPerformer.Gender = &sql.NullString{String: input.Gender.String(), Valid: true}
|
updatedPerformer.Gender = models.NewOptionalString(input.Gender.String())
|
||||||
} else {
|
} else {
|
||||||
updatedPerformer.Gender = &sql.NullString{String: "", Valid: false}
|
updatedPerformer.Gender = models.NewOptionalStringPtr(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedPerformer.Birthdate = translator.sqliteDate(input.Birthdate, "birthdate")
|
updatedPerformer.Birthdate = translator.optionalDate(input.Birthdate, "birthdate")
|
||||||
updatedPerformer.Country = translator.nullString(input.Country, "country")
|
updatedPerformer.Country = translator.optionalString(input.Country, "country")
|
||||||
updatedPerformer.EyeColor = translator.nullString(input.EyeColor, "eye_color")
|
updatedPerformer.EyeColor = translator.optionalString(input.EyeColor, "eye_color")
|
||||||
updatedPerformer.Measurements = translator.nullString(input.Measurements, "measurements")
|
updatedPerformer.Measurements = translator.optionalString(input.Measurements, "measurements")
|
||||||
updatedPerformer.Height = translator.nullString(input.Height, "height")
|
updatedPerformer.Height = translator.optionalString(input.Height, "height")
|
||||||
updatedPerformer.Ethnicity = translator.nullString(input.Ethnicity, "ethnicity")
|
updatedPerformer.Ethnicity = translator.optionalString(input.Ethnicity, "ethnicity")
|
||||||
updatedPerformer.FakeTits = translator.nullString(input.FakeTits, "fake_tits")
|
updatedPerformer.FakeTits = translator.optionalString(input.FakeTits, "fake_tits")
|
||||||
updatedPerformer.CareerLength = translator.nullString(input.CareerLength, "career_length")
|
updatedPerformer.CareerLength = translator.optionalString(input.CareerLength, "career_length")
|
||||||
updatedPerformer.Tattoos = translator.nullString(input.Tattoos, "tattoos")
|
updatedPerformer.Tattoos = translator.optionalString(input.Tattoos, "tattoos")
|
||||||
updatedPerformer.Piercings = translator.nullString(input.Piercings, "piercings")
|
updatedPerformer.Piercings = translator.optionalString(input.Piercings, "piercings")
|
||||||
updatedPerformer.Aliases = translator.nullString(input.Aliases, "aliases")
|
updatedPerformer.Aliases = translator.optionalString(input.Aliases, "aliases")
|
||||||
updatedPerformer.Twitter = translator.nullString(input.Twitter, "twitter")
|
updatedPerformer.Twitter = translator.optionalString(input.Twitter, "twitter")
|
||||||
updatedPerformer.Instagram = translator.nullString(input.Instagram, "instagram")
|
updatedPerformer.Instagram = translator.optionalString(input.Instagram, "instagram")
|
||||||
updatedPerformer.Favorite = translator.nullBool(input.Favorite, "favorite")
|
updatedPerformer.Favorite = translator.optionalBool(input.Favorite, "favorite")
|
||||||
updatedPerformer.Rating = translator.nullInt64(input.Rating, "rating")
|
updatedPerformer.Rating = translator.optionalInt(input.Rating, "rating")
|
||||||
updatedPerformer.Details = translator.nullString(input.Details, "details")
|
updatedPerformer.Details = translator.optionalString(input.Details, "details")
|
||||||
updatedPerformer.DeathDate = translator.sqliteDate(input.DeathDate, "death_date")
|
updatedPerformer.DeathDate = translator.optionalDate(input.DeathDate, "death_date")
|
||||||
updatedPerformer.HairColor = translator.nullString(input.HairColor, "hair_color")
|
updatedPerformer.HairColor = translator.optionalString(input.HairColor, "hair_color")
|
||||||
updatedPerformer.Weight = translator.nullInt64(input.Weight, "weight")
|
updatedPerformer.Weight = translator.optionalInt(input.Weight, "weight")
|
||||||
updatedPerformer.IgnoreAutoTag = input.IgnoreAutoTag
|
updatedPerformer.IgnoreAutoTag = translator.optionalBool(input.IgnoreAutoTag, "ignore_auto_tag")
|
||||||
|
|
||||||
// Start the transaction and save the p
|
// Start the transaction and save the p
|
||||||
var p *models.Performer
|
|
||||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||||
qb := r.repository.Performer
|
qb := r.repository.Performer
|
||||||
|
|
||||||
// need to get existing performer
|
// need to get existing performer
|
||||||
existing, err := qb.Find(ctx, updatedPerformer.ID)
|
existing, err := qb.Find(ctx, performerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if existing == nil {
|
if existing == nil {
|
||||||
return fmt.Errorf("performer with id %d not found", updatedPerformer.ID)
|
return fmt.Errorf("performer with id %d not found", performerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := performer.ValidateDeathDate(existing, input.Birthdate, input.DeathDate); err != nil {
|
if err := performer.ValidateDeathDate(existing, input.Birthdate, input.DeathDate); err != nil {
|
||||||
|
|
@ -259,26 +250,26 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err = qb.Update(ctx, updatedPerformer)
|
_, err = qb.UpdatePartial(ctx, performerID, updatedPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the tags
|
// Save the tags
|
||||||
if translator.hasField("tag_ids") {
|
if translator.hasField("tag_ids") {
|
||||||
if err := r.updatePerformerTags(ctx, p.ID, input.TagIds); err != nil {
|
if err := r.updatePerformerTags(ctx, performerID, input.TagIds); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update image table
|
// update image table
|
||||||
if len(imageData) > 0 {
|
if len(imageData) > 0 {
|
||||||
if err := qb.UpdateImage(ctx, p.ID, imageData); err != nil {
|
if err := qb.UpdateImage(ctx, performerID, imageData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if imageIncluded {
|
} else if imageIncluded {
|
||||||
// must be unsetting
|
// must be unsetting
|
||||||
if err := qb.DestroyImage(ctx, p.ID); err != nil {
|
if err := qb.DestroyImage(ctx, performerID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -296,8 +287,8 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input PerformerU
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.hookExecutor.ExecutePostHooks(ctx, p.ID, plugin.PerformerUpdatePost, input, translator.getFields())
|
r.hookExecutor.ExecutePostHooks(ctx, performerID, plugin.PerformerUpdatePost, input, translator.getFields())
|
||||||
return r.getPerformer(ctx, p.ID)
|
return r.getPerformer(ctx, performerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mutationResolver) updatePerformerTags(ctx context.Context, performerID int, tagsIDs []string) error {
|
func (r *mutationResolver) updatePerformerTags(ctx context.Context, performerID int, tagsIDs []string) error {
|
||||||
|
|
@ -315,43 +306,39 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate performer from the input
|
// Populate performer from the input
|
||||||
updatedTime := time.Now()
|
|
||||||
|
|
||||||
translator := changesetTranslator{
|
translator := changesetTranslator{
|
||||||
inputMap: getUpdateInputMap(ctx),
|
inputMap: getUpdateInputMap(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedPerformer := models.PerformerPartial{
|
updatedPerformer := models.NewPerformerPartial()
|
||||||
UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime},
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedPerformer.URL = translator.nullString(input.URL, "url")
|
updatedPerformer.URL = translator.optionalString(input.URL, "url")
|
||||||
updatedPerformer.Birthdate = translator.sqliteDate(input.Birthdate, "birthdate")
|
updatedPerformer.Birthdate = translator.optionalDate(input.Birthdate, "birthdate")
|
||||||
updatedPerformer.Ethnicity = translator.nullString(input.Ethnicity, "ethnicity")
|
updatedPerformer.Ethnicity = translator.optionalString(input.Ethnicity, "ethnicity")
|
||||||
updatedPerformer.Country = translator.nullString(input.Country, "country")
|
updatedPerformer.Country = translator.optionalString(input.Country, "country")
|
||||||
updatedPerformer.EyeColor = translator.nullString(input.EyeColor, "eye_color")
|
updatedPerformer.EyeColor = translator.optionalString(input.EyeColor, "eye_color")
|
||||||
updatedPerformer.Height = translator.nullString(input.Height, "height")
|
updatedPerformer.Height = translator.optionalString(input.Height, "height")
|
||||||
updatedPerformer.Measurements = translator.nullString(input.Measurements, "measurements")
|
updatedPerformer.Measurements = translator.optionalString(input.Measurements, "measurements")
|
||||||
updatedPerformer.FakeTits = translator.nullString(input.FakeTits, "fake_tits")
|
updatedPerformer.FakeTits = translator.optionalString(input.FakeTits, "fake_tits")
|
||||||
updatedPerformer.CareerLength = translator.nullString(input.CareerLength, "career_length")
|
updatedPerformer.CareerLength = translator.optionalString(input.CareerLength, "career_length")
|
||||||
updatedPerformer.Tattoos = translator.nullString(input.Tattoos, "tattoos")
|
updatedPerformer.Tattoos = translator.optionalString(input.Tattoos, "tattoos")
|
||||||
updatedPerformer.Piercings = translator.nullString(input.Piercings, "piercings")
|
updatedPerformer.Piercings = translator.optionalString(input.Piercings, "piercings")
|
||||||
updatedPerformer.Aliases = translator.nullString(input.Aliases, "aliases")
|
updatedPerformer.Aliases = translator.optionalString(input.Aliases, "aliases")
|
||||||
updatedPerformer.Twitter = translator.nullString(input.Twitter, "twitter")
|
updatedPerformer.Twitter = translator.optionalString(input.Twitter, "twitter")
|
||||||
updatedPerformer.Instagram = translator.nullString(input.Instagram, "instagram")
|
updatedPerformer.Instagram = translator.optionalString(input.Instagram, "instagram")
|
||||||
updatedPerformer.Favorite = translator.nullBool(input.Favorite, "favorite")
|
updatedPerformer.Favorite = translator.optionalBool(input.Favorite, "favorite")
|
||||||
updatedPerformer.Rating = translator.nullInt64(input.Rating, "rating")
|
updatedPerformer.Rating = translator.optionalInt(input.Rating, "rating")
|
||||||
updatedPerformer.Details = translator.nullString(input.Details, "details")
|
updatedPerformer.Details = translator.optionalString(input.Details, "details")
|
||||||
updatedPerformer.DeathDate = translator.sqliteDate(input.DeathDate, "death_date")
|
updatedPerformer.DeathDate = translator.optionalDate(input.DeathDate, "death_date")
|
||||||
updatedPerformer.HairColor = translator.nullString(input.HairColor, "hair_color")
|
updatedPerformer.HairColor = translator.optionalString(input.HairColor, "hair_color")
|
||||||
updatedPerformer.Weight = translator.nullInt64(input.Weight, "weight")
|
updatedPerformer.Weight = translator.optionalInt(input.Weight, "weight")
|
||||||
updatedPerformer.IgnoreAutoTag = input.IgnoreAutoTag
|
updatedPerformer.IgnoreAutoTag = translator.optionalBool(input.IgnoreAutoTag, "ignore_auto_tag")
|
||||||
|
|
||||||
if translator.hasField("gender") {
|
if translator.hasField("gender") {
|
||||||
if input.Gender != nil {
|
if input.Gender != nil {
|
||||||
updatedPerformer.Gender = &sql.NullString{String: input.Gender.String(), Valid: true}
|
updatedPerformer.Gender = models.NewOptionalString(input.Gender.String())
|
||||||
} else {
|
} else {
|
||||||
updatedPerformer.Gender = &sql.NullString{String: "", Valid: false}
|
updatedPerformer.Gender = models.NewOptionalStringPtr(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -378,7 +365,7 @@ func (r *mutationResolver) BulkPerformerUpdate(ctx context.Context, input BulkPe
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
performer, err := qb.Update(ctx, updatedPerformer)
|
performer, err := qb.UpdatePartial(ctx, performerID, updatedPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(image) == 0 || defaultParam == "true" {
|
if len(image) == 0 || defaultParam == "true" {
|
||||||
image, _ = getRandomPerformerImageUsingName(performer.Name.String, performer.Gender.String, config.GetInstance().GetCustomPerformerImageLocation())
|
image, _ = getRandomPerformerImageUsingName(performer.Name, performer.Gender, config.GetInstance().GetCustomPerformerImageLocation())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := utils.ServeImage(image, w, r); err != nil {
|
if err := utils.ServeImage(image, w, r); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package urlbuilders
|
package urlbuilders
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/stashapp/stash/pkg/models"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PerformerURLBuilder struct {
|
type PerformerURLBuilder struct {
|
||||||
|
|
@ -15,7 +16,7 @@ func NewPerformerURLBuilder(baseURL string, performer *models.Performer) Perform
|
||||||
return PerformerURLBuilder{
|
return PerformerURLBuilder{
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
PerformerID: strconv.Itoa(performer.ID),
|
PerformerID: strconv.Itoa(performer.ID),
|
||||||
UpdatedAt: strconv.FormatInt(performer.UpdatedAt.Timestamp.Unix(), 10),
|
UpdatedAt: strconv.FormatInt(performer.UpdatedAt.Unix(), 10),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,14 +22,14 @@ func TestGalleryPerformers(t *testing.T) {
|
||||||
const performerID = 2
|
const performerID = 2
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
ID: performerID,
|
ID: performerID,
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
const reversedPerformerName = "name performer"
|
const reversedPerformerName = "name performer"
|
||||||
const reversedPerformerID = 3
|
const reversedPerformerID = 3
|
||||||
reversedPerformer := models.Performer{
|
reversedPerformer := models.Performer{
|
||||||
ID: reversedPerformerID,
|
ID: reversedPerformerID,
|
||||||
Name: models.NullString(reversedPerformerName),
|
Name: reversedPerformerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
testTables := generateTestTable(performerName, galleryExt)
|
testTables := generateTestTable(performerName, galleryExt)
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,14 @@ func TestImagePerformers(t *testing.T) {
|
||||||
const performerID = 2
|
const performerID = 2
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
ID: performerID,
|
ID: performerID,
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
const reversedPerformerName = "name performer"
|
const reversedPerformerName = "name performer"
|
||||||
const reversedPerformerID = 3
|
const reversedPerformerID = 3
|
||||||
reversedPerformer := models.Performer{
|
reversedPerformer := models.Performer{
|
||||||
ID: reversedPerformerID,
|
ID: reversedPerformerID,
|
||||||
Name: models.NullString(reversedPerformerName),
|
Name: reversedPerformerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
testTables := generateTestTable(performerName, imageExt)
|
testTables := generateTestTable(performerName, imageExt)
|
||||||
|
|
|
||||||
|
|
@ -87,11 +87,10 @@ func createPerformer(ctx context.Context, pqb models.PerformerWriter) error {
|
||||||
// create the performer
|
// create the performer
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
Checksum: testName,
|
Checksum: testName,
|
||||||
Name: sql.NullString{Valid: true, String: testName},
|
Name: testName,
|
||||||
Favorite: sql.NullBool{Valid: true, Bool: false},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := pqb.Create(ctx, performer)
|
err := pqb.Create(ctx, &performer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func getPerformerTagger(p *models.Performer, cache *match.Cache) tagger {
|
||||||
return tagger{
|
return tagger{
|
||||||
ID: p.ID,
|
ID: p.ID,
|
||||||
Type: "performer",
|
Type: "performer",
|
||||||
Name: p.Name.String,
|
Name: p.Name,
|
||||||
cache: cache,
|
cache: cache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func testPerformerScenes(t *testing.T, performerName, expectedRegex string) {
|
||||||
|
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
ID: performerID,
|
ID: performerID,
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
organized := false
|
organized := false
|
||||||
|
|
@ -140,7 +140,7 @@ func testPerformerImages(t *testing.T, performerName, expectedRegex string) {
|
||||||
|
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
ID: performerID,
|
ID: performerID,
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
organized := false
|
organized := false
|
||||||
|
|
@ -221,7 +221,7 @@ func testPerformerGalleries(t *testing.T, performerName, expectedRegex string) {
|
||||||
|
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
ID: performerID,
|
ID: performerID,
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
organized := false
|
organized := false
|
||||||
|
|
|
||||||
|
|
@ -152,14 +152,14 @@ func TestScenePerformers(t *testing.T) {
|
||||||
const performerID = 2
|
const performerID = 2
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
ID: performerID,
|
ID: performerID,
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
const reversedPerformerName = "name performer"
|
const reversedPerformerName = "name performer"
|
||||||
const reversedPerformerID = 3
|
const reversedPerformerID = 3
|
||||||
reversedPerformer := models.Performer{
|
reversedPerformer := models.Performer{
|
||||||
ID: reversedPerformerID,
|
ID: reversedPerformerID,
|
||||||
Name: models.NullString(reversedPerformerName),
|
Name: reversedPerformerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
testTables := generateTestTable(performerName, sceneExt)
|
testTables := generateTestTable(performerName, sceneExt)
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,11 @@ func (t *tagger) tagPerformers(ctx context.Context, performerReader match.Perfor
|
||||||
added, err := addFunc(t.ID, p.ID)
|
added, err := addFunc(t.ID, p.ID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return t.addError("performer", p.Name.String, err)
|
return t.addError("performer", p.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if added {
|
if added {
|
||||||
t.addLog("performer", p.Name.String)
|
t.addLog("performer", p.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -612,7 +612,7 @@ func (me *contentDirectoryService) getPerformers() []interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range performers {
|
for _, s := range performers {
|
||||||
objs = append(objs, makeStorageFolder("performers/"+strconv.Itoa(s.ID), s.Name.String, "performers"))
|
objs = append(objs, makeStorageFolder("performers/"+strconv.Itoa(s.ID), s.Name, "performers"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package identify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -12,7 +11,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type PerformerCreator interface {
|
type PerformerCreator interface {
|
||||||
Create(ctx context.Context, newPerformer models.Performer) (*models.Performer, error)
|
Create(ctx context.Context, newPerformer *models.Performer) error
|
||||||
UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error
|
UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,13 +32,14 @@ func getPerformerID(ctx context.Context, endpoint string, w PerformerCreator, p
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMissingPerformer(ctx context.Context, endpoint string, w PerformerCreator, p *models.ScrapedPerformer) (*int, error) {
|
func createMissingPerformer(ctx context.Context, endpoint string, w PerformerCreator, p *models.ScrapedPerformer) (*int, error) {
|
||||||
created, err := w.Create(ctx, scrapedToPerformerInput(p))
|
performerInput := scrapedToPerformerInput(p)
|
||||||
|
err := w.Create(ctx, &performerInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating performer: %w", err)
|
return nil, fmt.Errorf("error creating performer: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if endpoint != "" && p.RemoteSiteID != nil {
|
if endpoint != "" && p.RemoteSiteID != nil {
|
||||||
if err := w.UpdateStashIDs(ctx, created.ID, []models.StashID{
|
if err := w.UpdateStashIDs(ctx, performerInput.ID, []models.StashID{
|
||||||
{
|
{
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
StashID: *p.RemoteSiteID,
|
StashID: *p.RemoteSiteID,
|
||||||
|
|
@ -49,65 +49,66 @@ func createMissingPerformer(ctx context.Context, endpoint string, w PerformerCre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &created.ID, nil
|
return &performerInput.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrapedToPerformerInput(performer *models.ScrapedPerformer) models.Performer {
|
func scrapedToPerformerInput(performer *models.ScrapedPerformer) models.Performer {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
ret := models.Performer{
|
ret := models.Performer{
|
||||||
Name: sql.NullString{String: *performer.Name, Valid: true},
|
Name: *performer.Name,
|
||||||
Checksum: md5.FromString(*performer.Name),
|
Checksum: md5.FromString(*performer.Name),
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: currentTime,
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
UpdatedAt: currentTime,
|
||||||
Favorite: sql.NullBool{Bool: false, Valid: true},
|
|
||||||
}
|
}
|
||||||
if performer.Birthdate != nil {
|
if performer.Birthdate != nil {
|
||||||
ret.Birthdate = models.SQLiteDate{String: *performer.Birthdate, Valid: true}
|
d := models.NewDate(*performer.Birthdate)
|
||||||
|
ret.Birthdate = &d
|
||||||
}
|
}
|
||||||
if performer.DeathDate != nil {
|
if performer.DeathDate != nil {
|
||||||
ret.DeathDate = models.SQLiteDate{String: *performer.DeathDate, Valid: true}
|
d := models.NewDate(*performer.DeathDate)
|
||||||
|
ret.DeathDate = &d
|
||||||
}
|
}
|
||||||
if performer.Gender != nil {
|
if performer.Gender != nil {
|
||||||
ret.Gender = sql.NullString{String: *performer.Gender, Valid: true}
|
ret.Gender = models.GenderEnum(*performer.Gender)
|
||||||
}
|
}
|
||||||
if performer.Ethnicity != nil {
|
if performer.Ethnicity != nil {
|
||||||
ret.Ethnicity = sql.NullString{String: *performer.Ethnicity, Valid: true}
|
ret.Ethnicity = *performer.Ethnicity
|
||||||
}
|
}
|
||||||
if performer.Country != nil {
|
if performer.Country != nil {
|
||||||
ret.Country = sql.NullString{String: *performer.Country, Valid: true}
|
ret.Country = *performer.Country
|
||||||
}
|
}
|
||||||
if performer.EyeColor != nil {
|
if performer.EyeColor != nil {
|
||||||
ret.EyeColor = sql.NullString{String: *performer.EyeColor, Valid: true}
|
ret.EyeColor = *performer.EyeColor
|
||||||
}
|
}
|
||||||
if performer.HairColor != nil {
|
if performer.HairColor != nil {
|
||||||
ret.HairColor = sql.NullString{String: *performer.HairColor, Valid: true}
|
ret.HairColor = *performer.HairColor
|
||||||
}
|
}
|
||||||
if performer.Height != nil {
|
if performer.Height != nil {
|
||||||
ret.Height = sql.NullString{String: *performer.Height, Valid: true}
|
ret.Height = *performer.Height
|
||||||
}
|
}
|
||||||
if performer.Measurements != nil {
|
if performer.Measurements != nil {
|
||||||
ret.Measurements = sql.NullString{String: *performer.Measurements, Valid: true}
|
ret.Measurements = *performer.Measurements
|
||||||
}
|
}
|
||||||
if performer.FakeTits != nil {
|
if performer.FakeTits != nil {
|
||||||
ret.FakeTits = sql.NullString{String: *performer.FakeTits, Valid: true}
|
ret.FakeTits = *performer.FakeTits
|
||||||
}
|
}
|
||||||
if performer.CareerLength != nil {
|
if performer.CareerLength != nil {
|
||||||
ret.CareerLength = sql.NullString{String: *performer.CareerLength, Valid: true}
|
ret.CareerLength = *performer.CareerLength
|
||||||
}
|
}
|
||||||
if performer.Tattoos != nil {
|
if performer.Tattoos != nil {
|
||||||
ret.Tattoos = sql.NullString{String: *performer.Tattoos, Valid: true}
|
ret.Tattoos = *performer.Tattoos
|
||||||
}
|
}
|
||||||
if performer.Piercings != nil {
|
if performer.Piercings != nil {
|
||||||
ret.Piercings = sql.NullString{String: *performer.Piercings, Valid: true}
|
ret.Piercings = *performer.Piercings
|
||||||
}
|
}
|
||||||
if performer.Aliases != nil {
|
if performer.Aliases != nil {
|
||||||
ret.Aliases = sql.NullString{String: *performer.Aliases, Valid: true}
|
ret.Aliases = *performer.Aliases
|
||||||
}
|
}
|
||||||
if performer.Twitter != nil {
|
if performer.Twitter != nil {
|
||||||
ret.Twitter = sql.NullString{String: *performer.Twitter, Valid: true}
|
ret.Twitter = *performer.Twitter
|
||||||
}
|
}
|
||||||
if performer.Instagram != nil {
|
if performer.Instagram != nil {
|
||||||
ret.Instagram = sql.NullString{String: *performer.Instagram, Valid: true}
|
ret.Instagram = *performer.Instagram
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package identify
|
package identify
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"github.com/stashapp/stash/pkg/models/mocks"
|
"github.com/stashapp/stash/pkg/models/mocks"
|
||||||
|
|
@ -24,9 +24,10 @@ func Test_getPerformerID(t *testing.T) {
|
||||||
name := "name"
|
name := "name"
|
||||||
|
|
||||||
mockPerformerReaderWriter := mocks.PerformerReaderWriter{}
|
mockPerformerReaderWriter := mocks.PerformerReaderWriter{}
|
||||||
mockPerformerReaderWriter.On("Create", testCtx, mock.Anything).Return(&models.Performer{
|
mockPerformerReaderWriter.On("Create", testCtx, mock.Anything).Run(func(args mock.Arguments) {
|
||||||
ID: validStoredID,
|
p := args.Get(1).(*models.Performer)
|
||||||
}, nil)
|
p.ID = validStoredID
|
||||||
|
}).Return(nil)
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
endpoint string
|
endpoint string
|
||||||
|
|
@ -132,14 +133,16 @@ func Test_createMissingPerformer(t *testing.T) {
|
||||||
performerID := 1
|
performerID := 1
|
||||||
|
|
||||||
mockPerformerReaderWriter := mocks.PerformerReaderWriter{}
|
mockPerformerReaderWriter := mocks.PerformerReaderWriter{}
|
||||||
mockPerformerReaderWriter.On("Create", testCtx, mock.MatchedBy(func(p models.Performer) bool {
|
mockPerformerReaderWriter.On("Create", testCtx, mock.MatchedBy(func(p *models.Performer) bool {
|
||||||
return p.Name.String == validName
|
return p.Name == validName
|
||||||
})).Return(&models.Performer{
|
})).Run(func(args mock.Arguments) {
|
||||||
ID: performerID,
|
p := args.Get(1).(*models.Performer)
|
||||||
}, nil)
|
p.ID = performerID
|
||||||
mockPerformerReaderWriter.On("Create", testCtx, mock.MatchedBy(func(p models.Performer) bool {
|
}).Return(nil)
|
||||||
return p.Name.String == invalidName
|
|
||||||
})).Return(nil, errors.New("error creating performer"))
|
mockPerformerReaderWriter.On("Create", testCtx, mock.MatchedBy(func(p *models.Performer) bool {
|
||||||
|
return p.Name == invalidName
|
||||||
|
})).Return(errors.New("error creating performer"))
|
||||||
|
|
||||||
mockPerformerReaderWriter.On("UpdateStashIDs", testCtx, performerID, []models.StashID{
|
mockPerformerReaderWriter.On("UpdateStashIDs", testCtx, performerID, []models.StashID{
|
||||||
{
|
{
|
||||||
|
|
@ -241,6 +244,10 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
||||||
return &ret
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dateToDatePtr := func(d models.Date) *models.Date {
|
||||||
|
return &d
|
||||||
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
performer *models.ScrapedPerformer
|
performer *models.ScrapedPerformer
|
||||||
|
|
@ -268,34 +275,24 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
||||||
Instagram: nextVal(),
|
Instagram: nextVal(),
|
||||||
},
|
},
|
||||||
models.Performer{
|
models.Performer{
|
||||||
Name: models.NullString(name),
|
Name: name,
|
||||||
Checksum: md5,
|
Checksum: md5,
|
||||||
Favorite: sql.NullBool{
|
Birthdate: dateToDatePtr(models.NewDate(*nextVal())),
|
||||||
Bool: false,
|
DeathDate: dateToDatePtr(models.NewDate(*nextVal())),
|
||||||
Valid: true,
|
Gender: models.GenderEnum(*nextVal()),
|
||||||
},
|
Ethnicity: *nextVal(),
|
||||||
Birthdate: models.SQLiteDate{
|
Country: *nextVal(),
|
||||||
String: *nextVal(),
|
EyeColor: *nextVal(),
|
||||||
Valid: true,
|
HairColor: *nextVal(),
|
||||||
},
|
Height: *nextVal(),
|
||||||
DeathDate: models.SQLiteDate{
|
Measurements: *nextVal(),
|
||||||
String: *nextVal(),
|
FakeTits: *nextVal(),
|
||||||
Valid: true,
|
CareerLength: *nextVal(),
|
||||||
},
|
Tattoos: *nextVal(),
|
||||||
Gender: models.NullString(*nextVal()),
|
Piercings: *nextVal(),
|
||||||
Ethnicity: models.NullString(*nextVal()),
|
Aliases: *nextVal(),
|
||||||
Country: models.NullString(*nextVal()),
|
Twitter: *nextVal(),
|
||||||
EyeColor: models.NullString(*nextVal()),
|
Instagram: *nextVal(),
|
||||||
HairColor: models.NullString(*nextVal()),
|
|
||||||
Height: models.NullString(*nextVal()),
|
|
||||||
Measurements: models.NullString(*nextVal()),
|
|
||||||
FakeTits: models.NullString(*nextVal()),
|
|
||||||
CareerLength: models.NullString(*nextVal()),
|
|
||||||
Tattoos: models.NullString(*nextVal()),
|
|
||||||
Piercings: models.NullString(*nextVal()),
|
|
||||||
Aliases: models.NullString(*nextVal()),
|
|
||||||
Twitter: models.NullString(*nextVal()),
|
|
||||||
Instagram: models.NullString(*nextVal()),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -304,12 +301,8 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
||||||
Name: &name,
|
Name: &name,
|
||||||
},
|
},
|
||||||
models.Performer{
|
models.Performer{
|
||||||
Name: models.NullString(name),
|
Name: name,
|
||||||
Checksum: md5,
|
Checksum: md5,
|
||||||
Favorite: sql.NullBool{
|
|
||||||
Bool: false,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -318,7 +311,7 @@ func Test_scrapedToPerformerInput(t *testing.T) {
|
||||||
got := scrapedToPerformerInput(tt.performer)
|
got := scrapedToPerformerInput(tt.performer)
|
||||||
|
|
||||||
// clear created/updated dates
|
// clear created/updated dates
|
||||||
got.CreatedAt = models.SQLiteTimestamp{}
|
got.CreatedAt = time.Time{}
|
||||||
got.UpdatedAt = got.CreatedAt
|
got.UpdatedAt = got.CreatedAt
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ func (j *autoTagJob) autoTagPerformers(ctx context.Context, progress *job.Progre
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("error auto-tagging performer '%s': %s", performer.Name.String, err.Error())
|
return fmt.Errorf("error auto-tagging performer '%s': %s", performer.Name, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
progress.Increment()
|
progress.Increment()
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -31,7 +30,7 @@ func (t *StashBoxPerformerTagTask) Description() string {
|
||||||
if t.name != nil {
|
if t.name != nil {
|
||||||
name = *t.name
|
name = *t.name
|
||||||
} else if t.performer != nil {
|
} else if t.performer != nil {
|
||||||
name = t.performer.Name.String
|
name = t.performer.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("Tagging performer %s from stash-box", name)
|
return fmt.Sprintf("Tagging performer %s from stash-box", name)
|
||||||
|
|
@ -70,7 +69,7 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
||||||
if t.name != nil {
|
if t.name != nil {
|
||||||
name = *t.name
|
name = *t.name
|
||||||
} else {
|
} else {
|
||||||
name = t.performer.Name.String
|
name = t.performer.Name
|
||||||
}
|
}
|
||||||
performer, err = client.FindStashBoxPerformerByName(ctx, name)
|
performer, err = client.FindStashBoxPerformerByName(ctx, name)
|
||||||
}
|
}
|
||||||
|
|
@ -86,84 +85,64 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if performer != nil {
|
if performer != nil {
|
||||||
updatedTime := time.Now()
|
|
||||||
|
|
||||||
if t.performer != nil {
|
if t.performer != nil {
|
||||||
partial := models.PerformerPartial{
|
partial := models.NewPerformerPartial()
|
||||||
ID: t.performer.ID,
|
|
||||||
UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime},
|
|
||||||
}
|
|
||||||
|
|
||||||
if performer.Aliases != nil && !excluded["aliases"] {
|
if performer.Aliases != nil && !excluded["aliases"] {
|
||||||
value := getNullString(performer.Aliases)
|
partial.Aliases = models.NewOptionalString(*performer.Aliases)
|
||||||
partial.Aliases = &value
|
|
||||||
}
|
}
|
||||||
if performer.Birthdate != nil && *performer.Birthdate != "" && !excluded["birthdate"] {
|
if performer.Birthdate != nil && *performer.Birthdate != "" && !excluded["birthdate"] {
|
||||||
value := getDate(performer.Birthdate)
|
value := getDate(performer.Birthdate)
|
||||||
partial.Birthdate = &value
|
partial.Birthdate = models.NewOptionalDate(*value)
|
||||||
}
|
}
|
||||||
if performer.CareerLength != nil && !excluded["career_length"] {
|
if performer.CareerLength != nil && !excluded["career_length"] {
|
||||||
value := getNullString(performer.CareerLength)
|
partial.CareerLength = models.NewOptionalString(*performer.CareerLength)
|
||||||
partial.CareerLength = &value
|
|
||||||
}
|
}
|
||||||
if performer.Country != nil && !excluded["country"] {
|
if performer.Country != nil && !excluded["country"] {
|
||||||
value := getNullString(performer.Country)
|
partial.Country = models.NewOptionalString(*performer.Country)
|
||||||
partial.Country = &value
|
|
||||||
}
|
}
|
||||||
if performer.Ethnicity != nil && !excluded["ethnicity"] {
|
if performer.Ethnicity != nil && !excluded["ethnicity"] {
|
||||||
value := getNullString(performer.Ethnicity)
|
partial.Ethnicity = models.NewOptionalString(*performer.Ethnicity)
|
||||||
partial.Ethnicity = &value
|
|
||||||
}
|
}
|
||||||
if performer.EyeColor != nil && !excluded["eye_color"] {
|
if performer.EyeColor != nil && !excluded["eye_color"] {
|
||||||
value := getNullString(performer.EyeColor)
|
partial.EyeColor = models.NewOptionalString(*performer.EyeColor)
|
||||||
partial.EyeColor = &value
|
|
||||||
}
|
}
|
||||||
if performer.FakeTits != nil && !excluded["fake_tits"] {
|
if performer.FakeTits != nil && !excluded["fake_tits"] {
|
||||||
value := getNullString(performer.FakeTits)
|
partial.FakeTits = models.NewOptionalString(*performer.FakeTits)
|
||||||
partial.FakeTits = &value
|
|
||||||
}
|
}
|
||||||
if performer.Gender != nil && !excluded["gender"] {
|
if performer.Gender != nil && !excluded["gender"] {
|
||||||
value := getNullString(performer.Gender)
|
partial.Gender = models.NewOptionalString(*performer.Gender)
|
||||||
partial.Gender = &value
|
|
||||||
}
|
}
|
||||||
if performer.Height != nil && !excluded["height"] {
|
if performer.Height != nil && !excluded["height"] {
|
||||||
value := getNullString(performer.Height)
|
partial.Height = models.NewOptionalString(*performer.Height)
|
||||||
partial.Height = &value
|
|
||||||
}
|
}
|
||||||
if performer.Instagram != nil && !excluded["instagram"] {
|
if performer.Instagram != nil && !excluded["instagram"] {
|
||||||
value := getNullString(performer.Instagram)
|
partial.Instagram = models.NewOptionalString(*performer.Instagram)
|
||||||
partial.Instagram = &value
|
|
||||||
}
|
}
|
||||||
if performer.Measurements != nil && !excluded["measurements"] {
|
if performer.Measurements != nil && !excluded["measurements"] {
|
||||||
value := getNullString(performer.Measurements)
|
partial.Measurements = models.NewOptionalString(*performer.Measurements)
|
||||||
partial.Measurements = &value
|
|
||||||
}
|
}
|
||||||
if excluded["name"] && performer.Name != nil {
|
if excluded["name"] && performer.Name != nil {
|
||||||
value := sql.NullString{String: *performer.Name, Valid: true}
|
partial.Name = models.NewOptionalString(*performer.Name)
|
||||||
partial.Name = &value
|
|
||||||
checksum := md5.FromString(*performer.Name)
|
checksum := md5.FromString(*performer.Name)
|
||||||
partial.Checksum = &checksum
|
partial.Checksum = models.NewOptionalString(checksum)
|
||||||
}
|
}
|
||||||
if performer.Piercings != nil && !excluded["piercings"] {
|
if performer.Piercings != nil && !excluded["piercings"] {
|
||||||
value := getNullString(performer.Piercings)
|
partial.Piercings = models.NewOptionalString(*performer.Piercings)
|
||||||
partial.Piercings = &value
|
|
||||||
}
|
}
|
||||||
if performer.Tattoos != nil && !excluded["tattoos"] {
|
if performer.Tattoos != nil && !excluded["tattoos"] {
|
||||||
value := getNullString(performer.Tattoos)
|
partial.Tattoos = models.NewOptionalString(*performer.Tattoos)
|
||||||
partial.Tattoos = &value
|
|
||||||
}
|
}
|
||||||
if performer.Twitter != nil && !excluded["twitter"] {
|
if performer.Twitter != nil && !excluded["twitter"] {
|
||||||
value := getNullString(performer.Twitter)
|
partial.Twitter = models.NewOptionalString(*performer.Twitter)
|
||||||
partial.Twitter = &value
|
|
||||||
}
|
}
|
||||||
if performer.URL != nil && !excluded["url"] {
|
if performer.URL != nil && !excluded["url"] {
|
||||||
value := getNullString(performer.URL)
|
partial.URL = models.NewOptionalString(*performer.URL)
|
||||||
partial.URL = &value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txnErr := txn.WithTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
txnErr := txn.WithTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
||||||
r := instance.Repository
|
r := instance.Repository
|
||||||
_, err := r.Performer.Update(ctx, partial)
|
_, err := r.Performer.UpdatePartial(ctx, t.performer.ID, partial)
|
||||||
|
|
||||||
if !t.refresh {
|
if !t.refresh {
|
||||||
err = r.Performer.UpdateStashIDs(ctx, t.performer.ID, []models.StashID{
|
err = r.Performer.UpdateStashIDs(ctx, t.performer.ID, []models.StashID{
|
||||||
|
|
@ -203,35 +182,34 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
||||||
} else if t.name != nil && performer.Name != nil {
|
} else if t.name != nil && performer.Name != nil {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
newPerformer := models.Performer{
|
newPerformer := models.Performer{
|
||||||
Aliases: getNullString(performer.Aliases),
|
Aliases: getString(performer.Aliases),
|
||||||
Birthdate: getDate(performer.Birthdate),
|
Birthdate: getDate(performer.Birthdate),
|
||||||
CareerLength: getNullString(performer.CareerLength),
|
CareerLength: getString(performer.CareerLength),
|
||||||
Checksum: md5.FromString(*performer.Name),
|
Checksum: md5.FromString(*performer.Name),
|
||||||
Country: getNullString(performer.Country),
|
Country: getString(performer.Country),
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: currentTime,
|
||||||
Ethnicity: getNullString(performer.Ethnicity),
|
Ethnicity: getString(performer.Ethnicity),
|
||||||
EyeColor: getNullString(performer.EyeColor),
|
EyeColor: getString(performer.EyeColor),
|
||||||
FakeTits: getNullString(performer.FakeTits),
|
FakeTits: getString(performer.FakeTits),
|
||||||
Favorite: sql.NullBool{Bool: false, Valid: true},
|
Gender: models.GenderEnum(getString(performer.Gender)),
|
||||||
Gender: getNullString(performer.Gender),
|
Height: getString(performer.Height),
|
||||||
Height: getNullString(performer.Height),
|
Instagram: getString(performer.Instagram),
|
||||||
Instagram: getNullString(performer.Instagram),
|
Measurements: getString(performer.Measurements),
|
||||||
Measurements: getNullString(performer.Measurements),
|
Name: *performer.Name,
|
||||||
Name: sql.NullString{String: *performer.Name, Valid: true},
|
Piercings: getString(performer.Piercings),
|
||||||
Piercings: getNullString(performer.Piercings),
|
Tattoos: getString(performer.Tattoos),
|
||||||
Tattoos: getNullString(performer.Tattoos),
|
Twitter: getString(performer.Twitter),
|
||||||
Twitter: getNullString(performer.Twitter),
|
URL: getString(performer.URL),
|
||||||
URL: getNullString(performer.URL),
|
UpdatedAt: currentTime,
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
|
||||||
}
|
}
|
||||||
err := txn.WithTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
err := txn.WithTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
||||||
r := instance.Repository
|
r := instance.Repository
|
||||||
createdPerformer, err := r.Performer.Create(ctx, newPerformer)
|
err := r.Performer.Create(ctx, &newPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = r.Performer.UpdateStashIDs(ctx, createdPerformer.ID, []models.StashID{
|
err = r.Performer.UpdateStashIDs(ctx, newPerformer.ID, []models.StashID{
|
||||||
{
|
{
|
||||||
Endpoint: t.box.Endpoint,
|
Endpoint: t.box.Endpoint,
|
||||||
StashID: *performer.RemoteSiteID,
|
StashID: *performer.RemoteSiteID,
|
||||||
|
|
@ -246,7 +224,7 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
||||||
if imageErr != nil {
|
if imageErr != nil {
|
||||||
return imageErr
|
return imageErr
|
||||||
}
|
}
|
||||||
err = r.Performer.UpdateImage(ctx, createdPerformer.ID, image)
|
err = r.Performer.UpdateImage(ctx, newPerformer.ID, image)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
@ -261,24 +239,25 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
||||||
if t.name != nil {
|
if t.name != nil {
|
||||||
name = *t.name
|
name = *t.name
|
||||||
} else if t.performer != nil {
|
} else if t.performer != nil {
|
||||||
name = t.performer.Name.String
|
name = t.performer.Name
|
||||||
}
|
}
|
||||||
logger.Infof("No match found for %s", name)
|
logger.Infof("No match found for %s", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDate(val *string) models.SQLiteDate {
|
func getDate(val *string) *models.Date {
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return models.SQLiteDate{Valid: false}
|
return nil
|
||||||
} else {
|
|
||||||
return models.SQLiteDate{String: *val, Valid: true}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret := models.NewDate(*val)
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNullString(val *string) sql.NullString {
|
func getString(val *string) string {
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return sql.NullString{Valid: false}
|
return ""
|
||||||
} else {
|
} else {
|
||||||
return sql.NullString{String: *val, Valid: true}
|
return *val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,10 +136,10 @@ func (i *Importer) populatePerformers(ctx context.Context) error {
|
||||||
|
|
||||||
var pluckedNames []string
|
var pluckedNames []string
|
||||||
for _, performer := range performers {
|
for _, performer := range performers {
|
||||||
if !performer.Name.Valid {
|
if performer.Name == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pluckedNames = append(pluckedNames, performer.Name.String)
|
pluckedNames = append(pluckedNames, performer.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
missingPerformers := stringslice.StrFilter(names, func(name string) bool {
|
missingPerformers := stringslice.StrFilter(names, func(name string) bool {
|
||||||
|
|
@ -176,12 +176,12 @@ func (i *Importer) createPerformers(ctx context.Context, names []string) ([]*mod
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
newPerformer := *models.NewPerformer(name)
|
newPerformer := *models.NewPerformer(name)
|
||||||
|
|
||||||
created, err := i.PerformerWriter.Create(ctx, newPerformer)
|
err := i.PerformerWriter.Create(ctx, &newPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, created)
|
ret = append(ret, &newPerformer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ func TestImporterPreImportWithPerformer(t *testing.T) {
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerName}, false).Return([]*models.Performer{
|
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerName}, false).Return([]*models.Performer{
|
||||||
{
|
{
|
||||||
ID: existingPerformerID,
|
ID: existingPerformerID,
|
||||||
Name: models.NullString(existingPerformerName),
|
Name: existingPerformerName,
|
||||||
},
|
},
|
||||||
}, nil).Once()
|
}, nil).Once()
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerErr}, false).Return(nil, errors.New("FindByNames error")).Once()
|
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerErr}, false).Return(nil, errors.New("FindByNames error")).Once()
|
||||||
|
|
@ -199,9 +199,10 @@ func TestImporterPreImportWithMissingPerformer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Times(3)
|
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Times(3)
|
||||||
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("models.Performer")).Return(&models.Performer{
|
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("*models.Performer")).Run(func(args mock.Arguments) {
|
||||||
ID: existingPerformerID,
|
performer := args.Get(1).(*models.Performer)
|
||||||
}, nil)
|
performer.ID = existingPerformerID
|
||||||
|
}).Return(nil)
|
||||||
|
|
||||||
err := i.PreImport(testCtx)
|
err := i.PreImport(testCtx)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
@ -232,7 +233,7 @@ func TestImporterPreImportWithMissingPerformerCreateErr(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Once()
|
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Once()
|
||||||
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("models.Performer")).Return(nil, errors.New("Create error"))
|
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("*models.Performer")).Return(errors.New("Create error"))
|
||||||
|
|
||||||
err := i.PreImport(testCtx)
|
err := i.PreImport(testCtx)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -216,10 +216,10 @@ func (i *Importer) populatePerformers(ctx context.Context) error {
|
||||||
|
|
||||||
var pluckedNames []string
|
var pluckedNames []string
|
||||||
for _, performer := range performers {
|
for _, performer := range performers {
|
||||||
if !performer.Name.Valid {
|
if performer.Name == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pluckedNames = append(pluckedNames, performer.Name.String)
|
pluckedNames = append(pluckedNames, performer.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
missingPerformers := stringslice.StrFilter(names, func(name string) bool {
|
missingPerformers := stringslice.StrFilter(names, func(name string) bool {
|
||||||
|
|
@ -256,12 +256,12 @@ func (i *Importer) createPerformers(ctx context.Context, names []string) ([]*mod
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
newPerformer := *models.NewPerformer(name)
|
newPerformer := *models.NewPerformer(name)
|
||||||
|
|
||||||
created, err := i.PerformerWriter.Create(ctx, newPerformer)
|
err := i.PerformerWriter.Create(ctx, &newPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, created)
|
ret = append(ret, &newPerformer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ func TestImporterPreImportWithPerformer(t *testing.T) {
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerName}, false).Return([]*models.Performer{
|
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerName}, false).Return([]*models.Performer{
|
||||||
{
|
{
|
||||||
ID: existingPerformerID,
|
ID: existingPerformerID,
|
||||||
Name: models.NullString(existingPerformerName),
|
Name: existingPerformerName,
|
||||||
},
|
},
|
||||||
}, nil).Once()
|
}, nil).Once()
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerErr}, false).Return(nil, errors.New("FindByNames error")).Once()
|
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerErr}, false).Return(nil, errors.New("FindByNames error")).Once()
|
||||||
|
|
@ -160,9 +160,10 @@ func TestImporterPreImportWithMissingPerformer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Times(3)
|
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Times(3)
|
||||||
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("models.Performer")).Return(&models.Performer{
|
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("*models.Performer")).Run(func(args mock.Arguments) {
|
||||||
ID: existingPerformerID,
|
performer := args.Get(1).(*models.Performer)
|
||||||
}, nil)
|
performer.ID = existingPerformerID
|
||||||
|
}).Return(nil)
|
||||||
|
|
||||||
err := i.PreImport(testCtx)
|
err := i.PreImport(testCtx)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
@ -193,7 +194,7 @@ func TestImporterPreImportWithMissingPerformerCreateErr(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Once()
|
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Once()
|
||||||
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("models.Performer")).Return(nil, errors.New("Create error"))
|
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("*models.Performer")).Return(errors.New("Create error"))
|
||||||
|
|
||||||
err := i.PreImport(testCtx)
|
err := i.PreImport(testCtx)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ func PathToPerformers(ctx context.Context, path string, reader PerformerAutoTagQ
|
||||||
var ret []*models.Performer
|
var ret []*models.Performer
|
||||||
for _, p := range performers {
|
for _, p := range performers {
|
||||||
// TODO - commenting out alias handling until both sides work correctly
|
// TODO - commenting out alias handling until both sides work correctly
|
||||||
if nameMatchesPath(p.Name.String, path) != -1 { // || nameMatchesPath(p.Aliases.String, path) {
|
if nameMatchesPath(p.Name, path) != -1 { // || nameMatchesPath(p.Aliases.String, path) {
|
||||||
ret = append(ret, p)
|
ret = append(ret, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,26 +80,17 @@ func (_m *PerformerReaderWriter) CountByTagID(ctx context.Context, tagID int) (i
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create provides a mock function with given fields: ctx, newPerformer
|
// Create provides a mock function with given fields: ctx, newPerformer
|
||||||
func (_m *PerformerReaderWriter) Create(ctx context.Context, newPerformer models.Performer) (*models.Performer, error) {
|
func (_m *PerformerReaderWriter) Create(ctx context.Context, newPerformer *models.Performer) error {
|
||||||
ret := _m.Called(ctx, newPerformer)
|
ret := _m.Called(ctx, newPerformer)
|
||||||
|
|
||||||
var r0 *models.Performer
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, models.Performer) *models.Performer); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *models.Performer) error); ok {
|
||||||
r0 = rf(ctx, newPerformer)
|
r0 = rf(ctx, newPerformer)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
r0 = ret.Error(0)
|
||||||
r0 = ret.Get(0).(*models.Performer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
return r0
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, models.Performer) error); ok {
|
|
||||||
r1 = rf(ctx, newPerformer)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy provides a mock function with given fields: ctx, id
|
// Destroy provides a mock function with given fields: ctx, id
|
||||||
|
|
@ -314,29 +305,6 @@ func (_m *PerformerReaderWriter) FindMany(ctx context.Context, ids []int) ([]*mo
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindNamesBySceneID provides a mock function with given fields: ctx, sceneID
|
|
||||||
func (_m *PerformerReaderWriter) FindNamesBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
|
||||||
ret := _m.Called(ctx, sceneID)
|
|
||||||
|
|
||||||
var r0 []*models.Performer
|
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, int) []*models.Performer); ok {
|
|
||||||
r0 = rf(ctx, sceneID)
|
|
||||||
} else {
|
|
||||||
if ret.Get(0) != nil {
|
|
||||||
r0 = ret.Get(0).([]*models.Performer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var r1 error
|
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, int) error); ok {
|
|
||||||
r1 = rf(ctx, sceneID)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetImage provides a mock function with given fields: ctx, performerID
|
// GetImage provides a mock function with given fields: ctx, performerID
|
||||||
func (_m *PerformerReaderWriter) GetImage(ctx context.Context, performerID int) ([]byte, error) {
|
func (_m *PerformerReaderWriter) GetImage(ctx context.Context, performerID int) ([]byte, error) {
|
||||||
ret := _m.Called(ctx, performerID)
|
ret := _m.Called(ctx, performerID)
|
||||||
|
|
@ -460,49 +428,17 @@ func (_m *PerformerReaderWriter) QueryForAutoTag(ctx context.Context, words []st
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update provides a mock function with given fields: ctx, updatedPerformer
|
// Update provides a mock function with given fields: ctx, updatedPerformer
|
||||||
func (_m *PerformerReaderWriter) Update(ctx context.Context, updatedPerformer models.PerformerPartial) (*models.Performer, error) {
|
func (_m *PerformerReaderWriter) Update(ctx context.Context, updatedPerformer *models.Performer) error {
|
||||||
ret := _m.Called(ctx, updatedPerformer)
|
ret := _m.Called(ctx, updatedPerformer)
|
||||||
|
|
||||||
var r0 *models.Performer
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, models.PerformerPartial) *models.Performer); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, *models.Performer) error); ok {
|
||||||
r0 = rf(ctx, updatedPerformer)
|
r0 = rf(ctx, updatedPerformer)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
r0 = ret.Error(0)
|
||||||
r0 = ret.Get(0).(*models.Performer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
return r0
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, models.PerformerPartial) error); ok {
|
|
||||||
r1 = rf(ctx, updatedPerformer)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFull provides a mock function with given fields: ctx, updatedPerformer
|
|
||||||
func (_m *PerformerReaderWriter) UpdateFull(ctx context.Context, updatedPerformer models.Performer) (*models.Performer, error) {
|
|
||||||
ret := _m.Called(ctx, updatedPerformer)
|
|
||||||
|
|
||||||
var r0 *models.Performer
|
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, models.Performer) *models.Performer); ok {
|
|
||||||
r0 = rf(ctx, updatedPerformer)
|
|
||||||
} else {
|
|
||||||
if ret.Get(0) != nil {
|
|
||||||
r0 = ret.Get(0).(*models.Performer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var r1 error
|
|
||||||
if rf, ok := ret.Get(1).(func(context.Context, models.Performer) error); ok {
|
|
||||||
r1 = rf(ctx, updatedPerformer)
|
|
||||||
} else {
|
|
||||||
r1 = ret.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return r0, r1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateImage provides a mock function with given fields: ctx, performerID, image
|
// UpdateImage provides a mock function with given fields: ctx, performerID, image
|
||||||
|
|
@ -519,6 +455,29 @@ func (_m *PerformerReaderWriter) UpdateImage(ctx context.Context, performerID in
|
||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdatePartial provides a mock function with given fields: ctx, id, updatedPerformer
|
||||||
|
func (_m *PerformerReaderWriter) UpdatePartial(ctx context.Context, id int, updatedPerformer models.PerformerPartial) (*models.Performer, error) {
|
||||||
|
ret := _m.Called(ctx, id, updatedPerformer)
|
||||||
|
|
||||||
|
var r0 *models.Performer
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, int, models.PerformerPartial) *models.Performer); ok {
|
||||||
|
r0 = rf(ctx, id, updatedPerformer)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*models.Performer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, int, models.PerformerPartial) error); ok {
|
||||||
|
r1 = rf(ctx, id, updatedPerformer)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateStashIDs provides a mock function with given fields: ctx, performerID, stashIDs
|
// UpdateStashIDs provides a mock function with given fields: ctx, performerID, stashIDs
|
||||||
func (_m *PerformerReaderWriter) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
|
func (_m *PerformerReaderWriter) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
|
||||||
ret := _m.Called(ctx, performerID, stashIDs)
|
ret := _m.Called(ctx, performerID, stashIDs)
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,87 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/hash/md5"
|
"github.com/stashapp/stash/pkg/hash/md5"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Performer struct {
|
type Performer struct {
|
||||||
ID int `db:"id" json:"id"`
|
ID int `json:"id"`
|
||||||
Checksum string `db:"checksum" json:"checksum"`
|
Checksum string `json:"checksum"`
|
||||||
Name sql.NullString `db:"name" json:"name"`
|
Name string `json:"name"`
|
||||||
Gender sql.NullString `db:"gender" json:"gender"`
|
Gender GenderEnum `json:"gender"`
|
||||||
URL sql.NullString `db:"url" json:"url"`
|
URL string `json:"url"`
|
||||||
Twitter sql.NullString `db:"twitter" json:"twitter"`
|
Twitter string `json:"twitter"`
|
||||||
Instagram sql.NullString `db:"instagram" json:"instagram"`
|
Instagram string `json:"instagram"`
|
||||||
Birthdate SQLiteDate `db:"birthdate" json:"birthdate"`
|
Birthdate *Date `json:"birthdate"`
|
||||||
Ethnicity sql.NullString `db:"ethnicity" json:"ethnicity"`
|
Ethnicity string `json:"ethnicity"`
|
||||||
Country sql.NullString `db:"country" json:"country"`
|
Country string `json:"country"`
|
||||||
EyeColor sql.NullString `db:"eye_color" json:"eye_color"`
|
EyeColor string `json:"eye_color"`
|
||||||
Height sql.NullString `db:"height" json:"height"`
|
Height string `json:"height"`
|
||||||
Measurements sql.NullString `db:"measurements" json:"measurements"`
|
Measurements string `json:"measurements"`
|
||||||
FakeTits sql.NullString `db:"fake_tits" json:"fake_tits"`
|
FakeTits string `json:"fake_tits"`
|
||||||
CareerLength sql.NullString `db:"career_length" json:"career_length"`
|
CareerLength string `json:"career_length"`
|
||||||
Tattoos sql.NullString `db:"tattoos" json:"tattoos"`
|
Tattoos string `json:"tattoos"`
|
||||||
Piercings sql.NullString `db:"piercings" json:"piercings"`
|
Piercings string `json:"piercings"`
|
||||||
Aliases sql.NullString `db:"aliases" json:"aliases"`
|
Aliases string `json:"aliases"`
|
||||||
Favorite sql.NullBool `db:"favorite" json:"favorite"`
|
Favorite bool `json:"favorite"`
|
||||||
CreatedAt SQLiteTimestamp `db:"created_at" json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt SQLiteTimestamp `db:"updated_at" json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
Rating sql.NullInt64 `db:"rating" json:"rating"`
|
Rating *int `json:"rating"`
|
||||||
Details sql.NullString `db:"details" json:"details"`
|
Details string `json:"details"`
|
||||||
DeathDate SQLiteDate `db:"death_date" json:"death_date"`
|
DeathDate *Date `json:"death_date"`
|
||||||
HairColor sql.NullString `db:"hair_color" json:"hair_color"`
|
HairColor string `json:"hair_color"`
|
||||||
Weight sql.NullInt64 `db:"weight" json:"weight"`
|
Weight *int `json:"weight"`
|
||||||
IgnoreAutoTag bool `db:"ignore_auto_tag" json:"ignore_auto_tag"`
|
IgnoreAutoTag bool `json:"ignore_auto_tag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PerformerPartial represents part of a Performer object. It is used to update
|
||||||
|
// the database entry.
|
||||||
type PerformerPartial struct {
|
type PerformerPartial struct {
|
||||||
ID int `db:"id" json:"id"`
|
ID int
|
||||||
Checksum *string `db:"checksum" json:"checksum"`
|
Checksum OptionalString
|
||||||
Name *sql.NullString `db:"name" json:"name"`
|
Name OptionalString
|
||||||
Gender *sql.NullString `db:"gender" json:"gender"`
|
Gender OptionalString
|
||||||
URL *sql.NullString `db:"url" json:"url"`
|
URL OptionalString
|
||||||
Twitter *sql.NullString `db:"twitter" json:"twitter"`
|
Twitter OptionalString
|
||||||
Instagram *sql.NullString `db:"instagram" json:"instagram"`
|
Instagram OptionalString
|
||||||
Birthdate *SQLiteDate `db:"birthdate" json:"birthdate"`
|
Birthdate OptionalDate
|
||||||
Ethnicity *sql.NullString `db:"ethnicity" json:"ethnicity"`
|
Ethnicity OptionalString
|
||||||
Country *sql.NullString `db:"country" json:"country"`
|
Country OptionalString
|
||||||
EyeColor *sql.NullString `db:"eye_color" json:"eye_color"`
|
EyeColor OptionalString
|
||||||
Height *sql.NullString `db:"height" json:"height"`
|
Height OptionalString
|
||||||
Measurements *sql.NullString `db:"measurements" json:"measurements"`
|
Measurements OptionalString
|
||||||
FakeTits *sql.NullString `db:"fake_tits" json:"fake_tits"`
|
FakeTits OptionalString
|
||||||
CareerLength *sql.NullString `db:"career_length" json:"career_length"`
|
CareerLength OptionalString
|
||||||
Tattoos *sql.NullString `db:"tattoos" json:"tattoos"`
|
Tattoos OptionalString
|
||||||
Piercings *sql.NullString `db:"piercings" json:"piercings"`
|
Piercings OptionalString
|
||||||
Aliases *sql.NullString `db:"aliases" json:"aliases"`
|
Aliases OptionalString
|
||||||
Favorite *sql.NullBool `db:"favorite" json:"favorite"`
|
Favorite OptionalBool
|
||||||
CreatedAt *SQLiteTimestamp `db:"created_at" json:"created_at"`
|
CreatedAt OptionalTime
|
||||||
UpdatedAt *SQLiteTimestamp `db:"updated_at" json:"updated_at"`
|
UpdatedAt OptionalTime
|
||||||
Rating *sql.NullInt64 `db:"rating" json:"rating"`
|
Rating OptionalInt
|
||||||
Details *sql.NullString `db:"details" json:"details"`
|
Details OptionalString
|
||||||
DeathDate *SQLiteDate `db:"death_date" json:"death_date"`
|
DeathDate OptionalDate
|
||||||
HairColor *sql.NullString `db:"hair_color" json:"hair_color"`
|
HairColor OptionalString
|
||||||
Weight *sql.NullInt64 `db:"weight" json:"weight"`
|
Weight OptionalInt
|
||||||
IgnoreAutoTag *bool `db:"ignore_auto_tag" json:"ignore_auto_tag"`
|
IgnoreAutoTag OptionalBool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPerformer(name string) *Performer {
|
func NewPerformer(name string) *Performer {
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
return &Performer{
|
return &Performer{
|
||||||
Checksum: md5.FromString(name),
|
Checksum: md5.FromString(name),
|
||||||
Name: sql.NullString{String: name, Valid: true},
|
Name: name,
|
||||||
Favorite: sql.NullBool{Bool: false, Valid: true},
|
CreatedAt: currentTime,
|
||||||
CreatedAt: SQLiteTimestamp{Timestamp: currentTime},
|
UpdatedAt: currentTime,
|
||||||
UpdatedAt: SQLiteTimestamp{Timestamp: currentTime},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPerformerPartial() PerformerPartial {
|
||||||
|
updatedTime := time.Now()
|
||||||
|
return PerformerPartial{
|
||||||
|
UpdatedAt: NewOptionalTime(updatedTime),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,6 @@ type PerformerReader interface {
|
||||||
Find(ctx context.Context, id int) (*Performer, error)
|
Find(ctx context.Context, id int) (*Performer, error)
|
||||||
PerformerFinder
|
PerformerFinder
|
||||||
FindBySceneID(ctx context.Context, sceneID int) ([]*Performer, error)
|
FindBySceneID(ctx context.Context, sceneID int) ([]*Performer, error)
|
||||||
FindNamesBySceneID(ctx context.Context, sceneID int) ([]*Performer, error)
|
|
||||||
FindByImageID(ctx context.Context, imageID int) ([]*Performer, error)
|
FindByImageID(ctx context.Context, imageID int) ([]*Performer, error)
|
||||||
FindByGalleryID(ctx context.Context, galleryID int) ([]*Performer, error)
|
FindByGalleryID(ctx context.Context, galleryID int) ([]*Performer, error)
|
||||||
FindByNames(ctx context.Context, names []string, nocase bool) ([]*Performer, error)
|
FindByNames(ctx context.Context, names []string, nocase bool) ([]*Performer, error)
|
||||||
|
|
@ -152,9 +151,9 @@ type PerformerReader interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PerformerWriter interface {
|
type PerformerWriter interface {
|
||||||
Create(ctx context.Context, newPerformer Performer) (*Performer, error)
|
Create(ctx context.Context, newPerformer *Performer) error
|
||||||
Update(ctx context.Context, updatedPerformer PerformerPartial) (*Performer, error)
|
UpdatePartial(ctx context.Context, id int, updatedPerformer PerformerPartial) (*Performer, error)
|
||||||
UpdateFull(ctx context.Context, updatedPerformer Performer) (*Performer, error)
|
Update(ctx context.Context, updatedPerformer *Performer) error
|
||||||
Destroy(ctx context.Context, id int) error
|
Destroy(ctx context.Context, id int) error
|
||||||
UpdateImage(ctx context.Context, performerID int, image []byte) error
|
UpdateImage(ctx context.Context, performerID int, image []byte) error
|
||||||
DestroyImage(ctx context.Context, performerID int) error
|
DestroyImage(ctx context.Context, performerID int) error
|
||||||
|
|
|
||||||
|
|
@ -18,76 +18,40 @@ type ImageStashIDGetter interface {
|
||||||
// ToJSON converts a Performer object into its JSON equivalent.
|
// ToJSON converts a Performer object into its JSON equivalent.
|
||||||
func ToJSON(ctx context.Context, reader ImageStashIDGetter, performer *models.Performer) (*jsonschema.Performer, error) {
|
func ToJSON(ctx context.Context, reader ImageStashIDGetter, performer *models.Performer) (*jsonschema.Performer, error) {
|
||||||
newPerformerJSON := jsonschema.Performer{
|
newPerformerJSON := jsonschema.Performer{
|
||||||
|
Name: performer.Name,
|
||||||
|
Gender: performer.Gender.String(),
|
||||||
|
URL: performer.URL,
|
||||||
|
Ethnicity: performer.Ethnicity,
|
||||||
|
Country: performer.Country,
|
||||||
|
EyeColor: performer.EyeColor,
|
||||||
|
Height: performer.Height,
|
||||||
|
Measurements: performer.Measurements,
|
||||||
|
FakeTits: performer.FakeTits,
|
||||||
|
CareerLength: performer.CareerLength,
|
||||||
|
Tattoos: performer.Tattoos,
|
||||||
|
Piercings: performer.Piercings,
|
||||||
|
Aliases: performer.Aliases,
|
||||||
|
Twitter: performer.Twitter,
|
||||||
|
Instagram: performer.Instagram,
|
||||||
|
Favorite: performer.Favorite,
|
||||||
|
Details: performer.Details,
|
||||||
|
HairColor: performer.HairColor,
|
||||||
IgnoreAutoTag: performer.IgnoreAutoTag,
|
IgnoreAutoTag: performer.IgnoreAutoTag,
|
||||||
CreatedAt: json.JSONTime{Time: performer.CreatedAt.Timestamp},
|
CreatedAt: json.JSONTime{Time: performer.CreatedAt},
|
||||||
UpdatedAt: json.JSONTime{Time: performer.UpdatedAt.Timestamp},
|
UpdatedAt: json.JSONTime{Time: performer.UpdatedAt},
|
||||||
}
|
}
|
||||||
|
|
||||||
if performer.Name.Valid {
|
if performer.Birthdate != nil {
|
||||||
newPerformerJSON.Name = performer.Name.String
|
newPerformerJSON.Birthdate = performer.Birthdate.String()
|
||||||
}
|
}
|
||||||
if performer.Gender.Valid {
|
if performer.Rating != nil {
|
||||||
newPerformerJSON.Gender = performer.Gender.String
|
newPerformerJSON.Rating = *performer.Rating
|
||||||
}
|
}
|
||||||
if performer.URL.Valid {
|
if performer.DeathDate != nil {
|
||||||
newPerformerJSON.URL = performer.URL.String
|
newPerformerJSON.DeathDate = performer.DeathDate.String()
|
||||||
}
|
}
|
||||||
if performer.Birthdate.Valid {
|
if performer.Weight != nil {
|
||||||
newPerformerJSON.Birthdate = utils.GetYMDFromDatabaseDate(performer.Birthdate.String)
|
newPerformerJSON.Weight = *performer.Weight
|
||||||
}
|
|
||||||
if performer.Ethnicity.Valid {
|
|
||||||
newPerformerJSON.Ethnicity = performer.Ethnicity.String
|
|
||||||
}
|
|
||||||
if performer.Country.Valid {
|
|
||||||
newPerformerJSON.Country = performer.Country.String
|
|
||||||
}
|
|
||||||
if performer.EyeColor.Valid {
|
|
||||||
newPerformerJSON.EyeColor = performer.EyeColor.String
|
|
||||||
}
|
|
||||||
if performer.Height.Valid {
|
|
||||||
newPerformerJSON.Height = performer.Height.String
|
|
||||||
}
|
|
||||||
if performer.Measurements.Valid {
|
|
||||||
newPerformerJSON.Measurements = performer.Measurements.String
|
|
||||||
}
|
|
||||||
if performer.FakeTits.Valid {
|
|
||||||
newPerformerJSON.FakeTits = performer.FakeTits.String
|
|
||||||
}
|
|
||||||
if performer.CareerLength.Valid {
|
|
||||||
newPerformerJSON.CareerLength = performer.CareerLength.String
|
|
||||||
}
|
|
||||||
if performer.Tattoos.Valid {
|
|
||||||
newPerformerJSON.Tattoos = performer.Tattoos.String
|
|
||||||
}
|
|
||||||
if performer.Piercings.Valid {
|
|
||||||
newPerformerJSON.Piercings = performer.Piercings.String
|
|
||||||
}
|
|
||||||
if performer.Aliases.Valid {
|
|
||||||
newPerformerJSON.Aliases = performer.Aliases.String
|
|
||||||
}
|
|
||||||
if performer.Twitter.Valid {
|
|
||||||
newPerformerJSON.Twitter = performer.Twitter.String
|
|
||||||
}
|
|
||||||
if performer.Instagram.Valid {
|
|
||||||
newPerformerJSON.Instagram = performer.Instagram.String
|
|
||||||
}
|
|
||||||
if performer.Favorite.Valid {
|
|
||||||
newPerformerJSON.Favorite = performer.Favorite.Bool
|
|
||||||
}
|
|
||||||
if performer.Rating.Valid {
|
|
||||||
newPerformerJSON.Rating = int(performer.Rating.Int64)
|
|
||||||
}
|
|
||||||
if performer.Details.Valid {
|
|
||||||
newPerformerJSON.Details = performer.Details.String
|
|
||||||
}
|
|
||||||
if performer.DeathDate.Valid {
|
|
||||||
newPerformerJSON.DeathDate = utils.GetYMDFromDatabaseDate(performer.DeathDate.String)
|
|
||||||
}
|
|
||||||
if performer.HairColor.Valid {
|
|
||||||
newPerformerJSON.HairColor = performer.HairColor.String
|
|
||||||
}
|
|
||||||
if performer.Weight.Valid {
|
|
||||||
newPerformerJSON.Weight = int(performer.Weight.Int64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
image, err := reader.GetImage(ctx, performer.ID)
|
image, err := reader.GetImage(ctx, performer.ID)
|
||||||
|
|
@ -126,8 +90,8 @@ func GetIDs(performers []*models.Performer) []int {
|
||||||
func GetNames(performers []*models.Performer) []string {
|
func GetNames(performers []*models.Performer) []string {
|
||||||
var results []string
|
var results []string
|
||||||
for _, performer := range performers {
|
for _, performer := range performers {
|
||||||
if performer.Name.Valid {
|
if performer.Name != "" {
|
||||||
results = append(results, performer.Name.String)
|
results = append(results, performer.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package performer
|
package performer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/hash/md5"
|
"github.com/stashapp/stash/pkg/hash/md5"
|
||||||
|
|
@ -37,13 +36,17 @@ const (
|
||||||
piercings = "piercings"
|
piercings = "piercings"
|
||||||
tattoos = "tattoos"
|
tattoos = "tattoos"
|
||||||
twitter = "twitter"
|
twitter = "twitter"
|
||||||
rating = 5
|
|
||||||
details = "details"
|
details = "details"
|
||||||
hairColor = "hairColor"
|
hairColor = "hairColor"
|
||||||
weight = 60
|
|
||||||
autoTagIgnored = true
|
autoTagIgnored = true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
rating = 5
|
||||||
|
weight = 60
|
||||||
|
)
|
||||||
|
|
||||||
var imageBytes = []byte("imageBytes")
|
var imageBytes = []byte("imageBytes")
|
||||||
|
|
||||||
var stashID = models.StashID{
|
var stashID = models.StashID{
|
||||||
|
|
@ -56,14 +59,8 @@ var stashIDs = []models.StashID{
|
||||||
|
|
||||||
const image = "aW1hZ2VCeXRlcw=="
|
const image = "aW1hZ2VCeXRlcw=="
|
||||||
|
|
||||||
var birthDate = models.SQLiteDate{
|
var birthDate = models.NewDate("2001-01-01")
|
||||||
String: "2001-01-01",
|
var deathDate = models.NewDate("2021-02-02")
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
var deathDate = models.SQLiteDate{
|
|
||||||
String: "2021-02-02",
|
|
||||||
Valid: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
createTime = time.Date(2001, 01, 01, 0, 0, 0, 0, time.Local)
|
createTime = time.Date(2001, 01, 01, 0, 0, 0, 0, time.Local)
|
||||||
|
|
@ -73,41 +70,31 @@ var (
|
||||||
func createFullPerformer(id int, name string) *models.Performer {
|
func createFullPerformer(id int, name string) *models.Performer {
|
||||||
return &models.Performer{
|
return &models.Performer{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: models.NullString(name),
|
Name: name,
|
||||||
Checksum: md5.FromString(name),
|
Checksum: md5.FromString(name),
|
||||||
URL: models.NullString(url),
|
URL: url,
|
||||||
Aliases: models.NullString(aliases),
|
Aliases: aliases,
|
||||||
Birthdate: birthDate,
|
Birthdate: &birthDate,
|
||||||
CareerLength: models.NullString(careerLength),
|
CareerLength: careerLength,
|
||||||
Country: models.NullString(country),
|
Country: country,
|
||||||
Ethnicity: models.NullString(ethnicity),
|
Ethnicity: ethnicity,
|
||||||
EyeColor: models.NullString(eyeColor),
|
EyeColor: eyeColor,
|
||||||
FakeTits: models.NullString(fakeTits),
|
FakeTits: fakeTits,
|
||||||
Favorite: sql.NullBool{
|
Favorite: true,
|
||||||
Bool: true,
|
Gender: gender,
|
||||||
Valid: true,
|
Height: height,
|
||||||
},
|
Instagram: instagram,
|
||||||
Gender: models.NullString(gender),
|
Measurements: measurements,
|
||||||
Height: models.NullString(height),
|
Piercings: piercings,
|
||||||
Instagram: models.NullString(instagram),
|
Tattoos: tattoos,
|
||||||
Measurements: models.NullString(measurements),
|
Twitter: twitter,
|
||||||
Piercings: models.NullString(piercings),
|
CreatedAt: createTime,
|
||||||
Tattoos: models.NullString(tattoos),
|
UpdatedAt: updateTime,
|
||||||
Twitter: models.NullString(twitter),
|
Rating: &rating,
|
||||||
CreatedAt: models.SQLiteTimestamp{
|
Details: details,
|
||||||
Timestamp: createTime,
|
DeathDate: &deathDate,
|
||||||
},
|
HairColor: hairColor,
|
||||||
UpdatedAt: models.SQLiteTimestamp{
|
Weight: &weight,
|
||||||
Timestamp: updateTime,
|
|
||||||
},
|
|
||||||
Rating: models.NullInt64(rating),
|
|
||||||
Details: models.NullString(details),
|
|
||||||
DeathDate: deathDate,
|
|
||||||
HairColor: models.NullString(hairColor),
|
|
||||||
Weight: sql.NullInt64{
|
|
||||||
Int64: weight,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
IgnoreAutoTag: autoTagIgnored,
|
IgnoreAutoTag: autoTagIgnored,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,12 +102,8 @@ func createFullPerformer(id int, name string) *models.Performer {
|
||||||
func createEmptyPerformer(id int) models.Performer {
|
func createEmptyPerformer(id int) models.Performer {
|
||||||
return models.Performer{
|
return models.Performer{
|
||||||
ID: id,
|
ID: id,
|
||||||
CreatedAt: models.SQLiteTimestamp{
|
CreatedAt: createTime,
|
||||||
Timestamp: createTime,
|
UpdatedAt: updateTime,
|
||||||
},
|
|
||||||
UpdatedAt: models.SQLiteTimestamp{
|
|
||||||
Timestamp: updateTime,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +112,7 @@ func createFullJSONPerformer(name string, image string) *jsonschema.Performer {
|
||||||
Name: name,
|
Name: name,
|
||||||
URL: url,
|
URL: url,
|
||||||
Aliases: aliases,
|
Aliases: aliases,
|
||||||
Birthdate: birthDate.String,
|
Birthdate: birthDate.String(),
|
||||||
CareerLength: careerLength,
|
CareerLength: careerLength,
|
||||||
Country: country,
|
Country: country,
|
||||||
Ethnicity: ethnicity,
|
Ethnicity: ethnicity,
|
||||||
|
|
@ -152,7 +135,7 @@ func createFullJSONPerformer(name string, image string) *jsonschema.Performer {
|
||||||
Rating: rating,
|
Rating: rating,
|
||||||
Image: image,
|
Image: image,
|
||||||
Details: details,
|
Details: details,
|
||||||
DeathDate: deathDate.String,
|
DeathDate: deathDate.String(),
|
||||||
HairColor: hairColor,
|
HairColor: hairColor,
|
||||||
Weight: weight,
|
Weight: weight,
|
||||||
StashIDs: []models.StashID{
|
StashIDs: []models.StashID{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package performer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -16,7 +15,7 @@ import (
|
||||||
|
|
||||||
type NameFinderCreatorUpdater interface {
|
type NameFinderCreatorUpdater interface {
|
||||||
NameFinderCreator
|
NameFinderCreator
|
||||||
UpdateFull(ctx context.Context, updatedPerformer models.Performer) (*models.Performer, error)
|
Update(ctx context.Context, updatedPerformer *models.Performer) error
|
||||||
UpdateTags(ctx context.Context, performerID int, tagIDs []int) error
|
UpdateTags(ctx context.Context, performerID int, tagIDs []int) error
|
||||||
UpdateImage(ctx context.Context, performerID int, image []byte) error
|
UpdateImage(ctx context.Context, performerID int, image []byte) error
|
||||||
UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error
|
UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error
|
||||||
|
|
@ -164,19 +163,19 @@ func (i *Importer) FindExistingID(ctx context.Context) (*int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Importer) Create(ctx context.Context) (*int, error) {
|
func (i *Importer) Create(ctx context.Context) (*int, error) {
|
||||||
created, err := i.ReaderWriter.Create(ctx, i.performer)
|
err := i.ReaderWriter.Create(ctx, &i.performer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error creating performer: %v", err)
|
return nil, fmt.Errorf("error creating performer: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
id := created.ID
|
id := i.performer.ID
|
||||||
return &id, nil
|
return &id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Importer) Update(ctx context.Context, id int) error {
|
func (i *Importer) Update(ctx context.Context, id int) error {
|
||||||
performer := i.performer
|
performer := i.performer
|
||||||
performer.ID = id
|
performer.ID = id
|
||||||
_, err := i.ReaderWriter.UpdateFull(ctx, performer)
|
err := i.ReaderWriter.Update(ctx, &performer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error updating existing performer: %v", err)
|
return fmt.Errorf("error updating existing performer: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -188,75 +187,52 @@ func performerJSONToPerformer(performerJSON jsonschema.Performer) models.Perform
|
||||||
checksum := md5.FromString(performerJSON.Name)
|
checksum := md5.FromString(performerJSON.Name)
|
||||||
|
|
||||||
newPerformer := models.Performer{
|
newPerformer := models.Performer{
|
||||||
|
Name: performerJSON.Name,
|
||||||
Checksum: checksum,
|
Checksum: checksum,
|
||||||
Favorite: sql.NullBool{Bool: performerJSON.Favorite, Valid: true},
|
Gender: models.GenderEnum(performerJSON.Gender),
|
||||||
|
URL: performerJSON.URL,
|
||||||
|
Ethnicity: performerJSON.Ethnicity,
|
||||||
|
Country: performerJSON.Country,
|
||||||
|
EyeColor: performerJSON.EyeColor,
|
||||||
|
Height: performerJSON.Height,
|
||||||
|
Measurements: performerJSON.Measurements,
|
||||||
|
FakeTits: performerJSON.FakeTits,
|
||||||
|
CareerLength: performerJSON.CareerLength,
|
||||||
|
Tattoos: performerJSON.Tattoos,
|
||||||
|
Piercings: performerJSON.Piercings,
|
||||||
|
Aliases: performerJSON.Aliases,
|
||||||
|
Twitter: performerJSON.Twitter,
|
||||||
|
Instagram: performerJSON.Instagram,
|
||||||
|
Details: performerJSON.Details,
|
||||||
|
HairColor: performerJSON.HairColor,
|
||||||
|
Favorite: performerJSON.Favorite,
|
||||||
IgnoreAutoTag: performerJSON.IgnoreAutoTag,
|
IgnoreAutoTag: performerJSON.IgnoreAutoTag,
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: performerJSON.CreatedAt.GetTime()},
|
CreatedAt: performerJSON.CreatedAt.GetTime(),
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: performerJSON.UpdatedAt.GetTime()},
|
UpdatedAt: performerJSON.UpdatedAt.GetTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if performerJSON.Name != "" {
|
|
||||||
newPerformer.Name = sql.NullString{String: performerJSON.Name, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Gender != "" {
|
|
||||||
newPerformer.Gender = sql.NullString{String: performerJSON.Gender, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.URL != "" {
|
|
||||||
newPerformer.URL = sql.NullString{String: performerJSON.URL, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Birthdate != "" {
|
if performerJSON.Birthdate != "" {
|
||||||
newPerformer.Birthdate = models.SQLiteDate{String: performerJSON.Birthdate, Valid: true}
|
d, err := utils.ParseDateStringAsTime(performerJSON.Birthdate)
|
||||||
|
if err == nil {
|
||||||
|
newPerformer.Birthdate = &models.Date{
|
||||||
|
Time: d,
|
||||||
}
|
}
|
||||||
if performerJSON.Ethnicity != "" {
|
|
||||||
newPerformer.Ethnicity = sql.NullString{String: performerJSON.Ethnicity, Valid: true}
|
|
||||||
}
|
}
|
||||||
if performerJSON.Country != "" {
|
|
||||||
newPerformer.Country = sql.NullString{String: performerJSON.Country, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.EyeColor != "" {
|
|
||||||
newPerformer.EyeColor = sql.NullString{String: performerJSON.EyeColor, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Height != "" {
|
|
||||||
newPerformer.Height = sql.NullString{String: performerJSON.Height, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Measurements != "" {
|
|
||||||
newPerformer.Measurements = sql.NullString{String: performerJSON.Measurements, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.FakeTits != "" {
|
|
||||||
newPerformer.FakeTits = sql.NullString{String: performerJSON.FakeTits, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.CareerLength != "" {
|
|
||||||
newPerformer.CareerLength = sql.NullString{String: performerJSON.CareerLength, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Tattoos != "" {
|
|
||||||
newPerformer.Tattoos = sql.NullString{String: performerJSON.Tattoos, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Piercings != "" {
|
|
||||||
newPerformer.Piercings = sql.NullString{String: performerJSON.Piercings, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Aliases != "" {
|
|
||||||
newPerformer.Aliases = sql.NullString{String: performerJSON.Aliases, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Twitter != "" {
|
|
||||||
newPerformer.Twitter = sql.NullString{String: performerJSON.Twitter, Valid: true}
|
|
||||||
}
|
|
||||||
if performerJSON.Instagram != "" {
|
|
||||||
newPerformer.Instagram = sql.NullString{String: performerJSON.Instagram, Valid: true}
|
|
||||||
}
|
}
|
||||||
if performerJSON.Rating != 0 {
|
if performerJSON.Rating != 0 {
|
||||||
newPerformer.Rating = sql.NullInt64{Int64: int64(performerJSON.Rating), Valid: true}
|
newPerformer.Rating = &performerJSON.Rating
|
||||||
}
|
|
||||||
if performerJSON.Details != "" {
|
|
||||||
newPerformer.Details = sql.NullString{String: performerJSON.Details, Valid: true}
|
|
||||||
}
|
}
|
||||||
if performerJSON.DeathDate != "" {
|
if performerJSON.DeathDate != "" {
|
||||||
newPerformer.DeathDate = models.SQLiteDate{String: performerJSON.DeathDate, Valid: true}
|
d, err := utils.ParseDateStringAsTime(performerJSON.DeathDate)
|
||||||
|
if err == nil {
|
||||||
|
newPerformer.DeathDate = &models.Date{
|
||||||
|
Time: d,
|
||||||
}
|
}
|
||||||
if performerJSON.HairColor != "" {
|
|
||||||
newPerformer.HairColor = sql.NullString{String: performerJSON.HairColor, Valid: true}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if performerJSON.Weight != 0 {
|
if performerJSON.Weight != 0 {
|
||||||
newPerformer.Weight = sql.NullInt64{Int64: int64(performerJSON.Weight), Valid: true}
|
newPerformer.Weight = &performerJSON.Weight
|
||||||
}
|
}
|
||||||
|
|
||||||
return newPerformer
|
return newPerformer
|
||||||
|
|
|
||||||
|
|
@ -237,11 +237,11 @@ func TestCreate(t *testing.T) {
|
||||||
readerWriter := &mocks.PerformerReaderWriter{}
|
readerWriter := &mocks.PerformerReaderWriter{}
|
||||||
|
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
performerErr := models.Performer{
|
performerErr := models.Performer{
|
||||||
Name: models.NullString(performerNameErr),
|
Name: performerNameErr,
|
||||||
}
|
}
|
||||||
|
|
||||||
i := Importer{
|
i := Importer{
|
||||||
|
|
@ -250,10 +250,11 @@ func TestCreate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
errCreate := errors.New("Create error")
|
errCreate := errors.New("Create error")
|
||||||
readerWriter.On("Create", testCtx, performer).Return(&models.Performer{
|
readerWriter.On("Create", testCtx, &performer).Run(func(args mock.Arguments) {
|
||||||
ID: performerID,
|
arg := args.Get(1).(*models.Performer)
|
||||||
}, nil).Once()
|
arg.ID = performerID
|
||||||
readerWriter.On("Create", testCtx, performerErr).Return(nil, errCreate).Once()
|
}).Return(nil).Once()
|
||||||
|
readerWriter.On("Create", testCtx, &performerErr).Return(errCreate).Once()
|
||||||
|
|
||||||
id, err := i.Create(testCtx)
|
id, err := i.Create(testCtx)
|
||||||
assert.Equal(t, performerID, *id)
|
assert.Equal(t, performerID, *id)
|
||||||
|
|
@ -271,11 +272,11 @@ func TestUpdate(t *testing.T) {
|
||||||
readerWriter := &mocks.PerformerReaderWriter{}
|
readerWriter := &mocks.PerformerReaderWriter{}
|
||||||
|
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
Name: models.NullString(performerName),
|
Name: performerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
performerErr := models.Performer{
|
performerErr := models.Performer{
|
||||||
Name: models.NullString(performerNameErr),
|
Name: performerNameErr,
|
||||||
}
|
}
|
||||||
|
|
||||||
i := Importer{
|
i := Importer{
|
||||||
|
|
@ -287,7 +288,7 @@ func TestUpdate(t *testing.T) {
|
||||||
|
|
||||||
// id needs to be set for the mock input
|
// id needs to be set for the mock input
|
||||||
performer.ID = performerID
|
performer.ID = performerID
|
||||||
readerWriter.On("UpdateFull", testCtx, performer).Return(nil, nil).Once()
|
readerWriter.On("Update", testCtx, &performer).Return(nil).Once()
|
||||||
|
|
||||||
err := i.Update(testCtx, performerID)
|
err := i.Update(testCtx, performerID)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
@ -296,7 +297,7 @@ func TestUpdate(t *testing.T) {
|
||||||
|
|
||||||
// need to set id separately
|
// need to set id separately
|
||||||
performerErr.ID = errImageID
|
performerErr.ID = errImageID
|
||||||
readerWriter.On("UpdateFull", testCtx, performerErr).Return(nil, errUpdate).Once()
|
readerWriter.On("Update", testCtx, &performerErr).Return(errUpdate).Once()
|
||||||
|
|
||||||
err = i.Update(testCtx, errImageID)
|
err = i.Update(testCtx, errImageID)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,5 @@ import (
|
||||||
|
|
||||||
type NameFinderCreator interface {
|
type NameFinderCreator interface {
|
||||||
FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error)
|
FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error)
|
||||||
Create(ctx context.Context, newPerformer models.Performer) (*models.Performer, error)
|
Create(ctx context.Context, newPerformer *models.Performer) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,13 @@ func ValidateDeathDate(performer *models.Performer, birthdate *string, deathDate
|
||||||
}
|
}
|
||||||
|
|
||||||
if performer != nil {
|
if performer != nil {
|
||||||
if birthdate == nil && performer.Birthdate.Valid {
|
if birthdate == nil && performer.Birthdate != nil {
|
||||||
birthdate = &performer.Birthdate.String
|
s := performer.Birthdate.String()
|
||||||
|
birthdate = &s
|
||||||
}
|
}
|
||||||
if deathDate == nil && performer.DeathDate.Valid {
|
if deathDate == nil && performer.DeathDate != nil {
|
||||||
deathDate = &performer.DeathDate.String
|
s := performer.DeathDate.String()
|
||||||
|
deathDate = &s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,26 +16,17 @@ func TestValidateDeathDate(t *testing.T) {
|
||||||
date4 := "2004-01-01"
|
date4 := "2004-01-01"
|
||||||
empty := ""
|
empty := ""
|
||||||
|
|
||||||
|
md2 := models.NewDate(date2)
|
||||||
|
md3 := models.NewDate(date3)
|
||||||
|
|
||||||
emptyPerformer := models.Performer{}
|
emptyPerformer := models.Performer{}
|
||||||
invalidPerformer := models.Performer{
|
invalidPerformer := models.Performer{
|
||||||
Birthdate: models.SQLiteDate{
|
Birthdate: &md3,
|
||||||
String: date3,
|
DeathDate: &md2,
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
DeathDate: models.SQLiteDate{
|
|
||||||
String: date2,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
validPerformer := models.Performer{
|
validPerformer := models.Performer{
|
||||||
Birthdate: models.SQLiteDate{
|
Birthdate: &md2,
|
||||||
String: date2,
|
DeathDate: &md3,
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
DeathDate: models.SQLiteDate{
|
|
||||||
String: date3,
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nil values should always return nil
|
// nil values should always return nil
|
||||||
|
|
|
||||||
|
|
@ -231,10 +231,10 @@ func (i *Importer) populatePerformers(ctx context.Context) error {
|
||||||
|
|
||||||
var pluckedNames []string
|
var pluckedNames []string
|
||||||
for _, performer := range performers {
|
for _, performer := range performers {
|
||||||
if !performer.Name.Valid {
|
if performer.Name == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pluckedNames = append(pluckedNames, performer.Name.String)
|
pluckedNames = append(pluckedNames, performer.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
missingPerformers := stringslice.StrFilter(names, func(name string) bool {
|
missingPerformers := stringslice.StrFilter(names, func(name string) bool {
|
||||||
|
|
@ -271,12 +271,12 @@ func (i *Importer) createPerformers(ctx context.Context, names []string) ([]*mod
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
newPerformer := *models.NewPerformer(name)
|
newPerformer := *models.NewPerformer(name)
|
||||||
|
|
||||||
created, err := i.PerformerWriter.Create(ctx, newPerformer)
|
err := i.PerformerWriter.Create(ctx, &newPerformer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, created)
|
ret = append(ret, &newPerformer)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ func TestImporterPreImportWithPerformer(t *testing.T) {
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerName}, false).Return([]*models.Performer{
|
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerName}, false).Return([]*models.Performer{
|
||||||
{
|
{
|
||||||
ID: existingPerformerID,
|
ID: existingPerformerID,
|
||||||
Name: models.NullString(existingPerformerName),
|
Name: existingPerformerName,
|
||||||
},
|
},
|
||||||
}, nil).Once()
|
}, nil).Once()
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerErr}, false).Return(nil, errors.New("FindByNames error")).Once()
|
performerReaderWriter.On("FindByNames", testCtx, []string{existingPerformerErr}, false).Return(nil, errors.New("FindByNames error")).Once()
|
||||||
|
|
@ -177,9 +177,10 @@ func TestImporterPreImportWithMissingPerformer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Times(3)
|
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Times(3)
|
||||||
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("models.Performer")).Return(&models.Performer{
|
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("*models.Performer")).Run(func(args mock.Arguments) {
|
||||||
ID: existingPerformerID,
|
p := args.Get(1).(*models.Performer)
|
||||||
}, nil)
|
p.ID = existingPerformerID
|
||||||
|
}).Return(nil)
|
||||||
|
|
||||||
err := i.PreImport(testCtx)
|
err := i.PreImport(testCtx)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
@ -210,7 +211,7 @@ func TestImporterPreImportWithMissingPerformerCreateErr(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Once()
|
performerReaderWriter.On("FindByNames", testCtx, []string{missingPerformerName}, false).Return(nil, nil).Once()
|
||||||
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("models.Performer")).Return(nil, errors.New("Create error"))
|
performerReaderWriter.On("Create", testCtx, mock.AnythingOfType("*models.Performer")).Return(errors.New("Create error"))
|
||||||
|
|
||||||
err := i.PreImport(testCtx)
|
err := i.PreImport(testCtx)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,12 @@ func autotagMatchPerformers(ctx context.Context, path string, performerReader ma
|
||||||
id := strconv.Itoa(pp.ID)
|
id := strconv.Itoa(pp.ID)
|
||||||
|
|
||||||
sp := &models.ScrapedPerformer{
|
sp := &models.ScrapedPerformer{
|
||||||
Name: &pp.Name.String,
|
Name: &pp.Name,
|
||||||
StoredID: &id,
|
StoredID: &id,
|
||||||
}
|
}
|
||||||
if pp.Gender.Valid {
|
if pp.Gender.IsValid() {
|
||||||
sp.Gender = &pp.Gender.String
|
v := pp.Gender.String()
|
||||||
|
sp.Gender = &v
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, sp)
|
ret = append(ret, sp)
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,7 @@ func (c Client) FindStashBoxPerformersByNames(ctx context.Context, performerIDs
|
||||||
return fmt.Errorf("performer with id %d not found", performerID)
|
return fmt.Errorf("performer with id %d not found", performerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if performer.Name.Valid {
|
if performer.Name != "" {
|
||||||
performers = append(performers, performer)
|
performers = append(performers, performer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -413,7 +413,7 @@ func (c Client) FindStashBoxPerformersByPerformerNames(ctx context.Context, perf
|
||||||
return fmt.Errorf("performer with id %d not found", performerID)
|
return fmt.Errorf("performer with id %d not found", performerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if performer.Name.Valid {
|
if performer.Name != "" {
|
||||||
performers = append(performers, performer)
|
performers = append(performers, performer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -439,8 +439,8 @@ func (c Client) FindStashBoxPerformersByPerformerNames(ctx context.Context, perf
|
||||||
func (c Client) findStashBoxPerformersByNames(ctx context.Context, performers []*models.Performer) ([]*StashBoxPerformerQueryResult, error) {
|
func (c Client) findStashBoxPerformersByNames(ctx context.Context, performers []*models.Performer) ([]*StashBoxPerformerQueryResult, error) {
|
||||||
var ret []*StashBoxPerformerQueryResult
|
var ret []*StashBoxPerformerQueryResult
|
||||||
for _, performer := range performers {
|
for _, performer := range performers {
|
||||||
if performer.Name.Valid {
|
if performer.Name != "" {
|
||||||
performerResults, err := c.queryStashBoxPerformer(ctx, performer.Name.String)
|
performerResults, err := c.queryStashBoxPerformer(ctx, performer.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -867,7 +867,7 @@ func (c Client) SubmitSceneDraft(ctx context.Context, scene *models.Scene, endpo
|
||||||
performers := []*graphql.DraftEntityInput{}
|
performers := []*graphql.DraftEntityInput{}
|
||||||
for _, p := range scenePerformers {
|
for _, p := range scenePerformers {
|
||||||
performerDraft := graphql.DraftEntityInput{
|
performerDraft := graphql.DraftEntityInput{
|
||||||
Name: p.Name.String,
|
Name: p.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
stashIDs, err := pqb.GetStashIDs(ctx, p.ID)
|
stashIDs, err := pqb.GetStashIDs(ctx, p.ID)
|
||||||
|
|
@ -947,55 +947,57 @@ func (c Client) SubmitPerformerDraft(ctx context.Context, performer *models.Perf
|
||||||
image = bytes.NewReader(img)
|
image = bytes.NewReader(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
if performer.Name.Valid {
|
if performer.Name != "" {
|
||||||
draft.Name = performer.Name.String
|
draft.Name = performer.Name
|
||||||
}
|
}
|
||||||
if performer.Birthdate.Valid {
|
if performer.Birthdate != nil {
|
||||||
draft.Birthdate = &performer.Birthdate.String
|
d := performer.Birthdate.String()
|
||||||
|
draft.Birthdate = &d
|
||||||
}
|
}
|
||||||
if performer.Country.Valid {
|
if performer.Country != "" {
|
||||||
draft.Country = &performer.Country.String
|
draft.Country = &performer.Country
|
||||||
}
|
}
|
||||||
if performer.Ethnicity.Valid {
|
if performer.Ethnicity != "" {
|
||||||
draft.Ethnicity = &performer.Ethnicity.String
|
draft.Ethnicity = &performer.Ethnicity
|
||||||
}
|
}
|
||||||
if performer.EyeColor.Valid {
|
if performer.EyeColor != "" {
|
||||||
draft.EyeColor = &performer.EyeColor.String
|
draft.EyeColor = &performer.EyeColor
|
||||||
}
|
}
|
||||||
if performer.FakeTits.Valid {
|
if performer.FakeTits != "" {
|
||||||
draft.BreastType = &performer.FakeTits.String
|
draft.BreastType = &performer.FakeTits
|
||||||
}
|
}
|
||||||
if performer.Gender.Valid {
|
if performer.Gender.IsValid() {
|
||||||
draft.Gender = &performer.Gender.String
|
v := performer.Gender.String()
|
||||||
|
draft.Gender = &v
|
||||||
}
|
}
|
||||||
if performer.HairColor.Valid {
|
if performer.HairColor != "" {
|
||||||
draft.HairColor = &performer.HairColor.String
|
draft.HairColor = &performer.HairColor
|
||||||
}
|
}
|
||||||
if performer.Height.Valid {
|
if performer.Height != "" {
|
||||||
draft.Height = &performer.Height.String
|
draft.Height = &performer.Height
|
||||||
}
|
}
|
||||||
if performer.Measurements.Valid {
|
if performer.Measurements != "" {
|
||||||
draft.Measurements = &performer.Measurements.String
|
draft.Measurements = &performer.Measurements
|
||||||
}
|
}
|
||||||
if performer.Piercings.Valid {
|
if performer.Piercings != "" {
|
||||||
draft.Piercings = &performer.Piercings.String
|
draft.Piercings = &performer.Piercings
|
||||||
}
|
}
|
||||||
if performer.Tattoos.Valid {
|
if performer.Tattoos != "" {
|
||||||
draft.Tattoos = &performer.Tattoos.String
|
draft.Tattoos = &performer.Tattoos
|
||||||
}
|
}
|
||||||
if performer.Aliases.Valid {
|
if performer.Aliases != "" {
|
||||||
draft.Aliases = &performer.Aliases.String
|
draft.Aliases = &performer.Aliases
|
||||||
}
|
}
|
||||||
|
|
||||||
var urls []string
|
var urls []string
|
||||||
if len(strings.TrimSpace(performer.Twitter.String)) > 0 {
|
if len(strings.TrimSpace(performer.Twitter)) > 0 {
|
||||||
urls = append(urls, "https://twitter.com/"+strings.TrimSpace(performer.Twitter.String))
|
urls = append(urls, "https://twitter.com/"+strings.TrimSpace(performer.Twitter))
|
||||||
}
|
}
|
||||||
if len(strings.TrimSpace(performer.Instagram.String)) > 0 {
|
if len(strings.TrimSpace(performer.Instagram)) > 0 {
|
||||||
urls = append(urls, "https://instagram.com/"+strings.TrimSpace(performer.Instagram.String))
|
urls = append(urls, "https://instagram.com/"+strings.TrimSpace(performer.Instagram))
|
||||||
}
|
}
|
||||||
if len(strings.TrimSpace(performer.URL.String)) > 0 {
|
if len(strings.TrimSpace(performer.URL)) > 0 {
|
||||||
urls = append(urls, strings.TrimSpace(performer.URL.String))
|
urls = append(urls, strings.TrimSpace(performer.URL))
|
||||||
}
|
}
|
||||||
if len(urls) > 0 {
|
if len(urls) > 0 {
|
||||||
draft.Urls = urls
|
draft.Urls = urls
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ type Database struct {
|
||||||
Image *ImageStore
|
Image *ImageStore
|
||||||
Gallery *GalleryStore
|
Gallery *GalleryStore
|
||||||
Scene *SceneStore
|
Scene *SceneStore
|
||||||
|
Performer *PerformerStore
|
||||||
|
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
dbPath string
|
dbPath string
|
||||||
|
|
@ -85,6 +86,7 @@ func NewDatabase() *Database {
|
||||||
Scene: NewSceneStore(fileStore),
|
Scene: NewSceneStore(fileStore),
|
||||||
Image: NewImageStore(fileStore),
|
Image: NewImageStore(fileStore),
|
||||||
Gallery: NewGalleryStore(fileStore, folderStore),
|
Gallery: NewGalleryStore(fileStore, folderStore),
|
||||||
|
Performer: NewPerformerStore(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,17 @@ package sqlite
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/doug-martin/goqu/v9"
|
"github.com/doug-martin/goqu/v9"
|
||||||
|
"github.com/doug-martin/goqu/v9/exp"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"github.com/stashapp/stash/pkg/sliceutil/intslice"
|
"github.com/stashapp/stash/pkg/sliceutil/intslice"
|
||||||
"github.com/stashapp/stash/pkg/utils"
|
"github.com/stashapp/stash/pkg/utils"
|
||||||
|
"gopkg.in/guregu/null.v4"
|
||||||
|
"gopkg.in/guregu/null.v4/zero"
|
||||||
)
|
)
|
||||||
|
|
||||||
const performerTable = "performers"
|
const performerTable = "performers"
|
||||||
|
|
@ -19,82 +21,227 @@ const performerIDColumn = "performer_id"
|
||||||
const performersTagsTable = "performers_tags"
|
const performersTagsTable = "performers_tags"
|
||||||
const performersImageTable = "performers_image" // performer cover image
|
const performersImageTable = "performers_image" // performer cover image
|
||||||
|
|
||||||
var countPerformersForTagQuery = `
|
type performerRow struct {
|
||||||
SELECT tag_id AS id FROM performers_tags
|
ID int `db:"id" goqu:"skipinsert"`
|
||||||
WHERE performers_tags.tag_id = ?
|
Checksum string `db:"checksum"`
|
||||||
GROUP BY performers_tags.performer_id
|
Name zero.String `db:"name"`
|
||||||
`
|
Gender zero.String `db:"gender"`
|
||||||
|
URL zero.String `db:"url"`
|
||||||
type performerQueryBuilder struct {
|
Twitter zero.String `db:"twitter"`
|
||||||
repository
|
Instagram zero.String `db:"instagram"`
|
||||||
|
Birthdate models.SQLiteDate `db:"birthdate"`
|
||||||
|
Ethnicity zero.String `db:"ethnicity"`
|
||||||
|
Country zero.String `db:"country"`
|
||||||
|
EyeColor zero.String `db:"eye_color"`
|
||||||
|
Height zero.String `db:"height"`
|
||||||
|
Measurements zero.String `db:"measurements"`
|
||||||
|
FakeTits zero.String `db:"fake_tits"`
|
||||||
|
CareerLength zero.String `db:"career_length"`
|
||||||
|
Tattoos zero.String `db:"tattoos"`
|
||||||
|
Piercings zero.String `db:"piercings"`
|
||||||
|
Aliases zero.String `db:"aliases"`
|
||||||
|
Favorite sql.NullBool `db:"favorite"`
|
||||||
|
CreatedAt models.SQLiteTimestamp `db:"created_at"`
|
||||||
|
UpdatedAt models.SQLiteTimestamp `db:"updated_at"`
|
||||||
|
Rating null.Int `db:"rating"`
|
||||||
|
Details zero.String `db:"details"`
|
||||||
|
DeathDate models.SQLiteDate `db:"death_date"`
|
||||||
|
HairColor zero.String `db:"hair_color"`
|
||||||
|
Weight null.Int `db:"weight"`
|
||||||
|
IgnoreAutoTag bool `db:"ignore_auto_tag"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var PerformerReaderWriter = &performerQueryBuilder{
|
func (r *performerRow) fromPerformer(o models.Performer) {
|
||||||
repository{
|
r.ID = o.ID
|
||||||
|
r.Checksum = o.Checksum
|
||||||
|
r.Name = zero.StringFrom(o.Name)
|
||||||
|
if o.Gender.IsValid() {
|
||||||
|
r.Gender = zero.StringFrom(o.Gender.String())
|
||||||
|
}
|
||||||
|
r.URL = zero.StringFrom(o.URL)
|
||||||
|
r.Twitter = zero.StringFrom(o.Twitter)
|
||||||
|
r.Instagram = zero.StringFrom(o.Instagram)
|
||||||
|
if o.Birthdate != nil {
|
||||||
|
_ = r.Birthdate.Scan(o.Birthdate.Time)
|
||||||
|
}
|
||||||
|
r.Ethnicity = zero.StringFrom(o.Ethnicity)
|
||||||
|
r.Country = zero.StringFrom(o.Country)
|
||||||
|
r.EyeColor = zero.StringFrom(o.EyeColor)
|
||||||
|
r.Height = zero.StringFrom(o.Height)
|
||||||
|
r.Measurements = zero.StringFrom(o.Measurements)
|
||||||
|
r.FakeTits = zero.StringFrom(o.FakeTits)
|
||||||
|
r.CareerLength = zero.StringFrom(o.CareerLength)
|
||||||
|
r.Tattoos = zero.StringFrom(o.Tattoos)
|
||||||
|
r.Piercings = zero.StringFrom(o.Piercings)
|
||||||
|
r.Aliases = zero.StringFrom(o.Aliases)
|
||||||
|
r.Favorite = sql.NullBool{Bool: o.Favorite, Valid: true}
|
||||||
|
r.CreatedAt = models.SQLiteTimestamp{Timestamp: o.CreatedAt}
|
||||||
|
r.UpdatedAt = models.SQLiteTimestamp{Timestamp: o.UpdatedAt}
|
||||||
|
r.Rating = intFromPtr(o.Rating)
|
||||||
|
r.Details = zero.StringFrom(o.Details)
|
||||||
|
if o.DeathDate != nil {
|
||||||
|
_ = r.DeathDate.Scan(o.DeathDate.Time)
|
||||||
|
}
|
||||||
|
r.HairColor = zero.StringFrom(o.HairColor)
|
||||||
|
r.Weight = intFromPtr(o.Weight)
|
||||||
|
r.IgnoreAutoTag = o.IgnoreAutoTag
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *performerRow) resolve() *models.Performer {
|
||||||
|
ret := &models.Performer{
|
||||||
|
ID: r.ID,
|
||||||
|
Checksum: r.Checksum,
|
||||||
|
Name: r.Name.String,
|
||||||
|
Gender: models.GenderEnum(r.Gender.String),
|
||||||
|
URL: r.URL.String,
|
||||||
|
Twitter: r.Twitter.String,
|
||||||
|
Instagram: r.Instagram.String,
|
||||||
|
Birthdate: r.Birthdate.DatePtr(),
|
||||||
|
Ethnicity: r.Ethnicity.String,
|
||||||
|
Country: r.Country.String,
|
||||||
|
EyeColor: r.EyeColor.String,
|
||||||
|
Height: r.Height.String,
|
||||||
|
Measurements: r.Measurements.String,
|
||||||
|
FakeTits: r.FakeTits.String,
|
||||||
|
CareerLength: r.CareerLength.String,
|
||||||
|
Tattoos: r.Tattoos.String,
|
||||||
|
Piercings: r.Piercings.String,
|
||||||
|
Aliases: r.Aliases.String,
|
||||||
|
Favorite: r.Favorite.Bool,
|
||||||
|
CreatedAt: r.CreatedAt.Timestamp,
|
||||||
|
UpdatedAt: r.UpdatedAt.Timestamp,
|
||||||
|
Rating: nullIntPtr(r.Rating),
|
||||||
|
Details: r.Details.String,
|
||||||
|
DeathDate: r.DeathDate.DatePtr(),
|
||||||
|
HairColor: r.HairColor.String,
|
||||||
|
Weight: nullIntPtr(r.Weight),
|
||||||
|
IgnoreAutoTag: r.IgnoreAutoTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
type performerRowRecord struct {
|
||||||
|
updateRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *performerRowRecord) fromPartial(o models.PerformerPartial) {
|
||||||
|
r.setNullString("checksum", o.Checksum)
|
||||||
|
r.setNullString("name", o.Name)
|
||||||
|
r.setNullString("gender", o.Gender)
|
||||||
|
r.setNullString("url", o.URL)
|
||||||
|
r.setNullString("twitter", o.Twitter)
|
||||||
|
r.setNullString("instagram", o.Instagram)
|
||||||
|
r.setSQLiteDate("birthdate", o.Birthdate)
|
||||||
|
r.setNullString("ethnicity", o.Ethnicity)
|
||||||
|
r.setNullString("country", o.Country)
|
||||||
|
r.setNullString("eye_color", o.EyeColor)
|
||||||
|
r.setNullString("height", o.Height)
|
||||||
|
r.setNullString("measurements", o.Measurements)
|
||||||
|
r.setNullString("fake_tits", o.FakeTits)
|
||||||
|
r.setNullString("career_length", o.CareerLength)
|
||||||
|
r.setNullString("tattoos", o.Tattoos)
|
||||||
|
r.setNullString("piercings", o.Piercings)
|
||||||
|
r.setNullString("aliases", o.Aliases)
|
||||||
|
r.setBool("favorite", o.Favorite)
|
||||||
|
r.setSQLiteTimestamp("created_at", o.CreatedAt)
|
||||||
|
r.setSQLiteTimestamp("updated_at", o.UpdatedAt)
|
||||||
|
r.setNullInt("rating", o.Rating)
|
||||||
|
r.setNullString("details", o.Details)
|
||||||
|
r.setSQLiteDate("death_date", o.DeathDate)
|
||||||
|
r.setNullString("hair_color", o.HairColor)
|
||||||
|
r.setNullInt("weight", o.Weight)
|
||||||
|
r.setBool("ignore_auto_tag", o.IgnoreAutoTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
type PerformerStore struct {
|
||||||
|
repository
|
||||||
|
|
||||||
|
tableMgr *table
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPerformerStore() *PerformerStore {
|
||||||
|
return &PerformerStore{
|
||||||
|
repository: repository{
|
||||||
tableName: performerTable,
|
tableName: performerTable,
|
||||||
idColumn: idColumn,
|
idColumn: idColumn,
|
||||||
},
|
},
|
||||||
|
tableMgr: performerTableMgr,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) Create(ctx context.Context, newObject models.Performer) (*models.Performer, error) {
|
func (qb *PerformerStore) Create(ctx context.Context, newObject *models.Performer) error {
|
||||||
var ret models.Performer
|
var r performerRow
|
||||||
if err := qb.insertObject(ctx, newObject, &ret); err != nil {
|
r.fromPerformer(*newObject)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ret, nil
|
id, err := qb.tableMgr.insertID(ctx, r)
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) Update(ctx context.Context, updatedObject models.PerformerPartial) (*models.Performer, error) {
|
|
||||||
const partial = true
|
|
||||||
if err := qb.update(ctx, updatedObject.ID, updatedObject, partial); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret models.Performer
|
|
||||||
if err := qb.getByID(ctx, updatedObject.ID, &ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) UpdateFull(ctx context.Context, updatedObject models.Performer) (*models.Performer, error) {
|
|
||||||
const partial = false
|
|
||||||
if err := qb.update(ctx, updatedObject.ID, updatedObject, partial); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var ret models.Performer
|
|
||||||
if err := qb.getByID(ctx, updatedObject.ID, &ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) Destroy(ctx context.Context, id int) error {
|
|
||||||
// TODO - add on delete cascade to performers_scenes
|
|
||||||
_, err := qb.tx.Exec(ctx, "DELETE FROM performers_scenes WHERE performer_id = ?", id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updated, err := qb.Find(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("finding after create: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*newObject = *updated
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) UpdatePartial(ctx context.Context, id int, updatedObject models.PerformerPartial) (*models.Performer, error) {
|
||||||
|
r := performerRowRecord{
|
||||||
|
updateRecord{
|
||||||
|
Record: make(exp.Record),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
r.fromPartial(updatedObject)
|
||||||
|
|
||||||
|
if len(r.Record) > 0 {
|
||||||
|
if err := qb.tableMgr.updateByID(ctx, id, r.Record); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return qb.Find(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) Update(ctx context.Context, updatedObject *models.Performer) error {
|
||||||
|
var r performerRow
|
||||||
|
r.fromPerformer(*updatedObject)
|
||||||
|
|
||||||
|
if err := qb.tableMgr.updateByID(ctx, updatedObject.ID, r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) Destroy(ctx context.Context, id int) error {
|
||||||
return qb.destroyExisting(ctx, []int{id})
|
return qb.destroyExisting(ctx, []int{id})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) Find(ctx context.Context, id int) (*models.Performer, error) {
|
func (qb *PerformerStore) table() exp.IdentifierExpression {
|
||||||
var ret models.Performer
|
return qb.tableMgr.table
|
||||||
if err := qb.getByID(ctx, id, &ret); err != nil {
|
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &ret, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*models.Performer, error) {
|
func (qb *PerformerStore) selectDataset() *goqu.SelectDataset {
|
||||||
|
return dialect.From(qb.table()).Select(qb.table().All())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) Find(ctx context.Context, id int) (*models.Performer, error) {
|
||||||
|
q := qb.selectDataset().Where(qb.tableMgr.byID(id))
|
||||||
|
|
||||||
|
ret, err := qb.get(ctx, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting scene by id %d: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) FindMany(ctx context.Context, ids []int) ([]*models.Performer, error) {
|
||||||
tableMgr := performerTableMgr
|
tableMgr := performerTableMgr
|
||||||
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
|
q := goqu.Select("*").From(tableMgr.table).Where(tableMgr.byIDInts(ids...))
|
||||||
unsorted, err := qb.getMany(ctx, q)
|
unsorted, err := qb.getMany(ctx, q)
|
||||||
|
|
@ -118,16 +265,31 @@ func (qb *performerQueryBuilder) FindMany(ctx context.Context, ids []int) ([]*mo
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Performer, error) {
|
func (qb *PerformerStore) get(ctx context.Context, q *goqu.SelectDataset) (*models.Performer, error) {
|
||||||
|
ret, err := qb.getMany(ctx, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ret) == 0 {
|
||||||
|
return nil, sql.ErrNoRows
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) getMany(ctx context.Context, q *goqu.SelectDataset) ([]*models.Performer, error) {
|
||||||
const single = false
|
const single = false
|
||||||
var ret []*models.Performer
|
var ret []*models.Performer
|
||||||
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
if err := queryFunc(ctx, q, single, func(r *sqlx.Rows) error {
|
||||||
var f models.Performer
|
var f performerRow
|
||||||
if err := r.StructScan(&f); err != nil {
|
if err := r.StructScan(&f); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, &f)
|
s := f.resolve()
|
||||||
|
|
||||||
|
ret = append(ret, s)
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -136,95 +298,126 @@ func (qb *performerQueryBuilder) getMany(ctx context.Context, q *goqu.SelectData
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
func (qb *PerformerStore) findBySubquery(ctx context.Context, sq *goqu.SelectDataset) ([]*models.Performer, error) {
|
||||||
query := selectAll("performers") + `
|
table := qb.table()
|
||||||
LEFT JOIN performers_scenes as scenes_join on scenes_join.performer_id = performers.id
|
|
||||||
WHERE scenes_join.scene_id = ?
|
q := qb.selectDataset().Where(
|
||||||
`
|
table.Col(idColumn).Eq(
|
||||||
args := []interface{}{sceneID}
|
sq,
|
||||||
return qb.queryPerformers(ctx, query, args)
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return qb.getMany(ctx, q)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindByImageID(ctx context.Context, imageID int) ([]*models.Performer, error) {
|
func (qb *PerformerStore) FindBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
||||||
query := selectAll("performers") + `
|
sq := dialect.From(scenesPerformersJoinTable).Select(scenesPerformersJoinTable.Col(performerIDColumn)).Where(
|
||||||
LEFT JOIN performers_images as images_join on images_join.performer_id = performers.id
|
scenesPerformersJoinTable.Col(sceneIDColumn).Eq(sceneID),
|
||||||
WHERE images_join.image_id = ?
|
)
|
||||||
`
|
ret, err := qb.findBySubquery(ctx, sq)
|
||||||
args := []interface{}{imageID}
|
|
||||||
return qb.queryPerformers(ctx, query, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindByGalleryID(ctx context.Context, galleryID int) ([]*models.Performer, error) {
|
if err != nil {
|
||||||
query := selectAll("performers") + `
|
return nil, fmt.Errorf("getting performers for scene %d: %w", sceneID, err)
|
||||||
LEFT JOIN performers_galleries as galleries_join on galleries_join.performer_id = performers.id
|
|
||||||
WHERE galleries_join.gallery_id = ?
|
|
||||||
`
|
|
||||||
args := []interface{}{galleryID}
|
|
||||||
return qb.queryPerformers(ctx, query, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindNamesBySceneID(ctx context.Context, sceneID int) ([]*models.Performer, error) {
|
|
||||||
query := `
|
|
||||||
SELECT performers.name FROM performers
|
|
||||||
LEFT JOIN performers_scenes as scenes_join on scenes_join.performer_id = performers.id
|
|
||||||
WHERE scenes_join.scene_id = ?
|
|
||||||
`
|
|
||||||
args := []interface{}{sceneID}
|
|
||||||
return qb.queryPerformers(ctx, query, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error) {
|
|
||||||
query := "SELECT * FROM performers WHERE name"
|
|
||||||
if nocase {
|
|
||||||
query += " COLLATE NOCASE"
|
|
||||||
}
|
}
|
||||||
query += " IN " + getInBinding(len(names))
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) FindByImageID(ctx context.Context, imageID int) ([]*models.Performer, error) {
|
||||||
|
sq := dialect.From(performersImagesJoinTable).Select(performersImagesJoinTable.Col(performerIDColumn)).Where(
|
||||||
|
performersImagesJoinTable.Col(imageIDColumn).Eq(imageID),
|
||||||
|
)
|
||||||
|
ret, err := qb.findBySubquery(ctx, sq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting performers for image %d: %w", imageID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) FindByGalleryID(ctx context.Context, galleryID int) ([]*models.Performer, error) {
|
||||||
|
sq := dialect.From(performersGalleriesJoinTable).Select(performersGalleriesJoinTable.Col(performerIDColumn)).Where(
|
||||||
|
performersGalleriesJoinTable.Col(galleryIDColumn).Eq(galleryID),
|
||||||
|
)
|
||||||
|
ret, err := qb.findBySubquery(ctx, sq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting performers for gallery %d: %w", galleryID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) FindByNames(ctx context.Context, names []string, nocase bool) ([]*models.Performer, error) {
|
||||||
|
clause := "name "
|
||||||
|
if nocase {
|
||||||
|
clause += "COLLATE NOCASE "
|
||||||
|
}
|
||||||
|
clause += "IN " + getInBinding(len(names))
|
||||||
|
|
||||||
var args []interface{}
|
var args []interface{}
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
args = append(args, name)
|
args = append(args, name)
|
||||||
}
|
}
|
||||||
return qb.queryPerformers(ctx, query, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) CountByTagID(ctx context.Context, tagID int) (int, error) {
|
sq := qb.selectDataset().Prepared(true).Where(
|
||||||
args := []interface{}{tagID}
|
goqu.L(clause, args...),
|
||||||
return qb.runCountQuery(ctx, qb.buildCountQuery(countPerformersForTagQuery), args)
|
)
|
||||||
}
|
ret, err := qb.getMany(ctx, sq)
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) Count(ctx context.Context) (int, error) {
|
if err != nil {
|
||||||
return qb.runCountQuery(ctx, qb.buildCountQuery("SELECT performers.id FROM performers"), nil)
|
return nil, fmt.Errorf("getting performers by names: %w", err)
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) All(ctx context.Context) ([]*models.Performer, error) {
|
|
||||||
return qb.queryPerformers(ctx, selectAll("performers")+qb.getPerformerSort(nil), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) QueryForAutoTag(ctx context.Context, words []string) ([]*models.Performer, error) {
|
|
||||||
// TODO - Query needs to be changed to support queries of this type, and
|
|
||||||
// this method should be removed
|
|
||||||
query := selectAll(performerTable)
|
|
||||||
|
|
||||||
var whereClauses []string
|
|
||||||
var args []interface{}
|
|
||||||
|
|
||||||
for _, w := range words {
|
|
||||||
whereClauses = append(whereClauses, "name like ?")
|
|
||||||
args = append(args, w+"%")
|
|
||||||
// TODO - commented out until alias matching works both ways
|
|
||||||
// whereClauses = append(whereClauses, "aliases like ?")
|
|
||||||
// args = append(args, w+"%")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
whereOr := "(" + strings.Join(whereClauses, " OR ") + ")"
|
return ret, nil
|
||||||
where := strings.Join([]string{
|
|
||||||
"ignore_auto_tag = 0",
|
|
||||||
whereOr,
|
|
||||||
}, " AND ")
|
|
||||||
return qb.queryPerformers(ctx, query+" WHERE "+where, args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) validateFilter(filter *models.PerformerFilterType) error {
|
func (qb *PerformerStore) CountByTagID(ctx context.Context, tagID int) (int, error) {
|
||||||
|
joinTable := performersTagsJoinTable
|
||||||
|
|
||||||
|
q := dialect.Select(goqu.COUNT("*")).From(joinTable).Where(joinTable.Col(tagIDColumn).Eq(tagID))
|
||||||
|
return count(ctx, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) Count(ctx context.Context) (int, error) {
|
||||||
|
q := dialect.Select(goqu.COUNT("*")).From(qb.table())
|
||||||
|
return count(ctx, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) All(ctx context.Context) ([]*models.Performer, error) {
|
||||||
|
return qb.getMany(ctx, qb.selectDataset())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) QueryForAutoTag(ctx context.Context, words []string) ([]*models.Performer, error) {
|
||||||
|
// TODO - Query needs to be changed to support queries of this type, and
|
||||||
|
// this method should be removed
|
||||||
|
table := qb.table()
|
||||||
|
sq := dialect.From(table).Select(table.Col(idColumn)).Where()
|
||||||
|
|
||||||
|
var whereClauses []exp.Expression
|
||||||
|
|
||||||
|
for _, w := range words {
|
||||||
|
whereClauses = append(whereClauses, table.Col("name").Like(w+"%"))
|
||||||
|
// TODO - commented out until alias matching works both ways
|
||||||
|
// whereClauses = append(whereClauses, table.Col("aliases").Like(w+"%")
|
||||||
|
}
|
||||||
|
|
||||||
|
sq = sq.Where(
|
||||||
|
goqu.Or(whereClauses...),
|
||||||
|
table.Col("ignore_auto_tag").Eq(0),
|
||||||
|
)
|
||||||
|
|
||||||
|
ret, err := qb.findBySubquery(ctx, sq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting performers for autotag: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) validateFilter(filter *models.PerformerFilterType) error {
|
||||||
const and = "AND"
|
const and = "AND"
|
||||||
const or = "OR"
|
const or = "OR"
|
||||||
const not = "NOT"
|
const not = "NOT"
|
||||||
|
|
@ -255,7 +448,7 @@ func (qb *performerQueryBuilder) validateFilter(filter *models.PerformerFilterTy
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) makeFilter(ctx context.Context, filter *models.PerformerFilterType) *filterBuilder {
|
func (qb *PerformerStore) makeFilter(ctx context.Context, filter *models.PerformerFilterType) *filterBuilder {
|
||||||
query := &filterBuilder{}
|
query := &filterBuilder{}
|
||||||
|
|
||||||
if filter.And != nil {
|
if filter.And != nil {
|
||||||
|
|
@ -322,7 +515,7 @@ func (qb *performerQueryBuilder) makeFilter(ctx context.Context, filter *models.
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) Query(ctx context.Context, performerFilter *models.PerformerFilterType, findFilter *models.FindFilterType) ([]*models.Performer, int, error) {
|
func (qb *PerformerStore) Query(ctx context.Context, performerFilter *models.PerformerFilterType, findFilter *models.FindFilterType) ([]*models.Performer, int, error) {
|
||||||
if performerFilter == nil {
|
if performerFilter == nil {
|
||||||
performerFilter = &models.PerformerFilterType{}
|
performerFilter = &models.PerformerFilterType{}
|
||||||
}
|
}
|
||||||
|
|
@ -359,7 +552,7 @@ func (qb *performerQueryBuilder) Query(ctx context.Context, performerFilter *mod
|
||||||
return performers, countResult, nil
|
return performers, countResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerIsMissingCriterionHandler(qb *performerQueryBuilder, isMissing *string) criterionHandlerFunc {
|
func performerIsMissingCriterionHandler(qb *PerformerStore, isMissing *string) criterionHandlerFunc {
|
||||||
return func(ctx context.Context, f *filterBuilder) {
|
return func(ctx context.Context, f *filterBuilder) {
|
||||||
if isMissing != nil && *isMissing != "" {
|
if isMissing != nil && *isMissing != "" {
|
||||||
switch *isMissing {
|
switch *isMissing {
|
||||||
|
|
@ -400,7 +593,7 @@ func performerAgeFilterCriterionHandler(age *models.IntCriterionInput) criterion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerTagsCriterionHandler(qb *performerQueryBuilder, tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
func performerTagsCriterionHandler(qb *PerformerStore, tags *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||||
h := joinedHierarchicalMultiCriterionHandlerBuilder{
|
h := joinedHierarchicalMultiCriterionHandlerBuilder{
|
||||||
tx: qb.tx,
|
tx: qb.tx,
|
||||||
|
|
||||||
|
|
@ -417,7 +610,7 @@ func performerTagsCriterionHandler(qb *performerQueryBuilder, tags *models.Hiera
|
||||||
return h.handler(tags)
|
return h.handler(tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerTagCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
func performerTagCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||||
h := countCriterionHandlerBuilder{
|
h := countCriterionHandlerBuilder{
|
||||||
primaryTable: performerTable,
|
primaryTable: performerTable,
|
||||||
joinTable: performersTagsTable,
|
joinTable: performersTagsTable,
|
||||||
|
|
@ -427,7 +620,7 @@ func performerTagCountCriterionHandler(qb *performerQueryBuilder, count *models.
|
||||||
return h.handler(count)
|
return h.handler(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerSceneCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
func performerSceneCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||||
h := countCriterionHandlerBuilder{
|
h := countCriterionHandlerBuilder{
|
||||||
primaryTable: performerTable,
|
primaryTable: performerTable,
|
||||||
joinTable: performersScenesTable,
|
joinTable: performersScenesTable,
|
||||||
|
|
@ -437,7 +630,7 @@ func performerSceneCountCriterionHandler(qb *performerQueryBuilder, count *model
|
||||||
return h.handler(count)
|
return h.handler(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerImageCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
func performerImageCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||||
h := countCriterionHandlerBuilder{
|
h := countCriterionHandlerBuilder{
|
||||||
primaryTable: performerTable,
|
primaryTable: performerTable,
|
||||||
joinTable: performersImagesTable,
|
joinTable: performersImagesTable,
|
||||||
|
|
@ -447,7 +640,7 @@ func performerImageCountCriterionHandler(qb *performerQueryBuilder, count *model
|
||||||
return h.handler(count)
|
return h.handler(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerGalleryCountCriterionHandler(qb *performerQueryBuilder, count *models.IntCriterionInput) criterionHandlerFunc {
|
func performerGalleryCountCriterionHandler(qb *PerformerStore, count *models.IntCriterionInput) criterionHandlerFunc {
|
||||||
h := countCriterionHandlerBuilder{
|
h := countCriterionHandlerBuilder{
|
||||||
primaryTable: performerTable,
|
primaryTable: performerTable,
|
||||||
joinTable: performersGalleriesTable,
|
joinTable: performersGalleriesTable,
|
||||||
|
|
@ -457,7 +650,7 @@ func performerGalleryCountCriterionHandler(qb *performerQueryBuilder, count *mod
|
||||||
return h.handler(count)
|
return h.handler(count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func performerStudiosCriterionHandler(qb *performerQueryBuilder, studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
func performerStudiosCriterionHandler(qb *PerformerStore, studios *models.HierarchicalMultiCriterionInput) criterionHandlerFunc {
|
||||||
return func(ctx context.Context, f *filterBuilder) {
|
return func(ctx context.Context, f *filterBuilder) {
|
||||||
if studios != nil {
|
if studios != nil {
|
||||||
formatMaps := []utils.StrFormatMap{
|
formatMaps := []utils.StrFormatMap{
|
||||||
|
|
@ -534,7 +727,7 @@ func performerStudiosCriterionHandler(qb *performerQueryBuilder, studios *models
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) getPerformerSort(findFilter *models.FindFilterType) string {
|
func (qb *PerformerStore) getPerformerSort(findFilter *models.FindFilterType) string {
|
||||||
var sort string
|
var sort string
|
||||||
var direction string
|
var direction string
|
||||||
if findFilter == nil {
|
if findFilter == nil {
|
||||||
|
|
@ -561,16 +754,7 @@ func (qb *performerQueryBuilder) getPerformerSort(findFilter *models.FindFilterT
|
||||||
return getSort(sort, direction, "performers")
|
return getSort(sort, direction, "performers")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) queryPerformers(ctx context.Context, query string, args []interface{}) ([]*models.Performer, error) {
|
func (qb *PerformerStore) tagsRepository() *joinRepository {
|
||||||
var ret models.Performers
|
|
||||||
if err := qb.query(ctx, query, args, &ret); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return []*models.Performer(ret), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) tagsRepository() *joinRepository {
|
|
||||||
return &joinRepository{
|
return &joinRepository{
|
||||||
repository: repository{
|
repository: repository{
|
||||||
tx: qb.tx,
|
tx: qb.tx,
|
||||||
|
|
@ -581,16 +765,16 @@ func (qb *performerQueryBuilder) tagsRepository() *joinRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) GetTagIDs(ctx context.Context, id int) ([]int, error) {
|
func (qb *PerformerStore) GetTagIDs(ctx context.Context, id int) ([]int, error) {
|
||||||
return qb.tagsRepository().getIDs(ctx, id)
|
return qb.tagsRepository().getIDs(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) UpdateTags(ctx context.Context, id int, tagIDs []int) error {
|
func (qb *PerformerStore) UpdateTags(ctx context.Context, id int, tagIDs []int) error {
|
||||||
// Delete the existing joins and then create new ones
|
// Delete the existing joins and then create new ones
|
||||||
return qb.tagsRepository().replace(ctx, id, tagIDs)
|
return qb.tagsRepository().replace(ctx, id, tagIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) imageRepository() *imageRepository {
|
func (qb *PerformerStore) imageRepository() *imageRepository {
|
||||||
return &imageRepository{
|
return &imageRepository{
|
||||||
repository: repository{
|
repository: repository{
|
||||||
tx: qb.tx,
|
tx: qb.tx,
|
||||||
|
|
@ -601,19 +785,19 @@ func (qb *performerQueryBuilder) imageRepository() *imageRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) GetImage(ctx context.Context, performerID int) ([]byte, error) {
|
func (qb *PerformerStore) GetImage(ctx context.Context, performerID int) ([]byte, error) {
|
||||||
return qb.imageRepository().get(ctx, performerID)
|
return qb.imageRepository().get(ctx, performerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) UpdateImage(ctx context.Context, performerID int, image []byte) error {
|
func (qb *PerformerStore) UpdateImage(ctx context.Context, performerID int, image []byte) error {
|
||||||
return qb.imageRepository().replace(ctx, performerID, image)
|
return qb.imageRepository().replace(ctx, performerID, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) DestroyImage(ctx context.Context, performerID int) error {
|
func (qb *PerformerStore) DestroyImage(ctx context.Context, performerID int) error {
|
||||||
return qb.imageRepository().destroy(ctx, []int{performerID})
|
return qb.imageRepository().destroy(ctx, []int{performerID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) stashIDRepository() *stashIDRepository {
|
func (qb *PerformerStore) stashIDRepository() *stashIDRepository {
|
||||||
return &stashIDRepository{
|
return &stashIDRepository{
|
||||||
repository{
|
repository{
|
||||||
tx: qb.tx,
|
tx: qb.tx,
|
||||||
|
|
@ -623,40 +807,51 @@ func (qb *performerQueryBuilder) stashIDRepository() *stashIDRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) GetStashIDs(ctx context.Context, performerID int) ([]models.StashID, error) {
|
func (qb *PerformerStore) GetStashIDs(ctx context.Context, performerID int) ([]models.StashID, error) {
|
||||||
return qb.stashIDRepository().get(ctx, performerID)
|
return qb.stashIDRepository().get(ctx, performerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
|
func (qb *PerformerStore) UpdateStashIDs(ctx context.Context, performerID int, stashIDs []models.StashID) error {
|
||||||
return qb.stashIDRepository().replace(ctx, performerID, stashIDs)
|
return qb.stashIDRepository().replace(ctx, performerID, stashIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindByStashID(ctx context.Context, stashID models.StashID) ([]*models.Performer, error) {
|
func (qb *PerformerStore) FindByStashID(ctx context.Context, stashID models.StashID) ([]*models.Performer, error) {
|
||||||
query := selectAll("performers") + `
|
sq := dialect.From(performersStashIDsJoinTable).Select(performersStashIDsJoinTable.Col(performerIDColumn)).Where(
|
||||||
LEFT JOIN performer_stash_ids on performer_stash_ids.performer_id = performers.id
|
performersStashIDsJoinTable.Col("stash_id").Eq(stashID.StashID),
|
||||||
WHERE performer_stash_ids.stash_id = ?
|
performersStashIDsJoinTable.Col("endpoint").Eq(stashID.Endpoint),
|
||||||
AND performer_stash_ids.endpoint = ?
|
)
|
||||||
`
|
ret, err := qb.findBySubquery(ctx, sq)
|
||||||
args := []interface{}{stashID.StashID, stashID.Endpoint}
|
|
||||||
return qb.queryPerformers(ctx, query, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (qb *performerQueryBuilder) FindByStashIDStatus(ctx context.Context, hasStashID bool, stashboxEndpoint string) ([]*models.Performer, error) {
|
if err != nil {
|
||||||
query := selectAll("performers") + `
|
return nil, fmt.Errorf("getting performers for stash ID %s: %w", stashID.StashID, err)
|
||||||
LEFT JOIN performer_stash_ids on performer_stash_ids.performer_id = performers.id
|
|
||||||
`
|
|
||||||
|
|
||||||
if hasStashID {
|
|
||||||
query += `
|
|
||||||
WHERE performer_stash_ids.stash_id IS NOT NULL
|
|
||||||
AND performer_stash_ids.endpoint = ?
|
|
||||||
`
|
|
||||||
} else {
|
|
||||||
query += `
|
|
||||||
WHERE performer_stash_ids.stash_id IS NULL
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
args := []interface{}{stashboxEndpoint}
|
return ret, nil
|
||||||
return qb.queryPerformers(ctx, query, args)
|
}
|
||||||
|
|
||||||
|
func (qb *PerformerStore) FindByStashIDStatus(ctx context.Context, hasStashID bool, stashboxEndpoint string) ([]*models.Performer, error) {
|
||||||
|
table := qb.table()
|
||||||
|
sq := dialect.From(table).LeftJoin(
|
||||||
|
performersStashIDsJoinTable,
|
||||||
|
goqu.On(table.Col(idColumn).Eq(performersStashIDsJoinTable.Col(performerIDColumn))),
|
||||||
|
).Select(table.Col(idColumn))
|
||||||
|
|
||||||
|
if hasStashID {
|
||||||
|
sq = sq.Where(
|
||||||
|
performersStashIDsJoinTable.Col("stash_id").IsNotNull(),
|
||||||
|
performersStashIDsJoinTable.Col("endpoint").Eq(stashboxEndpoint),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
sq = sq.Where(
|
||||||
|
performersStashIDsJoinTable.Col("stash_id").IsNull(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := qb.findBySubquery(ctx, sq)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting performers for stash-box endpoint %s: %w", stashboxEndpoint, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -317,12 +317,6 @@ func (qb *SceneStore) Update(ctx context.Context, updatedObject *models.Scene) e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (qb *SceneStore) Destroy(ctx context.Context, id int) error {
|
func (qb *SceneStore) Destroy(ctx context.Context, id int) error {
|
||||||
// delete all related table rows
|
|
||||||
// TODO - this should be handled by a delete cascade
|
|
||||||
if err := qb.performersRepository().destroy(ctx, []int{id}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// scene markers should be handled prior to calling destroy
|
// scene markers should be handled prior to calling destroy
|
||||||
// galleries should be handled prior to calling destroy
|
// galleries should be handled prior to calling destroy
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,7 @@ func populateDB() error {
|
||||||
return fmt.Errorf("error creating movies: %s", err.Error())
|
return fmt.Errorf("error creating movies: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createPerformers(ctx, sqlite.PerformerReaderWriter, performersNameCase, performersNameNoCase); err != nil {
|
if err := createPerformers(ctx, performersNameCase, performersNameNoCase); err != nil {
|
||||||
return fmt.Errorf("error creating performers: %s", err.Error())
|
return fmt.Errorf("error creating performers: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,7 +584,7 @@ func populateDB() error {
|
||||||
return fmt.Errorf("error creating saved filters: %s", err.Error())
|
return fmt.Errorf("error creating saved filters: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := linkPerformerTags(ctx, sqlite.PerformerReaderWriter); err != nil {
|
if err := linkPerformerTags(ctx); err != nil {
|
||||||
return fmt.Errorf("error linking performer tags: %s", err.Error())
|
return fmt.Errorf("error linking performer tags: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1226,8 +1226,10 @@ func getPerformerStringValue(index int, field string) string {
|
||||||
return getPrefixedStringValue("performer", index, field)
|
return getPrefixedStringValue("performer", index, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPerformerNullStringValue(index int, field string) sql.NullString {
|
func getPerformerNullStringValue(index int, field string) string {
|
||||||
return getPrefixedNullStringValue("performer", index, field)
|
ret := getPrefixedNullStringValue("performer", index, field)
|
||||||
|
|
||||||
|
return ret.String
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPerformerBoolValue(index int) bool {
|
func getPerformerBoolValue(index int) bool {
|
||||||
|
|
@ -1235,24 +1237,29 @@ func getPerformerBoolValue(index int) bool {
|
||||||
return index == 1
|
return index == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPerformerBirthdate(index int) string {
|
func getPerformerBirthdate(index int) *models.Date {
|
||||||
const minAge = 18
|
const minAge = 18
|
||||||
birthdate := time.Now()
|
birthdate := time.Now()
|
||||||
birthdate = birthdate.AddDate(-minAge-index, -1, -1)
|
birthdate = birthdate.AddDate(-minAge-index, -1, -1)
|
||||||
return birthdate.Format("2006-01-02")
|
|
||||||
|
ret := models.Date{
|
||||||
|
Time: birthdate,
|
||||||
|
}
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPerformerDeathDate(index int) models.SQLiteDate {
|
func getPerformerDeathDate(index int) *models.Date {
|
||||||
if index != 5 {
|
if index != 5 {
|
||||||
return models.SQLiteDate{}
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
deathDate := time.Now()
|
deathDate := time.Now()
|
||||||
deathDate = deathDate.AddDate(-index+1, -1, -1)
|
deathDate = deathDate.AddDate(-index+1, -1, -1)
|
||||||
return models.SQLiteDate{
|
|
||||||
String: deathDate.Format("2006-01-02"),
|
ret := models.Date{
|
||||||
Valid: true,
|
Time: deathDate,
|
||||||
}
|
}
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPerformerCareerLength(index int) *string {
|
func getPerformerCareerLength(index int) *string {
|
||||||
|
|
@ -1268,8 +1275,17 @@ func getIgnoreAutoTag(index int) bool {
|
||||||
return index%5 == 0
|
return index%5 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func performerStashID(i int) models.StashID {
|
||||||
|
return models.StashID{
|
||||||
|
StashID: getPerformerStringValue(i, "stashid"),
|
||||||
|
Endpoint: getPerformerStringValue(i, "endpoint"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// createPerformers creates n performers with plain Name and o performers with camel cased NaMe included
|
// createPerformers creates n performers with plain Name and o performers with camel cased NaMe included
|
||||||
func createPerformers(ctx context.Context, pqb models.PerformerReaderWriter, n int, o int) error {
|
func createPerformers(ctx context.Context, n int, o int) error {
|
||||||
|
pqb := db.Performer
|
||||||
|
|
||||||
const namePlain = "Name"
|
const namePlain = "Name"
|
||||||
const nameNoCase = "NaMe"
|
const nameNoCase = "NaMe"
|
||||||
|
|
||||||
|
|
@ -1285,34 +1301,39 @@ func createPerformers(ctx context.Context, pqb models.PerformerReaderWriter, n i
|
||||||
// performers [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
// performers [ i ] and [ n + o - i - 1 ] should have similar names with only the Name!=NaMe part different
|
||||||
|
|
||||||
performer := models.Performer{
|
performer := models.Performer{
|
||||||
Name: sql.NullString{String: getPerformerStringValue(index, name), Valid: true},
|
Name: getPerformerStringValue(index, name),
|
||||||
Checksum: getPerformerStringValue(i, checksumField),
|
Checksum: getPerformerStringValue(i, checksumField),
|
||||||
URL: getPerformerNullStringValue(i, urlField),
|
URL: getPerformerNullStringValue(i, urlField),
|
||||||
Favorite: sql.NullBool{Bool: getPerformerBoolValue(i), Valid: true},
|
Favorite: getPerformerBoolValue(i),
|
||||||
Birthdate: models.SQLiteDate{
|
Birthdate: getPerformerBirthdate(i),
|
||||||
String: getPerformerBirthdate(i),
|
|
||||||
Valid: true,
|
|
||||||
},
|
|
||||||
DeathDate: getPerformerDeathDate(i),
|
DeathDate: getPerformerDeathDate(i),
|
||||||
Details: sql.NullString{String: getPerformerStringValue(i, "Details"), Valid: true},
|
Details: getPerformerStringValue(i, "Details"),
|
||||||
Ethnicity: sql.NullString{String: getPerformerStringValue(i, "Ethnicity"), Valid: true},
|
Ethnicity: getPerformerStringValue(i, "Ethnicity"),
|
||||||
Rating: getRating(i),
|
Rating: getIntPtr(getRating(i)),
|
||||||
IgnoreAutoTag: getIgnoreAutoTag(i),
|
IgnoreAutoTag: getIgnoreAutoTag(i),
|
||||||
}
|
}
|
||||||
|
|
||||||
careerLength := getPerformerCareerLength(i)
|
careerLength := getPerformerCareerLength(i)
|
||||||
if careerLength != nil {
|
if careerLength != nil {
|
||||||
performer.CareerLength = models.NullString(*careerLength)
|
performer.CareerLength = *careerLength
|
||||||
}
|
}
|
||||||
|
|
||||||
created, err := pqb.Create(ctx, performer)
|
err := pqb.Create(ctx, &performer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Error creating performer %v+: %s", performer, err.Error())
|
return fmt.Errorf("Error creating performer %v+: %s", performer, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
performerIDs = append(performerIDs, created.ID)
|
if (index+1)%5 != 0 {
|
||||||
performerNames = append(performerNames, created.Name.String)
|
if err := pqb.UpdateStashIDs(ctx, performer.ID, []models.StashID{
|
||||||
|
performerStashID(i),
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("setting performer stash ids: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
performerIDs = append(performerIDs, performer.ID)
|
||||||
|
performerNames = append(performerNames, performer.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1581,7 +1602,8 @@ func doLinks(links [][2]int, fn func(idx1, idx2 int) error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func linkPerformerTags(ctx context.Context, qb models.PerformerReaderWriter) error {
|
func linkPerformerTags(ctx context.Context) error {
|
||||||
|
qb := db.Performer
|
||||||
return doLinks(performerTagLinks, func(performerIndex, tagIndex int) error {
|
return doLinks(performerTagLinks, func(performerIndex, tagIndex int) error {
|
||||||
performerID := performerIDs[performerIndex]
|
performerID := performerIDs[performerIndex]
|
||||||
tagID := tagIDs[tagIndex]
|
tagID := tagIDs[tagIndex]
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ var (
|
||||||
scenesPerformersJoinTable = goqu.T(performersScenesTable)
|
scenesPerformersJoinTable = goqu.T(performersScenesTable)
|
||||||
scenesStashIDsJoinTable = goqu.T("scene_stash_ids")
|
scenesStashIDsJoinTable = goqu.T("scene_stash_ids")
|
||||||
scenesMoviesJoinTable = goqu.T(moviesScenesTable)
|
scenesMoviesJoinTable = goqu.T(moviesScenesTable)
|
||||||
|
|
||||||
|
performersTagsJoinTable = goqu.T(performersTagsTable)
|
||||||
|
performersStashIDsJoinTable = goqu.T("performer_stash_ids")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -1011,7 +1011,7 @@ func TestTagMerge(t *testing.T) {
|
||||||
assert.Contains(g.TagIDs.List(), destID)
|
assert.Contains(g.TagIDs.List(), destID)
|
||||||
|
|
||||||
// ensure performer points to new tag
|
// ensure performer points to new tag
|
||||||
performerTagIDs, err := sqlite.PerformerReaderWriter.GetTagIDs(ctx, performerIDs[performerIdxWithTwoTags])
|
performerTagIDs, err := db.Performer.GetTagIDs(ctx, performerIDs[performerIdxWithTwoTags])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ func (db *Database) TxnRepository() models.Repository {
|
||||||
Gallery: db.Gallery,
|
Gallery: db.Gallery,
|
||||||
Image: db.Image,
|
Image: db.Image,
|
||||||
Movie: MovieReaderWriter,
|
Movie: MovieReaderWriter,
|
||||||
Performer: PerformerReaderWriter,
|
Performer: db.Performer,
|
||||||
Scene: db.Scene,
|
Scene: db.Scene,
|
||||||
SceneMarker: SceneMarkerReaderWriter,
|
SceneMarker: SceneMarkerReaderWriter,
|
||||||
ScrapedItem: ScrapedItemReaderWriter,
|
ScrapedItem: ScrapedItemReaderWriter,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue