diff --git a/graphql/documents/mutations/gallery.graphql b/graphql/documents/mutations/gallery.graphql index 8cb5f82b8..04565504e 100644 --- a/graphql/documents/mutations/gallery.graphql +++ b/graphql/documents/mutations/gallery.graphql @@ -25,55 +25,17 @@ mutation GalleryCreate( } mutation GalleryUpdate( - $id: ID!, - $title: String, - $details: String, - $url: String, - $date: String, - $rating: Int, - $scene_id: ID, - $studio_id: ID, - $performer_ids: [ID!] = [], - $tag_ids: [ID!] = []) { + $input: GalleryUpdateInput!) { - galleryUpdate(input: { - id: $id, - title: $title, - details: $details, - url: $url, - date: $date, - rating: $rating, - scene_id: $scene_id, - studio_id: $studio_id, - tag_ids: $tag_ids, - performer_ids: $performer_ids - }) { + galleryUpdate(input: $input) { ...GalleryData } } mutation BulkGalleryUpdate( - $ids: [ID!] = [], - $url: String, - $date: String, - $details: String, - $rating: Int, - $scene_id: ID, - $studio_id: ID, - $tag_ids: BulkUpdateIds, - $performer_ids: BulkUpdateIds) { + $input: BulkGalleryUpdateInput!) { - bulkGalleryUpdate(input: { - ids: $ids, - details: $details, - url: $url, - date: $date, - rating: $rating, - scene_id: $scene_id, - studio_id: $studio_id, - tag_ids: $tag_ids, - performer_ids: $performer_ids - }) { + bulkGalleryUpdate(input: $input) { ...GalleryData } } diff --git a/graphql/documents/mutations/image.graphql b/graphql/documents/mutations/image.graphql index 963c33f5c..26777e833 100644 --- a/graphql/documents/mutations/image.graphql +++ b/graphql/documents/mutations/image.graphql @@ -1,43 +1,15 @@ mutation ImageUpdate( - $id: ID!, - $title: String, - $rating: Int, - $studio_id: ID, - $gallery_ids: [ID!] = [], - $performer_ids: [ID!] = [], - $tag_ids: [ID!] = []) { + $input: ImageUpdateInput!) { - imageUpdate(input: { - id: $id, - title: $title, - rating: $rating, - studio_id: $studio_id, - gallery_ids: $gallery_ids, - performer_ids: $performer_ids, - tag_ids: $tag_ids - }) { + imageUpdate(input: $input) { ...SlimImageData } } mutation BulkImageUpdate( - $ids: [ID!] = [], - $title: String, - $rating: Int, - $studio_id: ID, - $gallery_ids: BulkUpdateIds, - $performer_ids: BulkUpdateIds, - $tag_ids: BulkUpdateIds) { + $input: BulkImageUpdateInput!) { - bulkImageUpdate(input: { - ids: $ids, - title: $title, - rating: $rating, - studio_id: $studio_id, - gallery_ids: $gallery_ids, - performer_ids: $performer_ids, - tag_ids: $tag_ids - }) { + bulkImageUpdate(input: $input) { ...SlimImageData } } diff --git a/graphql/documents/mutations/movie.graphql b/graphql/documents/mutations/movie.graphql index 253d2f8ac..527b7fddb 100644 --- a/graphql/documents/mutations/movie.graphql +++ b/graphql/documents/mutations/movie.graphql @@ -16,21 +16,8 @@ mutation MovieCreate( } } -mutation MovieUpdate( - $id: ID! - $name: String, - $aliases: String, - $duration: Int, - $date: String, - $rating: Int, - $studio_id: ID, - $director: String, - $synopsis: String, - $url: String, - $front_image: String, - $back_image: String) { - - movieUpdate(input: { id: $id, name: $name, aliases: $aliases, duration: $duration, date: $date, rating: $rating, studio_id: $studio_id, director: $director, synopsis: $synopsis, url: $url, front_image: $front_image, back_image: $back_image }) { +mutation MovieUpdate($input: MovieUpdateInput!) { + movieUpdate(input: $input) { ...MovieData } } diff --git a/graphql/documents/mutations/performer.graphql b/graphql/documents/mutations/performer.graphql index 48b490f9d..9ea5a4eff 100644 --- a/graphql/documents/mutations/performer.graphql +++ b/graphql/documents/mutations/performer.graphql @@ -45,49 +45,9 @@ mutation PerformerCreate( } mutation PerformerUpdate( - $id: ID!, - $name: String, - $url: String, - $gender: GenderEnum, - $birthdate: String, - $ethnicity: String, - $country: String, - $eye_color: String, - $height: String, - $measurements: String, - $fake_tits: String, - $career_length: String, - $tattoos: String, - $piercings: String, - $aliases: String, - $twitter: String, - $instagram: String, - $favorite: Boolean, - $stash_ids: [StashIDInput!], - $image: String) { + $input: PerformerUpdateInput!) { - performerUpdate(input: { - id: $id, - name: $name, - url: $url, - gender: $gender, - birthdate: $birthdate, - ethnicity: $ethnicity, - country: $country, - eye_color: $eye_color, - height: $height, - measurements: $measurements, - fake_tits: $fake_tits, - career_length: $career_length, - tattoos: $tattoos, - piercings: $piercings, - aliases: $aliases, - twitter: $twitter, - instagram: $instagram, - favorite: $favorite, - stash_ids: $stash_ids, - image: $image - }) { + performerUpdate(input: $input) { ...PerformerData } } diff --git a/graphql/documents/mutations/scene.graphql b/graphql/documents/mutations/scene.graphql index 98c0b8a08..c9763e84a 100644 --- a/graphql/documents/mutations/scene.graphql +++ b/graphql/documents/mutations/scene.graphql @@ -1,62 +1,16 @@ mutation SceneUpdate( - $id: ID!, - $title: String, - $details: String, - $url: String, - $date: String, - $rating: Int, - $studio_id: ID, - $gallery_id: ID, - $performer_ids: [ID!] = [], - $movies: [SceneMovieInput!] = [], - $tag_ids: [ID!] = [], - $stash_ids: [StashIDInput!], - $cover_image: String) { + $input: SceneUpdateInput!) { - sceneUpdate(input: { - id: $id, - title: $title, - details: $details, - url: $url, - date: $date, - rating: $rating, - studio_id: $studio_id, - gallery_id: $gallery_id, - performer_ids: $performer_ids, - movies: $movies, - tag_ids: $tag_ids, - stash_ids: $stash_ids, - cover_image: $cover_image - }) { - ...SceneData + sceneUpdate(input: $input) { + ...SceneData } } mutation BulkSceneUpdate( - $ids: [ID!] = [], - $title: String, - $details: String, - $url: String, - $date: String, - $rating: Int, - $studio_id: ID, - $gallery_id: ID, - $performer_ids: BulkUpdateIds, - $tag_ids: BulkUpdateIds) { + $input: BulkSceneUpdateInput!) { - bulkSceneUpdate(input: { - ids: $ids, - title: $title, - details: $details, - url: $url, - date: $date, - rating: $rating, - studio_id: $studio_id, - gallery_id: $gallery_id, - performer_ids: $performer_ids, - tag_ids: $tag_ids - }) { - ...SceneData + bulkSceneUpdate(input: $input) { + ...SceneData } } diff --git a/graphql/documents/mutations/studio.graphql b/graphql/documents/mutations/studio.graphql index 9e4a473b5..71015a3ac 100644 --- a/graphql/documents/mutations/studio.graphql +++ b/graphql/documents/mutations/studio.graphql @@ -11,14 +11,9 @@ mutation StudioCreate( } mutation StudioUpdate( - $id: ID! - $name: String, - $url: String, - $image: String, - $stash_ids: [StashIDInput!], - $parent_id: ID) { + $input: StudioUpdateInput!) { - studioUpdate(input: { id: $id, name: $name, url: $url, image: $image, stash_ids: $stash_ids, parent_id: $parent_id }) { + studioUpdate(input: $input) { ...StudioData } } diff --git a/graphql/documents/mutations/tag.graphql b/graphql/documents/mutations/tag.graphql index 3dcd8f2b3..91ad0136b 100644 --- a/graphql/documents/mutations/tag.graphql +++ b/graphql/documents/mutations/tag.graphql @@ -8,8 +8,8 @@ mutation TagDestroy($id: ID!) { tagDestroy(input: { id: $id }) } -mutation TagUpdate($id: ID!, $name: String!, $image: String) { - tagUpdate(input: { id: $id, name: $name, image: $image }) { +mutation TagUpdate($input: TagUpdateInput!) { + tagUpdate(input: $input) { ...TagData } } \ No newline at end of file diff --git a/pkg/api/changeset_translator.go b/pkg/api/changeset_translator.go new file mode 100644 index 000000000..e71912645 --- /dev/null +++ b/pkg/api/changeset_translator.go @@ -0,0 +1,134 @@ +package api + +import ( + "context" + "database/sql" + "strconv" + + "github.com/99designs/gqlgen/graphql" + "github.com/stashapp/stash/pkg/models" +) + +const updateInputField = "input" + +func getArgumentMap(ctx context.Context) map[string]interface{} { + rctx := graphql.GetResolverContext(ctx) + reqCtx := graphql.GetRequestContext(ctx) + return rctx.Field.ArgumentMap(reqCtx.Variables) +} + +func getUpdateInputMap(ctx context.Context) map[string]interface{} { + args := getArgumentMap(ctx) + + input, _ := args[updateInputField] + var ret map[string]interface{} + if input != nil { + ret, _ = input.(map[string]interface{}) + } + + if ret == nil { + ret = make(map[string]interface{}) + } + + return ret +} + +func getUpdateInputMaps(ctx context.Context) []map[string]interface{} { + args := getArgumentMap(ctx) + + input, _ := args[updateInputField] + var ret []map[string]interface{} + if input != nil { + ret, _ = input.([]map[string]interface{}) + } + + return ret +} + +type changesetTranslator struct { + inputMap map[string]interface{} +} + +func (t changesetTranslator) hasField(field string) bool { + if t.inputMap == nil { + return false + } + + _, found := t.inputMap[field] + return found +} + +func (t changesetTranslator) nullString(value *string, field string) *sql.NullString { + if !t.hasField(field) { + return nil + } + + ret := &sql.NullString{} + + if value != nil { + ret.String = *value + ret.Valid = true + } + + return ret +} + +func (t changesetTranslator) sqliteDate(value *string, field string) *models.SQLiteDate { + if !t.hasField(field) { + return nil + } + + ret := &models.SQLiteDate{} + + if value != nil { + ret.String = *value + ret.Valid = true + } + + return ret +} + +func (t changesetTranslator) nullInt64(value *int, field string) *sql.NullInt64 { + if !t.hasField(field) { + return nil + } + + ret := &sql.NullInt64{} + + if value != nil { + ret.Int64 = int64(*value) + ret.Valid = true + } + + return ret +} + +func (t changesetTranslator) nullInt64FromString(value *string, field string) *sql.NullInt64 { + if !t.hasField(field) { + return nil + } + + ret := &sql.NullInt64{} + + if value != nil { + ret.Int64, _ = strconv.ParseInt(*value, 10, 64) + ret.Valid = true + } + + return ret +} + +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 +} diff --git a/pkg/api/resolver_mutation_gallery.go b/pkg/api/resolver_mutation_gallery.go index 77b48d09d..c20bc4b38 100644 --- a/pkg/api/resolver_mutation_gallery.go +++ b/pkg/api/resolver_mutation_gallery.go @@ -119,7 +119,10 @@ func (r *mutationResolver) GalleryUpdate(ctx context.Context, input models.Galle // Start the transaction and save the gallery tx := database.DB.MustBeginTx(ctx, nil) - ret, err := r.galleryUpdate(input, tx) + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + ret, err := r.galleryUpdate(input, translator, tx) if err != nil { _ = tx.Rollback() @@ -137,11 +140,16 @@ func (r *mutationResolver) GalleryUpdate(ctx context.Context, input models.Galle func (r *mutationResolver) GalleriesUpdate(ctx context.Context, input []*models.GalleryUpdateInput) ([]*models.Gallery, error) { // Start the transaction and save the gallery tx := database.DB.MustBeginTx(ctx, nil) + inputMaps := getUpdateInputMaps(ctx) var ret []*models.Gallery - for _, gallery := range input { - thisGallery, err := r.galleryUpdate(*gallery, tx) + for i, gallery := range input { + translator := changesetTranslator{ + inputMap: inputMaps[i], + } + + thisGallery, err := r.galleryUpdate(*gallery, translator, tx) ret = append(ret, thisGallery) if err != nil { @@ -158,7 +166,7 @@ func (r *mutationResolver) GalleriesUpdate(ctx context.Context, input []*models. return ret, nil } -func (r *mutationResolver) galleryUpdate(input models.GalleryUpdateInput, tx *sqlx.Tx) (*models.Gallery, error) { +func (r *mutationResolver) galleryUpdate(input models.GalleryUpdateInput, translator changesetTranslator, tx *sqlx.Tx) (*models.Gallery, error) { qb := models.NewGalleryQueryBuilder() // Populate gallery from the input galleryID, _ := strconv.Atoi(input.ID) @@ -176,6 +184,7 @@ func (r *mutationResolver) galleryUpdate(input models.GalleryUpdateInput, tx *sq ID: galleryID, UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, } + if input.Title != nil { // ensure title is not empty if *input.Title == "" { @@ -190,30 +199,12 @@ func (r *mutationResolver) galleryUpdate(input models.GalleryUpdateInput, tx *sq updatedGallery.Title = &sql.NullString{String: *input.Title, Valid: true} } - if input.Details != nil { - updatedGallery.Details = &sql.NullString{String: *input.Details, Valid: true} - } - if input.URL != nil { - updatedGallery.URL = &sql.NullString{String: *input.URL, Valid: true} - } - if input.Date != nil { - updatedGallery.Date = &models.SQLiteDate{String: *input.Date, Valid: true} - } - if input.Rating != nil { - updatedGallery.Rating = &sql.NullInt64{Int64: int64(*input.Rating), Valid: true} - } else { - // rating must be nullable - updatedGallery.Rating = &sql.NullInt64{Valid: false} - } - - if input.StudioID != nil { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedGallery.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } else { - // studio must be nullable - updatedGallery.StudioID = &sql.NullInt64{Valid: false} - } + updatedGallery.Details = translator.nullString(input.Details, "details") + updatedGallery.URL = translator.nullString(input.URL, "url") + updatedGallery.Date = translator.sqliteDate(input.Date, "date") + updatedGallery.Rating = translator.nullInt64(input.Rating, "rating") + updatedGallery.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") // gallery scene is set from the scene only @@ -224,31 +215,35 @@ func (r *mutationResolver) galleryUpdate(input models.GalleryUpdateInput, tx *sq } // Save the performers - var performerJoins []models.PerformersGalleries - for _, pid := range input.PerformerIds { - performerID, _ := strconv.Atoi(pid) - performerJoin := models.PerformersGalleries{ - PerformerID: performerID, - GalleryID: galleryID, + if translator.hasField("performer_ids") { + var performerJoins []models.PerformersGalleries + for _, pid := range input.PerformerIds { + performerID, _ := strconv.Atoi(pid) + performerJoin := models.PerformersGalleries{ + PerformerID: performerID, + GalleryID: galleryID, + } + performerJoins = append(performerJoins, performerJoin) + } + if err := jqb.UpdatePerformersGalleries(galleryID, performerJoins, tx); err != nil { + return nil, err } - performerJoins = append(performerJoins, performerJoin) - } - if err := jqb.UpdatePerformersGalleries(galleryID, performerJoins, tx); err != nil { - return nil, err } // Save the tags - var tagJoins []models.GalleriesTags - for _, tid := range input.TagIds { - tagID, _ := strconv.Atoi(tid) - tagJoin := models.GalleriesTags{ - GalleryID: galleryID, - TagID: tagID, + if translator.hasField("tag_ids") { + var tagJoins []models.GalleriesTags + for _, tid := range input.TagIds { + tagID, _ := strconv.Atoi(tid) + tagJoin := models.GalleriesTags{ + GalleryID: galleryID, + TagID: tagID, + } + tagJoins = append(tagJoins, tagJoin) + } + if err := jqb.UpdateGalleriesTags(galleryID, tagJoins, tx); err != nil { + return nil, err } - tagJoins = append(tagJoins, tagJoin) - } - if err := jqb.UpdateGalleriesTags(galleryID, tagJoins, tx); err != nil { - return nil, err } return gallery, nil @@ -263,44 +258,20 @@ func (r *mutationResolver) BulkGalleryUpdate(ctx context.Context, input models.B qb := models.NewGalleryQueryBuilder() jqb := models.NewJoinsQueryBuilder() + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + updatedGallery := models.GalleryPartial{ UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, } - if input.Details != nil { - updatedGallery.Details = &sql.NullString{String: *input.Details, Valid: true} - } - if input.URL != nil { - updatedGallery.URL = &sql.NullString{String: *input.URL, Valid: true} - } - if input.Date != nil { - updatedGallery.Date = &models.SQLiteDate{String: *input.Date, Valid: true} - } - if input.Rating != nil { - // a rating of 0 means unset the rating - if *input.Rating == 0 { - updatedGallery.Rating = &sql.NullInt64{Int64: 0, Valid: false} - } else { - updatedGallery.Rating = &sql.NullInt64{Int64: int64(*input.Rating), Valid: true} - } - } - if input.StudioID != nil { - // empty string means unset the studio - if *input.StudioID == "" { - updatedGallery.StudioID = &sql.NullInt64{Int64: 0, Valid: false} - } else { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedGallery.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } - } - if input.SceneID != nil { - // empty string means unset the studio - if *input.SceneID == "" { - updatedGallery.SceneID = &sql.NullInt64{Int64: 0, Valid: false} - } else { - sceneID, _ := strconv.ParseInt(*input.SceneID, 10, 64) - updatedGallery.SceneID = &sql.NullInt64{Int64: sceneID, Valid: true} - } - } + + updatedGallery.Details = translator.nullString(input.Details, "details") + updatedGallery.URL = translator.nullString(input.URL, "url") + updatedGallery.Date = translator.sqliteDate(input.Date, "date") + updatedGallery.Rating = translator.nullInt64(input.Rating, "rating") + updatedGallery.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") + updatedGallery.SceneID = translator.nullInt64FromString(input.SceneID, "scene_id") ret := []*models.Gallery{} @@ -317,7 +288,7 @@ func (r *mutationResolver) BulkGalleryUpdate(ctx context.Context, input models.B ret = append(ret, gallery) // Save the performers - if wasFieldIncluded(ctx, "performer_ids") { + if translator.hasField("performer_ids") { performerIDs, err := adjustGalleryPerformerIDs(tx, galleryID, *input.PerformerIds) if err != nil { _ = tx.Rollback() @@ -339,7 +310,7 @@ func (r *mutationResolver) BulkGalleryUpdate(ctx context.Context, input models.B } // Save the tags - if wasFieldIncluded(ctx, "tag_ids") { + if translator.hasField("tag_ids") { tagIDs, err := adjustGalleryTagIDs(tx, galleryID, *input.TagIds) if err != nil { _ = tx.Rollback() diff --git a/pkg/api/resolver_mutation_image.go b/pkg/api/resolver_mutation_image.go index a71c617f1..7d621cbe9 100644 --- a/pkg/api/resolver_mutation_image.go +++ b/pkg/api/resolver_mutation_image.go @@ -2,7 +2,6 @@ package api import ( "context" - "database/sql" "strconv" "time" @@ -17,7 +16,11 @@ func (r *mutationResolver) ImageUpdate(ctx context.Context, input models.ImageUp // Start the transaction and save the image tx := database.DB.MustBeginTx(ctx, nil) - ret, err := r.imageUpdate(input, tx) + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + + ret, err := r.imageUpdate(input, translator, tx) if err != nil { _ = tx.Rollback() @@ -35,11 +38,16 @@ func (r *mutationResolver) ImageUpdate(ctx context.Context, input models.ImageUp func (r *mutationResolver) ImagesUpdate(ctx context.Context, input []*models.ImageUpdateInput) ([]*models.Image, error) { // Start the transaction and save the image tx := database.DB.MustBeginTx(ctx, nil) + inputMaps := getUpdateInputMaps(ctx) var ret []*models.Image - for _, image := range input { - thisImage, err := r.imageUpdate(*image, tx) + for i, image := range input { + translator := changesetTranslator{ + inputMap: inputMaps[i], + } + + thisImage, err := r.imageUpdate(*image, translator, tx) ret = append(ret, thisImage) if err != nil { @@ -56,7 +64,7 @@ func (r *mutationResolver) ImagesUpdate(ctx context.Context, input []*models.Ima return ret, nil } -func (r *mutationResolver) imageUpdate(input models.ImageUpdateInput, tx *sqlx.Tx) (*models.Image, error) { +func (r *mutationResolver) imageUpdate(input models.ImageUpdateInput, translator changesetTranslator, tx *sqlx.Tx) (*models.Image, error) { // Populate image from the input imageID, _ := strconv.Atoi(input.ID) @@ -65,24 +73,10 @@ func (r *mutationResolver) imageUpdate(input models.ImageUpdateInput, tx *sqlx.T ID: imageID, UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, } - if input.Title != nil { - updatedImage.Title = &sql.NullString{String: *input.Title, Valid: true} - } - if input.Rating != nil { - updatedImage.Rating = &sql.NullInt64{Int64: int64(*input.Rating), Valid: true} - } else { - // rating must be nullable - updatedImage.Rating = &sql.NullInt64{Valid: false} - } - - if input.StudioID != nil { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedImage.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } else { - // studio must be nullable - updatedImage.StudioID = &sql.NullInt64{Valid: false} - } + updatedImage.Title = translator.nullString(input.Title, "title") + updatedImage.Rating = translator.nullInt64(input.Rating, "rating") + updatedImage.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") qb := models.NewImageQueryBuilder() jqb := models.NewJoinsQueryBuilder() @@ -94,31 +88,35 @@ func (r *mutationResolver) imageUpdate(input models.ImageUpdateInput, tx *sqlx.T // don't set the galleries directly. Use add/remove gallery images interface instead // Save the performers - var performerJoins []models.PerformersImages - for _, pid := range input.PerformerIds { - performerID, _ := strconv.Atoi(pid) - performerJoin := models.PerformersImages{ - PerformerID: performerID, - ImageID: imageID, + if translator.hasField("performer_ids") { + var performerJoins []models.PerformersImages + for _, pid := range input.PerformerIds { + performerID, _ := strconv.Atoi(pid) + performerJoin := models.PerformersImages{ + PerformerID: performerID, + ImageID: imageID, + } + performerJoins = append(performerJoins, performerJoin) + } + if err := jqb.UpdatePerformersImages(imageID, performerJoins, tx); err != nil { + return nil, err } - performerJoins = append(performerJoins, performerJoin) - } - if err := jqb.UpdatePerformersImages(imageID, performerJoins, tx); err != nil { - return nil, err } // Save the tags - var tagJoins []models.ImagesTags - for _, tid := range input.TagIds { - tagID, _ := strconv.Atoi(tid) - tagJoin := models.ImagesTags{ - ImageID: imageID, - TagID: tagID, + if translator.hasField("tag_ids") { + var tagJoins []models.ImagesTags + for _, tid := range input.TagIds { + tagID, _ := strconv.Atoi(tid) + tagJoin := models.ImagesTags{ + ImageID: imageID, + TagID: tagID, + } + tagJoins = append(tagJoins, tagJoin) + } + if err := jqb.UpdateImagesTags(imageID, tagJoins, tx); err != nil { + return nil, err } - tagJoins = append(tagJoins, tagJoin) - } - if err := jqb.UpdateImagesTags(imageID, tagJoins, tx); err != nil { - return nil, err } return image, nil @@ -136,27 +134,15 @@ func (r *mutationResolver) BulkImageUpdate(ctx context.Context, input models.Bul updatedImage := models.ImagePartial{ UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, } - if input.Title != nil { - updatedImage.Title = &sql.NullString{String: *input.Title, Valid: true} - } - if input.Rating != nil { - // a rating of 0 means unset the rating - if *input.Rating == 0 { - updatedImage.Rating = &sql.NullInt64{Int64: 0, Valid: false} - } else { - updatedImage.Rating = &sql.NullInt64{Int64: int64(*input.Rating), Valid: true} - } - } - if input.StudioID != nil { - // empty string means unset the studio - if *input.StudioID == "" { - updatedImage.StudioID = &sql.NullInt64{Int64: 0, Valid: false} - } else { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedImage.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } + + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), } + updatedImage.Title = translator.nullString(input.Title, "title") + updatedImage.Rating = translator.nullInt64(input.Rating, "rating") + updatedImage.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") + ret := []*models.Image{} for _, imageIDStr := range input.Ids { @@ -172,7 +158,7 @@ func (r *mutationResolver) BulkImageUpdate(ctx context.Context, input models.Bul ret = append(ret, image) // Save the galleries - if wasFieldIncluded(ctx, "gallery_ids") { + if translator.hasField("gallery_ids") { galleryIDs, err := adjustImageGalleryIDs(tx, imageID, *input.GalleryIds) if err != nil { _ = tx.Rollback() @@ -193,7 +179,7 @@ func (r *mutationResolver) BulkImageUpdate(ctx context.Context, input models.Bul } // Save the performers - if wasFieldIncluded(ctx, "performer_ids") { + if translator.hasField("performer_ids") { performerIDs, err := adjustImagePerformerIDs(tx, imageID, *input.PerformerIds) if err != nil { _ = tx.Rollback() @@ -215,7 +201,7 @@ func (r *mutationResolver) BulkImageUpdate(ctx context.Context, input models.Bul } // Save the tags - if wasFieldIncluded(ctx, "tag_ids") { + if translator.hasField("tag_ids") { tagIDs, err := adjustImageTagIDs(tx, imageID, *input.TagIds) if err != nil { _ = tx.Rollback() diff --git a/pkg/api/resolver_mutation_movie.go b/pkg/api/resolver_mutation_movie.go index 85c8f63f0..8af2a7126 100644 --- a/pkg/api/resolver_mutation_movie.go +++ b/pkg/api/resolver_mutation_movie.go @@ -117,16 +117,21 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input models.MovieUp ID: movieID, UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()}, } + + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + var frontimageData []byte var err error - frontImageIncluded := wasFieldIncluded(ctx, "front_image") + frontImageIncluded := translator.hasField("front_image") if input.FrontImage != nil { _, frontimageData, err = utils.ProcessBase64Image(*input.FrontImage) if err != nil { return nil, err } } - backImageIncluded := wasFieldIncluded(ctx, "back_image") + backImageIncluded := translator.hasField("back_image") var backimageData []byte if input.BackImage != nil { _, backimageData, err = utils.ProcessBase64Image(*input.BackImage) @@ -142,45 +147,14 @@ func (r *mutationResolver) MovieUpdate(ctx context.Context, input models.MovieUp updatedMovie.Checksum = &checksum } - if input.Aliases != nil { - updatedMovie.Aliases = &sql.NullString{String: *input.Aliases, Valid: true} - } - if input.Duration != nil { - duration := int64(*input.Duration) - updatedMovie.Duration = &sql.NullInt64{Int64: duration, Valid: true} - } - - if input.Date != nil { - updatedMovie.Date = &models.SQLiteDate{String: *input.Date, Valid: true} - } - - if input.Rating != nil { - rating := int64(*input.Rating) - updatedMovie.Rating = &sql.NullInt64{Int64: rating, Valid: true} - } else { - // rating must be nullable - updatedMovie.Rating = &sql.NullInt64{Valid: false} - } - - if input.StudioID != nil { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedMovie.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } else { - // studio must be nullable - updatedMovie.StudioID = &sql.NullInt64{Valid: false} - } - - if input.Director != nil { - updatedMovie.Director = &sql.NullString{String: *input.Director, Valid: true} - } - - if input.Synopsis != nil { - updatedMovie.Synopsis = &sql.NullString{String: *input.Synopsis, Valid: true} - } - - if input.URL != nil { - updatedMovie.URL = &sql.NullString{String: *input.URL, Valid: true} - } + updatedMovie.Aliases = translator.nullString(input.Aliases, "aliases") + updatedMovie.Duration = translator.nullInt64(input.Duration, "duration") + updatedMovie.Date = translator.sqliteDate(input.Date, "date") + updatedMovie.Rating = translator.nullInt64(input.Rating, "rating") + updatedMovie.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") + updatedMovie.Director = translator.nullString(input.Director, "director") + updatedMovie.Synopsis = translator.nullString(input.Synopsis, "synopsis") + updatedMovie.URL = translator.nullString(input.URL, "url") // Start the transaction and save the movie tx := database.DB.MustBeginTx(ctx, nil) diff --git a/pkg/api/resolver_mutation_performer.go b/pkg/api/resolver_mutation_performer.go index 0ef185dc0..bf79f6ae6 100644 --- a/pkg/api/resolver_mutation_performer.go +++ b/pkg/api/resolver_mutation_performer.go @@ -130,77 +130,58 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.Per func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.PerformerUpdateInput) (*models.Performer, error) { // Populate performer from the input performerID, _ := strconv.Atoi(input.ID) - updatedPerformer := models.Performer{ + updatedPerformer := models.PerformerPartial{ ID: performerID, - UpdatedAt: models.SQLiteTimestamp{Timestamp: time.Now()}, + UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()}, } + + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + var imageData []byte var err error - imageIncluded := wasFieldIncluded(ctx, "image") + imageIncluded := translator.hasField("image") if input.Image != nil { _, imageData, err = utils.ProcessBase64Image(*input.Image) if err != nil { return nil, err } } + if input.Name != nil { // generate checksum from performer name rather than image checksum := utils.MD5FromString(*input.Name) - updatedPerformer.Name = sql.NullString{String: *input.Name, Valid: true} - updatedPerformer.Checksum = checksum + updatedPerformer.Name = &sql.NullString{String: *input.Name, Valid: true} + updatedPerformer.Checksum = &checksum } - if input.URL != nil { - updatedPerformer.URL = sql.NullString{String: *input.URL, Valid: true} - } - if input.Gender != nil { - updatedPerformer.Gender = sql.NullString{String: input.Gender.String(), Valid: true} - } - if input.Birthdate != nil { - updatedPerformer.Birthdate = models.SQLiteDate{String: *input.Birthdate, Valid: true} - } - if input.Ethnicity != nil { - updatedPerformer.Ethnicity = sql.NullString{String: *input.Ethnicity, Valid: true} - } - if input.Country != nil { - updatedPerformer.Country = sql.NullString{String: *input.Country, Valid: true} - } - if input.EyeColor != nil { - updatedPerformer.EyeColor = sql.NullString{String: *input.EyeColor, Valid: true} - } - if input.Height != nil { - updatedPerformer.Height = sql.NullString{String: *input.Height, Valid: true} - } - if input.Measurements != nil { - updatedPerformer.Measurements = sql.NullString{String: *input.Measurements, Valid: true} - } - if input.FakeTits != nil { - updatedPerformer.FakeTits = sql.NullString{String: *input.FakeTits, Valid: true} - } - if input.CareerLength != nil { - updatedPerformer.CareerLength = sql.NullString{String: *input.CareerLength, Valid: true} - } - if input.Tattoos != nil { - updatedPerformer.Tattoos = sql.NullString{String: *input.Tattoos, Valid: true} - } - if input.Piercings != nil { - updatedPerformer.Piercings = sql.NullString{String: *input.Piercings, Valid: true} - } - if input.Aliases != nil { - updatedPerformer.Aliases = sql.NullString{String: *input.Aliases, Valid: true} - } - if input.Twitter != nil { - updatedPerformer.Twitter = sql.NullString{String: *input.Twitter, Valid: true} - } - if input.Instagram != nil { - updatedPerformer.Instagram = sql.NullString{String: *input.Instagram, Valid: true} - } - if input.Favorite != nil { - updatedPerformer.Favorite = sql.NullBool{Bool: *input.Favorite, Valid: true} - } else { - updatedPerformer.Favorite = sql.NullBool{Bool: false, Valid: true} + + updatedPerformer.URL = translator.nullString(input.URL, "url") + + if translator.hasField("gender") { + if input.Gender != nil { + updatedPerformer.Gender = &sql.NullString{String: input.Gender.String(), Valid: true} + } else { + updatedPerformer.Gender = &sql.NullString{String: "", Valid: false} + } } + updatedPerformer.Birthdate = translator.sqliteDate(input.Birthdate, "birthdate") + updatedPerformer.Country = translator.nullString(input.Country, "country") + updatedPerformer.EyeColor = translator.nullString(input.EyeColor, "eye_color") + updatedPerformer.Measurements = translator.nullString(input.Measurements, "measurements") + updatedPerformer.Height = translator.nullString(input.Height, "height") + updatedPerformer.Ethnicity = translator.nullString(input.Ethnicity, "ethnicity") + updatedPerformer.FakeTits = translator.nullString(input.FakeTits, "fake_tits") + updatedPerformer.CareerLength = translator.nullString(input.CareerLength, "career_length") + updatedPerformer.Tattoos = translator.nullString(input.Tattoos, "tattoos") + updatedPerformer.Piercings = translator.nullString(input.Piercings, "piercings") + updatedPerformer.Aliases = translator.nullString(input.Aliases, "aliases") + updatedPerformer.Twitter = translator.nullString(input.Twitter, "twitter") + updatedPerformer.Instagram = translator.nullString(input.Instagram, "instagram") + updatedPerformer.Favorite = translator.nullBool(input.Favorite, "favorite") + // Start the transaction and save the performer tx := database.DB.MustBeginTx(ctx, nil) qb := models.NewPerformerQueryBuilder() @@ -227,7 +208,7 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.Per } // Save the stash_ids - if input.StashIds != nil { + if translator.hasField("stash_ids") { var stashIDJoins []models.StashID for _, stashID := range input.StashIds { newJoin := models.StashID{ diff --git a/pkg/api/resolver_mutation_scene.go b/pkg/api/resolver_mutation_scene.go index ff2d77a04..d781636ac 100644 --- a/pkg/api/resolver_mutation_scene.go +++ b/pkg/api/resolver_mutation_scene.go @@ -19,7 +19,10 @@ func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUp // Start the transaction and save the scene tx := database.DB.MustBeginTx(ctx, nil) - ret, err := r.sceneUpdate(input, tx) + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + ret, err := r.sceneUpdate(input, translator, tx) if err != nil { _ = tx.Rollback() @@ -40,8 +43,14 @@ func (r *mutationResolver) ScenesUpdate(ctx context.Context, input []*models.Sce var ret []*models.Scene - for _, scene := range input { - thisScene, err := r.sceneUpdate(*scene, tx) + inputMaps := getUpdateInputMaps(ctx) + + for i, scene := range input { + translator := changesetTranslator{ + inputMap: inputMaps[i], + } + + thisScene, err := r.sceneUpdate(*scene, translator, tx) ret = append(ret, thisScene) if err != nil { @@ -58,7 +67,7 @@ func (r *mutationResolver) ScenesUpdate(ctx context.Context, input []*models.Sce return ret, nil } -func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.Tx) (*models.Scene, error) { +func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, translator changesetTranslator, tx *sqlx.Tx) (*models.Scene, error) { // Populate scene from the input sceneID, _ := strconv.Atoi(input.ID) @@ -69,18 +78,13 @@ func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.T ID: sceneID, UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, } - if input.Title != nil { - updatedScene.Title = &sql.NullString{String: *input.Title, Valid: true} - } - if input.Details != nil { - updatedScene.Details = &sql.NullString{String: *input.Details, Valid: true} - } - if input.URL != nil { - updatedScene.URL = &sql.NullString{String: *input.URL, Valid: true} - } - if input.Date != nil { - updatedScene.Date = &models.SQLiteDate{String: *input.Date, Valid: true} - } + + updatedScene.Title = translator.nullString(input.Title, "title") + updatedScene.Details = translator.nullString(input.Details, "details") + updatedScene.URL = translator.nullString(input.URL, "url") + updatedScene.Date = translator.sqliteDate(input.Date, "date") + updatedScene.Rating = translator.nullInt64(input.Rating, "rating") + updatedScene.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") if input.CoverImage != nil && *input.CoverImage != "" { var err error @@ -92,21 +96,6 @@ func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.T // update the cover after updating the scene } - if input.Rating != nil { - updatedScene.Rating = &sql.NullInt64{Int64: int64(*input.Rating), Valid: true} - } else { - // rating must be nullable - updatedScene.Rating = &sql.NullInt64{Valid: false} - } - - if input.StudioID != nil { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedScene.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } else { - // studio must be nullable - updatedScene.StudioID = &sql.NullInt64{Valid: false} - } - qb := models.NewSceneQueryBuilder() jqb := models.NewJoinsQueryBuilder() scene, err := qb.Update(updatedScene, tx) @@ -122,78 +111,86 @@ func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.T } // Clear the existing gallery value - gqb := models.NewGalleryQueryBuilder() - err = gqb.ClearGalleryId(sceneID, tx) - if err != nil { - return nil, err - } - - if input.GalleryID != nil { - // Save the gallery - galleryID, _ := strconv.Atoi(*input.GalleryID) - updatedGallery := models.Gallery{ - ID: galleryID, - SceneID: sql.NullInt64{Int64: int64(sceneID), Valid: true}, - UpdatedAt: models.SQLiteTimestamp{Timestamp: updatedTime}, - } + if translator.hasField("gallery_id") { gqb := models.NewGalleryQueryBuilder() - _, err := gqb.Update(updatedGallery, tx) + err = gqb.ClearGalleryId(sceneID, tx) if err != nil { return nil, err } + + if input.GalleryID != nil { + // Save the gallery + galleryID, _ := strconv.Atoi(*input.GalleryID) + updatedGallery := models.Gallery{ + ID: galleryID, + SceneID: sql.NullInt64{Int64: int64(sceneID), Valid: true}, + UpdatedAt: models.SQLiteTimestamp{Timestamp: updatedTime}, + } + gqb := models.NewGalleryQueryBuilder() + _, err := gqb.Update(updatedGallery, tx) + if err != nil { + return nil, err + } + } } // Save the performers - var performerJoins []models.PerformersScenes - for _, pid := range input.PerformerIds { - performerID, _ := strconv.Atoi(pid) - performerJoin := models.PerformersScenes{ - PerformerID: performerID, - SceneID: sceneID, + if translator.hasField("performer_ids") { + var performerJoins []models.PerformersScenes + for _, pid := range input.PerformerIds { + performerID, _ := strconv.Atoi(pid) + performerJoin := models.PerformersScenes{ + PerformerID: performerID, + SceneID: sceneID, + } + performerJoins = append(performerJoins, performerJoin) + } + if err := jqb.UpdatePerformersScenes(sceneID, performerJoins, tx); err != nil { + return nil, err } - performerJoins = append(performerJoins, performerJoin) - } - if err := jqb.UpdatePerformersScenes(sceneID, performerJoins, tx); err != nil { - return nil, err } // Save the movies - var movieJoins []models.MoviesScenes + if translator.hasField("movies") { + var movieJoins []models.MoviesScenes - for _, movie := range input.Movies { + for _, movie := range input.Movies { - movieID, _ := strconv.Atoi(movie.MovieID) + movieID, _ := strconv.Atoi(movie.MovieID) - movieJoin := models.MoviesScenes{ - MovieID: movieID, - SceneID: sceneID, - } - - if movie.SceneIndex != nil { - movieJoin.SceneIndex = sql.NullInt64{ - Int64: int64(*movie.SceneIndex), - Valid: true, + movieJoin := models.MoviesScenes{ + MovieID: movieID, + SceneID: sceneID, } - } - movieJoins = append(movieJoins, movieJoin) - } - if err := jqb.UpdateMoviesScenes(sceneID, movieJoins, tx); err != nil { - return nil, err + if movie.SceneIndex != nil { + movieJoin.SceneIndex = sql.NullInt64{ + Int64: int64(*movie.SceneIndex), + Valid: true, + } + } + + movieJoins = append(movieJoins, movieJoin) + } + if err := jqb.UpdateMoviesScenes(sceneID, movieJoins, tx); err != nil { + return nil, err + } } // Save the tags - var tagJoins []models.ScenesTags - for _, tid := range input.TagIds { - tagID, _ := strconv.Atoi(tid) - tagJoin := models.ScenesTags{ - SceneID: sceneID, - TagID: tagID, + if translator.hasField("tag_ids") { + var tagJoins []models.ScenesTags + for _, tid := range input.TagIds { + tagID, _ := strconv.Atoi(tid) + tagJoin := models.ScenesTags{ + SceneID: sceneID, + TagID: tagID, + } + tagJoins = append(tagJoins, tagJoin) + } + if err := jqb.UpdateScenesTags(sceneID, tagJoins, tx); err != nil { + return nil, err } - tagJoins = append(tagJoins, tagJoin) - } - if err := jqb.UpdateScenesTags(sceneID, tagJoins, tx); err != nil { - return nil, err } // only update the cover image if provided and everything else was successful @@ -205,7 +202,7 @@ func (r *mutationResolver) sceneUpdate(input models.SceneUpdateInput, tx *sqlx.T } // Save the stash_ids - if input.StashIds != nil { + if translator.hasField("stash_ids") { var stashIDJoins []models.StashID for _, stashID := range input.StashIds { newJoin := models.StashID{ @@ -226,6 +223,10 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul // Populate scene from the input updatedTime := time.Now() + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + // Start the transaction and save the scene marker tx := database.DB.MustBeginTx(ctx, nil) qb := models.NewSceneQueryBuilder() @@ -234,35 +235,13 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul updatedScene := models.ScenePartial{ UpdatedAt: &models.SQLiteTimestamp{Timestamp: updatedTime}, } - if input.Title != nil { - updatedScene.Title = &sql.NullString{String: *input.Title, Valid: true} - } - if input.Details != nil { - updatedScene.Details = &sql.NullString{String: *input.Details, Valid: true} - } - if input.URL != nil { - updatedScene.URL = &sql.NullString{String: *input.URL, Valid: true} - } - if input.Date != nil { - updatedScene.Date = &models.SQLiteDate{String: *input.Date, Valid: true} - } - if input.Rating != nil { - // a rating of 0 means unset the rating - if *input.Rating == 0 { - updatedScene.Rating = &sql.NullInt64{Int64: 0, Valid: false} - } else { - updatedScene.Rating = &sql.NullInt64{Int64: int64(*input.Rating), Valid: true} - } - } - if input.StudioID != nil { - // empty string means unset the studio - if *input.StudioID == "" { - updatedScene.StudioID = &sql.NullInt64{Int64: 0, Valid: false} - } else { - studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64) - updatedScene.StudioID = &sql.NullInt64{Int64: studioID, Valid: true} - } - } + + updatedScene.Title = translator.nullString(input.Title, "title") + updatedScene.Details = translator.nullString(input.Details, "details") + updatedScene.URL = translator.nullString(input.URL, "url") + updatedScene.Date = translator.sqliteDate(input.Date, "date") + updatedScene.Rating = translator.nullInt64(input.Rating, "rating") + updatedScene.StudioID = translator.nullInt64FromString(input.StudioID, "studio_id") ret := []*models.Scene{} @@ -278,9 +257,12 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul ret = append(ret, scene) - if input.GalleryID != nil { + if translator.hasField("gallery_id") { // Save the gallery - galleryID, _ := strconv.Atoi(*input.GalleryID) + var galleryID int + if input.GalleryID != nil { + galleryID, _ = strconv.Atoi(*input.GalleryID) + } updatedGallery := models.Gallery{ ID: galleryID, SceneID: sql.NullInt64{Int64: int64(sceneID), Valid: true}, @@ -295,7 +277,7 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul } // Save the performers - if wasFieldIncluded(ctx, "performer_ids") { + if translator.hasField("performer_ids") { performerIDs, err := adjustScenePerformerIDs(tx, sceneID, *input.PerformerIds) if err != nil { _ = tx.Rollback() @@ -317,7 +299,7 @@ func (r *mutationResolver) BulkSceneUpdate(ctx context.Context, input models.Bul } // Save the tags - if wasFieldIncluded(ctx, "tag_ids") { + if translator.hasField("tag_ids") { tagIDs, err := adjustSceneTagIDs(tx, sceneID, *input.TagIds) if err != nil { _ = tx.Rollback() diff --git a/pkg/api/resolver_mutation_studio.go b/pkg/api/resolver_mutation_studio.go index 855dfd7a5..163f3f5ec 100644 --- a/pkg/api/resolver_mutation_studio.go +++ b/pkg/api/resolver_mutation_studio.go @@ -89,13 +89,17 @@ func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.Studio // Populate studio from the input studioID, _ := strconv.Atoi(input.ID) + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + updatedStudio := models.StudioPartial{ ID: studioID, UpdatedAt: &models.SQLiteTimestamp{Timestamp: time.Now()}, } var imageData []byte - imageIncluded := wasFieldIncluded(ctx, "image") + imageIncluded := translator.hasField("image") if input.Image != nil { var err error _, imageData, err = utils.ProcessBase64Image(*input.Image) @@ -109,17 +113,9 @@ func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.Studio updatedStudio.Name = &sql.NullString{String: *input.Name, Valid: true} updatedStudio.Checksum = &checksum } - if input.URL != nil { - updatedStudio.URL = &sql.NullString{String: *input.URL, Valid: true} - } - if input.ParentID != nil { - parentID, _ := strconv.ParseInt(*input.ParentID, 10, 64) - updatedStudio.ParentID = &sql.NullInt64{Int64: parentID, Valid: true} - } else { - // parent studio must be nullable - updatedStudio.ParentID = &sql.NullInt64{Valid: false} - } + updatedStudio.URL = translator.nullString(input.URL, "url") + updatedStudio.ParentID = translator.nullInt64FromString(input.ParentID, "parent_id") // Start the transaction and save the studio tx := database.DB.MustBeginTx(ctx, nil) @@ -152,7 +148,7 @@ func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.Studio } // Save the stash_ids - if input.StashIds != nil { + if translator.hasField("stash_ids") { var stashIDJoins []models.StashID for _, stashID := range input.StashIds { newJoin := models.StashID{ diff --git a/pkg/api/resolver_mutation_tag.go b/pkg/api/resolver_mutation_tag.go index b23d99d00..96d0b4982 100644 --- a/pkg/api/resolver_mutation_tag.go +++ b/pkg/api/resolver_mutation_tag.go @@ -76,7 +76,11 @@ func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdate var imageData []byte var err error - imageIncluded := wasFieldIncluded(ctx, "image") + translator := changesetTranslator{ + inputMap: getUpdateInputMap(ctx), + } + + imageIncluded := translator.hasField("image") if input.Image != nil { _, imageData, err = utils.ProcessBase64Image(*input.Image) diff --git a/pkg/models/mocks/PerformerReaderWriter.go b/pkg/models/mocks/PerformerReaderWriter.go index 908529b2a..f10129fd8 100644 --- a/pkg/models/mocks/PerformerReaderWriter.go +++ b/pkg/models/mocks/PerformerReaderWriter.go @@ -220,7 +220,30 @@ func (_m *PerformerReaderWriter) GetPerformerImage(performerID int) ([]byte, err } // Update provides a mock function with given fields: updatedPerformer -func (_m *PerformerReaderWriter) Update(updatedPerformer models.Performer) (*models.Performer, error) { +func (_m *PerformerReaderWriter) Update(updatedPerformer models.PerformerPartial) (*models.Performer, error) { + ret := _m.Called(updatedPerformer) + + var r0 *models.Performer + if rf, ok := ret.Get(0).(func(models.PerformerPartial) *models.Performer); ok { + r0 = rf(updatedPerformer) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*models.Performer) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(models.PerformerPartial) error); ok { + r1 = rf(updatedPerformer) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateFull provides a mock function with given fields: updatedPerformer +func (_m *PerformerReaderWriter) UpdateFull(updatedPerformer models.Performer) (*models.Performer, error) { ret := _m.Called(updatedPerformer) var r0 *models.Performer diff --git a/pkg/models/model_performer.go b/pkg/models/model_performer.go index 26b033d61..52dbfa699 100644 --- a/pkg/models/model_performer.go +++ b/pkg/models/model_performer.go @@ -31,6 +31,30 @@ type Performer struct { UpdatedAt SQLiteTimestamp `db:"updated_at" json:"updated_at"` } +type PerformerPartial struct { + ID int `db:"id" json:"id"` + Checksum *string `db:"checksum" json:"checksum"` + Name *sql.NullString `db:"name" json:"name"` + Gender *sql.NullString `db:"gender" json:"gender"` + URL *sql.NullString `db:"url" json:"url"` + Twitter *sql.NullString `db:"twitter" json:"twitter"` + Instagram *sql.NullString `db:"instagram" json:"instagram"` + Birthdate *SQLiteDate `db:"birthdate" json:"birthdate"` + Ethnicity *sql.NullString `db:"ethnicity" json:"ethnicity"` + Country *sql.NullString `db:"country" json:"country"` + EyeColor *sql.NullString `db:"eye_color" json:"eye_color"` + Height *sql.NullString `db:"height" json:"height"` + Measurements *sql.NullString `db:"measurements" json:"measurements"` + FakeTits *sql.NullString `db:"fake_tits" json:"fake_tits"` + CareerLength *sql.NullString `db:"career_length" json:"career_length"` + Tattoos *sql.NullString `db:"tattoos" json:"tattoos"` + Piercings *sql.NullString `db:"piercings" json:"piercings"` + Aliases *sql.NullString `db:"aliases" json:"aliases"` + Favorite *sql.NullBool `db:"favorite" json:"favorite"` + CreatedAt *SQLiteTimestamp `db:"created_at" json:"created_at"` + UpdatedAt *SQLiteTimestamp `db:"updated_at" json:"updated_at"` +} + func NewPerformer(name string) *Performer { currentTime := time.Now() return &Performer{ diff --git a/pkg/models/performer.go b/pkg/models/performer.go index d3956b3bb..61a4d08e3 100644 --- a/pkg/models/performer.go +++ b/pkg/models/performer.go @@ -21,7 +21,8 @@ type PerformerReader interface { type PerformerWriter interface { Create(newPerformer Performer) (*Performer, error) - Update(updatedPerformer Performer) (*Performer, error) + Update(updatedPerformer PerformerPartial) (*Performer, error) + UpdateFull(updatedPerformer Performer) (*Performer, error) // Destroy(id string) error UpdatePerformerImage(performerID int, image []byte) error // DestroyPerformerImage(performerID int) error @@ -80,10 +81,14 @@ func (t *performerReaderWriter) Create(newPerformer Performer) (*Performer, erro return t.qb.Create(newPerformer, t.tx) } -func (t *performerReaderWriter) Update(updatedPerformer Performer) (*Performer, error) { +func (t *performerReaderWriter) Update(updatedPerformer PerformerPartial) (*Performer, error) { return t.qb.Update(updatedPerformer, t.tx) } +func (t *performerReaderWriter) UpdateFull(updatedPerformer Performer) (*Performer, error) { + return t.qb.UpdateFull(updatedPerformer, t.tx) +} + func (t *performerReaderWriter) UpdatePerformerImage(performerID int, image []byte) error { return t.qb.UpdatePerformerImage(performerID, image, t.tx) } diff --git a/pkg/models/querybuilder_performer.go b/pkg/models/querybuilder_performer.go index 7bebf214b..4df839807 100644 --- a/pkg/models/querybuilder_performer.go +++ b/pkg/models/querybuilder_performer.go @@ -42,7 +42,24 @@ func (qb *PerformerQueryBuilder) Create(newPerformer Performer, tx *sqlx.Tx) (*P return &newPerformer, nil } -func (qb *PerformerQueryBuilder) Update(updatedPerformer Performer, tx *sqlx.Tx) (*Performer, error) { +func (qb *PerformerQueryBuilder) Update(updatedPerformer PerformerPartial, tx *sqlx.Tx) (*Performer, error) { + ensureTx(tx) + _, err := tx.NamedExec( + `UPDATE performers SET `+SQLGenKeysPartial(updatedPerformer)+` WHERE performers.id = :id`, + updatedPerformer, + ) + if err != nil { + return nil, err + } + + var ret Performer + if err := tx.Get(&ret, `SELECT * FROM performers WHERE id = ? LIMIT 1`, updatedPerformer.ID); err != nil { + return nil, err + } + return &ret, nil +} + +func (qb *PerformerQueryBuilder) UpdateFull(updatedPerformer Performer, tx *sqlx.Tx) (*Performer, error) { ensureTx(tx) _, err := tx.NamedExec( `UPDATE performers SET `+SQLGenKeys(updatedPerformer)+` WHERE performers.id = :id`, diff --git a/pkg/performer/import.go b/pkg/performer/import.go index 0dae51776..605722577 100644 --- a/pkg/performer/import.go +++ b/pkg/performer/import.go @@ -73,7 +73,7 @@ func (i *Importer) Create() (*int, error) { func (i *Importer) Update(id int) error { performer := i.performer performer.ID = id - _, err := i.ReaderWriter.Update(performer) + _, err := i.ReaderWriter.UpdateFull(performer) if err != nil { return fmt.Errorf("error updating existing performer: %s", err.Error()) } diff --git a/pkg/performer/import_test.go b/pkg/performer/import_test.go index d58f91265..5560ba265 100644 --- a/pkg/performer/import_test.go +++ b/pkg/performer/import_test.go @@ -166,7 +166,7 @@ func TestUpdate(t *testing.T) { // id needs to be set for the mock input performer.ID = performerID - readerWriter.On("Update", performer).Return(nil, nil).Once() + readerWriter.On("UpdateFull", performer).Return(nil, nil).Once() err := i.Update(performerID) assert.Nil(t, err) @@ -175,7 +175,7 @@ func TestUpdate(t *testing.T) { // need to set id separately performerErr.ID = errImageID - readerWriter.On("Update", performerErr).Return(nil, errUpdate).Once() + readerWriter.On("UpdateFull", performerErr).Return(nil, errUpdate).Once() err = i.Update(errImageID) assert.NotNil(t, err) diff --git a/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx b/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx index af3ea3365..39973fc65 100644 --- a/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx +++ b/ui/v2.5/src/components/Galleries/EditGalleriesDialog.tsx @@ -29,7 +29,7 @@ export const EditGalleriesDialog: React.FC = ( ); const [tagIds, setTagIds] = useState(); - const [updateGalleries] = useBulkGalleryUpdate(getGalleryInput()); + const [updateGalleries] = useBulkGalleryUpdate(); // Network state const [isUpdating, setIsUpdating] = useState(false); @@ -61,8 +61,8 @@ export const EditGalleriesDialog: React.FC = ( if (rating === undefined) { // and all galleries have the same rating, then we are unsetting the rating. if (aggregateRating) { - // an undefined rating is ignored in the server, so set it to 0 instead - galleryInput.rating = 0; + // null to unset rating + galleryInput.rating = null; } // otherwise not setting the rating } else { @@ -75,8 +75,8 @@ export const EditGalleriesDialog: React.FC = ( // and all galleries have the same studioId, // then unset the studioId, otherwise ignoring studioId if (aggregateStudioId) { - // an undefined studio_id is ignored in the server, so set it to empty string instead - galleryInput.studio_id = ""; + // null to unset studio_id + galleryInput.studio_id = null; } } else { // if studioId is set, then we are setting it @@ -125,7 +125,11 @@ export const EditGalleriesDialog: React.FC = ( async function onSave() { setIsUpdating(true); try { - await updateGalleries(); + await updateGalleries({ + variables: { + input: getGalleryInput(), + }, + }); Toast.success({ content: "Updated galleries" }); props.onClose(true); } catch (e) { diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx index 18fc373a0..e26b06102 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/GalleryEditPanel.tsx @@ -63,9 +63,7 @@ export const GalleryEditPanel: React.FC< const [createGallery] = useGalleryCreate( getGalleryInput() as GQL.GalleryCreateInput ); - const [updateGallery] = useGalleryUpdate( - getGalleryInput() as GQL.GalleryUpdateInput - ); + const [updateGallery] = useGalleryUpdate(); useEffect(() => { if (props.isVisible) { @@ -135,8 +133,8 @@ export const GalleryEditPanel: React.FC< details, url, date, - rating, - studio_id: studioId, + rating: rating ?? null, + studio_id: studioId ?? null, performer_ids: performerIds, tag_ids: tagIds, }; @@ -152,7 +150,11 @@ export const GalleryEditPanel: React.FC< Toast.success({ content: "Created gallery" }); } } else { - const result = await updateGallery(); + const result = await updateGallery({ + variables: { + input: getGalleryInput() as GQL.GalleryUpdateInput, + }, + }); if (result.data?.galleryUpdate) { Toast.success({ content: "Updated gallery" }); } diff --git a/ui/v2.5/src/components/Images/EditImagesDialog.tsx b/ui/v2.5/src/components/Images/EditImagesDialog.tsx index 2fe85adbd..41776b143 100644 --- a/ui/v2.5/src/components/Images/EditImagesDialog.tsx +++ b/ui/v2.5/src/components/Images/EditImagesDialog.tsx @@ -29,7 +29,7 @@ export const EditImagesDialog: React.FC = ( ); const [tagIds, setTagIds] = useState(); - const [updateImages] = useBulkImageUpdate(getImageInput()); + const [updateImages] = useBulkImageUpdate(); // Network state const [isUpdating, setIsUpdating] = useState(false); @@ -61,8 +61,8 @@ export const EditImagesDialog: React.FC = ( if (rating === undefined) { // and all images have the same rating, then we are unsetting the rating. if (aggregateRating) { - // an undefined rating is ignored in the server, so set it to 0 instead - imageInput.rating = 0; + // null rating to unset it + imageInput.rating = null; } // otherwise not setting the rating } else { @@ -75,8 +75,8 @@ export const EditImagesDialog: React.FC = ( // and all images have the same studioId, // then unset the studioId, otherwise ignoring studioId if (aggregateStudioId) { - // an undefined studio_id is ignored in the server, so set it to empty string instead - imageInput.studio_id = ""; + // null studio_id to unset it + imageInput.studio_id = null; } } else { // if studioId is set, then we are setting it @@ -125,7 +125,11 @@ export const EditImagesDialog: React.FC = ( async function onSave() { setIsUpdating(true); try { - await updateImages(); + await updateImages({ + variables: { + input: getImageInput(), + }, + }); Toast.success({ content: "Updated images" }); props.onClose(true); } catch (e) { diff --git a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx index f49e10d2a..84c1d0ef2 100644 --- a/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx +++ b/ui/v2.5/src/components/Images/ImageDetails/ImageEditPanel.tsx @@ -30,7 +30,7 @@ export const ImageEditPanel: React.FC = (props: IProps) => { // Network state const [isLoading, setIsLoading] = useState(true); - const [updateImage] = useImageUpdate(getImageInput()); + const [updateImage] = useImageUpdate(); useEffect(() => { if (props.isVisible) { @@ -95,8 +95,8 @@ export const ImageEditPanel: React.FC = (props: IProps) => { return { id: props.image.id, title, - rating, - studio_id: studioId, + rating: rating ?? null, + studio_id: studioId ?? null, performer_ids: performerIds, tag_ids: tagIds, }; @@ -105,7 +105,11 @@ export const ImageEditPanel: React.FC = (props: IProps) => { async function onSave() { setIsLoading(true); try { - const result = await updateImage(); + const result = await updateImage({ + variables: { + input: getImageInput(), + }, + }); if (result.data?.imageUpdate) { Toast.success({ content: "Updated image" }); } diff --git a/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx b/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx index 3b6396fd9..9f57a74bf 100644 --- a/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx +++ b/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx @@ -79,7 +79,7 @@ export const Movie: React.FC = () => { // Network state const { data, error, loading } = useFindMovie(id); const [isLoading, setIsLoading] = useState(false); - const [updateMovie] = useMovieUpdate(getMovieInput() as GQL.MovieUpdateInput); + const [updateMovie] = useMovieUpdate(); const [createMovie] = useMovieCreate(getMovieInput() as GQL.MovieCreateInput); const [deleteMovie] = useMovieDestroy( getMovieInput() as GQL.MovieDestroyInput @@ -201,8 +201,8 @@ export const Movie: React.FC = () => { aliases, duration, date, - rating, - studio_id: studioId, + rating: rating ?? null, + studio_id: studioId ?? null, director, synopsis, url, @@ -219,7 +219,11 @@ export const Movie: React.FC = () => { async function onSave() { try { if (!isNew) { - const result = await updateMovie(); + const result = await updateMovie({ + variables: { + input: getMovieInput() as GQL.MovieUpdateInput, + }, + }); if (result.data?.movieUpdate) { updateMovieData(result.data.movieUpdate); setIsEditing(false); diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx index 6fd7a54b0..5fe01d9ef 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx @@ -111,12 +111,14 @@ export const Performer: React.FC = () => { if (!isNew) { await updatePerformer({ variables: { - ...performerInput, - stash_ids: (performerInput?.stash_ids ?? []).map((s) => ({ - endpoint: s.endpoint, - stash_id: s.stash_id, - })), - } as GQL.PerformerUpdateInput, + input: { + ...performerInput, + stash_ids: performerInput?.stash_ids?.map((s) => ({ + endpoint: s.endpoint, + stash_id: s.stash_id, + })), + } as GQL.PerformerUpdateInput, + }, }); if (performerInput.image) { // Refetch image to bust browser cache @@ -215,7 +217,10 @@ export const Performer: React.FC = () => { } function setFavorite(v: boolean) { - onSave({ ...performer, favorite: v }); + onSave({ + id: performer.id, + favorite: v, + }); } const renderIcons = () => ( diff --git a/ui/v2.5/src/components/Scenes/EditScenesDialog.tsx b/ui/v2.5/src/components/Scenes/EditScenesDialog.tsx index acdfeebc8..c3bc35360 100644 --- a/ui/v2.5/src/components/Scenes/EditScenesDialog.tsx +++ b/ui/v2.5/src/components/Scenes/EditScenesDialog.tsx @@ -61,8 +61,8 @@ export const EditScenesDialog: React.FC = ( if (rating === undefined) { // and all scenes have the same rating, then we are unsetting the rating. if (aggregateRating) { - // an undefined rating is ignored in the server, so set it to 0 instead - sceneInput.rating = 0; + // null rating unsets it + sceneInput.rating = null; } // otherwise not setting the rating } else { @@ -75,8 +75,8 @@ export const EditScenesDialog: React.FC = ( // and all scenes have the same studioId, // then unset the studioId, otherwise ignoring studioId if (aggregateStudioId) { - // an undefined studio_id is ignored in the server, so set it to empty string instead - sceneInput.studio_id = ""; + // null studio_id unsets it + sceneInput.studio_id = null; } } else { // if studioId is set, then we are setting it diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 0e6d32617..6c086b921 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -194,9 +194,9 @@ export const SceneEditPanel: React.FC = (props: IProps) => { details, url, date, - rating, - gallery_id: galleryId, - studio_id: studioId, + rating: rating ?? null, + gallery_id: galleryId ?? null, + studio_id: studioId ?? null, performer_ids: performerIds, movies: makeMovieInputs(), tag_ids: tagIds, diff --git a/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx b/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx index f76c9b3dc..61d7027cf 100644 --- a/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx +++ b/ui/v2.5/src/components/Studios/StudioDetails/Studio.tsx @@ -51,9 +51,7 @@ export const Studio: React.FC = () => { const [imagePreview, setImagePreview] = useState(); const { data, error, loading } = useFindStudio(id); - const [updateStudio] = useStudioUpdate( - getStudioInput() as GQL.StudioUpdateInput - ); + const [updateStudio] = useStudioUpdate(); const [createStudio] = useStudioCreate( getStudioInput() as GQL.StudioCreateInput ); @@ -118,8 +116,8 @@ export const Studio: React.FC = () => { const input: Partial = { name, url, - parent_id: parentStudioId, - image, + parent_id: parentStudioId ?? null, + image: image ?? null, }; if (!isNew) { @@ -131,7 +129,11 @@ export const Studio: React.FC = () => { async function onSave() { try { if (!isNew) { - const result = await updateStudio(); + const result = await updateStudio({ + variables: { + input: getStudioInput() as GQL.StudioUpdateInput, + }, + }); if (result.data?.studioUpdate) { updateStudioData(result.data.studioUpdate); setIsEditing(false); diff --git a/ui/v2.5/src/components/Tagger/StashSearchResult.tsx b/ui/v2.5/src/components/Tagger/StashSearchResult.tsx index f3fe70fca..7803db37a 100755 --- a/ui/v2.5/src/components/Tagger/StashSearchResult.tsx +++ b/ui/v2.5/src/components/Tagger/StashSearchResult.tsx @@ -279,27 +279,26 @@ const StashSearchResult: React.FC = ({ const sceneUpdateResult = await updateScene({ variables: { - id: stashScene.id ?? "", - title: scene.title, - details: scene.details, - date: scene.date, - performer_ids: performerIDs.filter((id) => id !== "Skip") as string[], - studio_id: studioID, - cover_image: imgData, - url: scene.url, - tag_ids: updatedTags, - rating: stashScene.rating, - movies: stashScene.movies.map((m) => ({ - movie_id: m.movie.id, - scene_index: m.scene_index, - })), - stash_ids: [ - ...(stashScene?.stash_ids ?? []), - { - endpoint, - stash_id: scene.stash_id, - }, - ], + input: { + id: stashScene.id ?? "", + title: scene.title, + details: scene.details, + date: scene.date, + performer_ids: performerIDs.filter( + (id) => id !== "Skip" + ) as string[], + studio_id: studioID, + cover_image: imgData, + url: scene.url, + tag_ids: updatedTags, + stash_ids: [ + ...(stashScene?.stash_ids ?? []), + { + endpoint, + stash_id: scene.stash_id, + }, + ], + }, }, }); diff --git a/ui/v2.5/src/components/Tagger/queries.ts b/ui/v2.5/src/components/Tagger/queries.ts index 98a685896..ae46d14e2 100644 --- a/ui/v2.5/src/components/Tagger/queries.ts +++ b/ui/v2.5/src/components/Tagger/queries.ts @@ -12,11 +12,13 @@ export const useUpdatePerformerStashID = () => { ) => updatePerformer({ variables: { - id: performerID, - stash_ids: stashIDs.map((s) => ({ - stash_id: s.stash_id, - endpoint: s.endpoint, - })), + input: { + id: performerID, + stash_ids: stashIDs.map((s) => ({ + stash_id: s.stash_id, + endpoint: s.endpoint, + })), + }, }, update: (store, updatedPerformer) => { if (!updatedPerformer.data?.performerUpdate) return; @@ -117,12 +119,13 @@ export const useUpdateStudioStashID = () => { ) => updateStudio({ variables: { - id: studio.id, - parent_id: studio.parent_studio?.id, - stash_ids: stashIDs.map((s) => ({ - stash_id: s.stash_id, - endpoint: s.endpoint, - })), + input: { + id: studio.id, + stash_ids: stashIDs.map((s) => ({ + stash_id: s.stash_id, + endpoint: s.endpoint, + })), + }, }, update: (store, result) => { if (!result.data?.studioUpdate) return; diff --git a/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx b/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx index 65b8489ac..53a975be5 100644 --- a/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx +++ b/ui/v2.5/src/components/Tags/TagDetails/Tag.tsx @@ -47,7 +47,7 @@ export const Tag: React.FC = () => { const [imagePreview, setImagePreview] = useState(); const { data, error, loading } = useFindTag(id); - const [updateTag] = useTagUpdate(getTagInput() as GQL.TagUpdateInput); + const [updateTag] = useTagUpdate(); const [createTag] = useTagCreate(getTagInput() as GQL.TagUpdateInput); const [deleteTag] = useTagDestroy(getTagInput() as GQL.TagUpdateInput); @@ -127,7 +127,11 @@ export const Tag: React.FC = () => { async function onSave() { try { if (!isNew) { - const result = await updateTag(); + const result = await updateTag({ + variables: { + input: getTagInput() as GQL.TagUpdateInput, + }, + }); if (result.data?.tagUpdate) { updateTagData(result.data.tagUpdate); setIsEditing(false); diff --git a/ui/v2.5/src/core/StashService.ts b/ui/v2.5/src/core/StashService.ts index 8bbc9e3ce..abbbe404b 100644 --- a/ui/v2.5/src/core/StashService.ts +++ b/ui/v2.5/src/core/StashService.ts @@ -325,13 +325,17 @@ const sceneMutationImpactedQueries = [ export const useSceneUpdate = (input: GQL.SceneUpdateInput) => GQL.useSceneUpdateMutation({ - variables: input, + variables: { + input, + }, update: deleteCache(sceneMutationImpactedQueries), }); export const useBulkSceneUpdate = (input: GQL.BulkSceneUpdateInput) => GQL.useBulkSceneUpdateMutation({ - variables: input, + variables: { + input, + }, update: deleteCache(sceneMutationImpactedQueries), }); @@ -419,15 +423,13 @@ const imageMutationImpactedQueries = [ GQL.FindGalleriesDocument, ]; -export const useImageUpdate = (input: GQL.ImageUpdateInput) => +export const useImageUpdate = () => GQL.useImageUpdateMutation({ - variables: input, update: deleteCache(imageMutationImpactedQueries), }); -export const useBulkImageUpdate = (input: GQL.BulkImageUpdateInput) => +export const useBulkImageUpdate = () => GQL.useBulkImageUpdateMutation({ - variables: input, update: deleteCache(imageMutationImpactedQueries), }); @@ -506,15 +508,13 @@ export const useGalleryCreate = (input: GQL.GalleryCreateInput) => update: deleteCache(galleryMutationImpactedQueries), }); -export const useGalleryUpdate = (input: GQL.GalleryUpdateInput) => +export const useGalleryUpdate = () => GQL.useGalleryUpdateMutation({ - variables: input, update: deleteCache(galleryMutationImpactedQueries), }); -export const useBulkGalleryUpdate = (input: GQL.BulkGalleryUpdateInput) => +export const useBulkGalleryUpdate = () => GQL.useBulkGalleryUpdateMutation({ - variables: input, update: deleteCache(galleryMutationImpactedQueries), }); @@ -555,9 +555,8 @@ export const useStudioCreate = (input: GQL.StudioCreateInput) => ]), }); -export const useStudioUpdate = (input: GQL.StudioUpdateInput) => +export const useStudioUpdate = () => GQL.useStudioUpdateMutation({ - variables: input, update: deleteCache(studioMutationImpactedQueries), }); @@ -583,9 +582,8 @@ export const useMovieCreate = (input: GQL.MovieCreateInput) => ]), }); -export const useMovieUpdate = (input: GQL.MovieUpdateInput) => +export const useMovieUpdate = () => GQL.useMovieUpdateMutation({ - variables: input, update: deleteCache(movieMutationImpactedQueries), }); @@ -618,9 +616,8 @@ export const useTagCreate = (input: GQL.TagCreateInput) => GQL.AllTagsForFilterDocument, ]), }); -export const useTagUpdate = (input: GQL.TagUpdateInput) => +export const useTagUpdate = () => GQL.useTagUpdateMutation({ - variables: input, update: deleteCache(tagMutationImpactedQueries), }); export const useTagDestroy = (input: GQL.TagDestroyInput) =>