@@ -820,6 +820,123 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input SceneMar
820820 return r .getSceneMarker (ctx , markerID )
821821}
822822
823+ func (r * mutationResolver ) BulkSceneMarkerUpdate (ctx context.Context , input BulkSceneMarkerUpdateInput ) ([]* models.SceneMarker , error ) {
824+ ids , err := stringslice .StringSliceToIntSlice (input .Ids )
825+ if err != nil {
826+ return nil , fmt .Errorf ("converting ids: %w" , err )
827+ }
828+
829+ translator := changesetTranslator {
830+ inputMap : getUpdateInputMap (ctx ),
831+ }
832+
833+ // Populate performer from the input
834+ partial := models .NewSceneMarkerPartial ()
835+
836+ partial .Title = translator .optionalString (input .Title , "title" )
837+
838+ partial .PrimaryTagID , err = translator .optionalIntFromString (input .PrimaryTagID , "primary_tag_id" )
839+ if err != nil {
840+ return nil , fmt .Errorf ("converting primary tag id: %w" , err )
841+ }
842+
843+ partial .TagIDs , err = translator .updateIdsBulk (input .TagIds , "tag_ids" )
844+ if err != nil {
845+ return nil , fmt .Errorf ("converting tag ids: %w" , err )
846+ }
847+
848+ ret := []* models.SceneMarker {}
849+
850+ // Start the transaction and save the performers
851+ if err := r .withTxn (ctx , func (ctx context.Context ) error {
852+ qb := r .repository .SceneMarker
853+
854+ for _ , id := range ids {
855+ l := partial
856+
857+ if err := adjustMarkerPartialForTagExclusion (ctx , r .repository .SceneMarker , id , & l ); err != nil {
858+ return err
859+ }
860+
861+ updated , err := qb .UpdatePartial (ctx , id , l )
862+ if err != nil {
863+ return err
864+ }
865+
866+ ret = append (ret , updated )
867+ }
868+
869+ return nil
870+ }); err != nil {
871+ return nil , err
872+ }
873+
874+ // execute post hooks outside of txn
875+ var newRet []* models.SceneMarker
876+ for _ , m := range ret {
877+ r .hookExecutor .ExecutePostHooks (ctx , m .ID , hook .SceneMarkerUpdatePost , input , translator .getFields ())
878+
879+ m , err = r .getSceneMarker (ctx , m .ID )
880+ if err != nil {
881+ return nil , err
882+ }
883+
884+ newRet = append (newRet , m )
885+ }
886+
887+ return newRet , nil
888+ }
889+
890+ // adjustMarkerPartialForTagExclusion adjusts the SceneMarkerPartial to exclude the primary tag from tag updates.
891+ func adjustMarkerPartialForTagExclusion (ctx context.Context , r models.SceneMarkerReader , id int , partial * models.SceneMarkerPartial ) error {
892+ if partial .TagIDs == nil && ! partial .PrimaryTagID .Set {
893+ return nil
894+ }
895+
896+ // exclude primary tag from tag updates
897+ var primaryTagID int
898+ if partial .PrimaryTagID .Set {
899+ primaryTagID = partial .PrimaryTagID .Value
900+ } else {
901+ existing , err := r .Find (ctx , id )
902+ if err != nil {
903+ return fmt .Errorf ("finding existing primary tag id: %w" , err )
904+ }
905+
906+ primaryTagID = existing .PrimaryTagID
907+ }
908+
909+ existingTagIDs , err := r .GetTagIDs (ctx , id )
910+ if err != nil {
911+ return fmt .Errorf ("getting existing tag ids: %w" , err )
912+ }
913+
914+ tagIDAttr := partial .TagIDs
915+
916+ if tagIDAttr == nil {
917+ tagIDAttr = & models.UpdateIDs {
918+ IDs : existingTagIDs ,
919+ Mode : models .RelationshipUpdateModeSet ,
920+ }
921+ }
922+
923+ newTagIDs := tagIDAttr .Apply (existingTagIDs )
924+ // Remove primary tag from newTagIDs if present
925+ newTagIDs = sliceutil .Exclude (newTagIDs , []int {primaryTagID })
926+
927+ if len (existingTagIDs ) != len (newTagIDs ) {
928+ partial .TagIDs = & models.UpdateIDs {
929+ IDs : newTagIDs ,
930+ Mode : models .RelationshipUpdateModeSet ,
931+ }
932+ } else {
933+ // no change to tags required
934+ partial .TagIDs = nil
935+ }
936+
937+ return nil
938+ }
939+
823940func (r * mutationResolver ) SceneMarkerDestroy (ctx context.Context , id string ) (bool , error ) {
824941 return r .SceneMarkersDestroy (ctx , []string {id })
825942}
0 commit comments