mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Use changesets correctly when updating objects (#976)
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
134
pkg/api/changeset_translator.go
Normal file
134
pkg/api/changeset_translator.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -29,7 +29,7 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
);
|
||||
const [tagIds, setTagIds] = useState<string[]>();
|
||||
|
||||
const [updateGalleries] = useBulkGalleryUpdate(getGalleryInput());
|
||||
const [updateGalleries] = useBulkGalleryUpdate();
|
||||
|
||||
// Network state
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
@@ -61,8 +61,8 @@ export const EditGalleriesDialog: React.FC<IListOperationProps> = (
|
||||
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<IListOperationProps> = (
|
||||
// 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<IListOperationProps> = (
|
||||
async function onSave() {
|
||||
setIsUpdating(true);
|
||||
try {
|
||||
await updateGalleries();
|
||||
await updateGalleries({
|
||||
variables: {
|
||||
input: getGalleryInput(),
|
||||
},
|
||||
});
|
||||
Toast.success({ content: "Updated galleries" });
|
||||
props.onClose(true);
|
||||
} catch (e) {
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export const EditImagesDialog: React.FC<IListOperationProps> = (
|
||||
);
|
||||
const [tagIds, setTagIds] = useState<string[]>();
|
||||
|
||||
const [updateImages] = useBulkImageUpdate(getImageInput());
|
||||
const [updateImages] = useBulkImageUpdate();
|
||||
|
||||
// Network state
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
@@ -61,8 +61,8 @@ export const EditImagesDialog: React.FC<IListOperationProps> = (
|
||||
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<IListOperationProps> = (
|
||||
// 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<IListOperationProps> = (
|
||||
async function onSave() {
|
||||
setIsUpdating(true);
|
||||
try {
|
||||
await updateImages();
|
||||
await updateImages({
|
||||
variables: {
|
||||
input: getImageInput(),
|
||||
},
|
||||
});
|
||||
Toast.success({ content: "Updated images" });
|
||||
props.onClose(true);
|
||||
} catch (e) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export const ImageEditPanel: React.FC<IProps> = (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<IProps> = (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<IProps> = (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" });
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = () => (
|
||||
|
||||
@@ -61,8 +61,8 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
||||
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<IListOperationProps> = (
|
||||
// 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
|
||||
|
||||
@@ -194,9 +194,9 @@ export const SceneEditPanel: React.FC<IProps> = (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,
|
||||
|
||||
@@ -51,9 +51,7 @@ export const Studio: React.FC = () => {
|
||||
const [imagePreview, setImagePreview] = useState<string | null>();
|
||||
|
||||
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<GQL.StudioCreateInput | GQL.StudioUpdateInput> = {
|
||||
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);
|
||||
|
||||
@@ -279,27 +279,26 @@ const StashSearchResult: React.FC<IStashSearchResultProps> = ({
|
||||
|
||||
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,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -47,7 +47,7 @@ export const Tag: React.FC = () => {
|
||||
const [imagePreview, setImagePreview] = useState<string>();
|
||||
|
||||
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);
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
Reference in New Issue
Block a user