mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Add bulk update markers interface (#6210)
This commit is contained in:
parent
2a2a730296
commit
8c4b607454
6 changed files with 151 additions and 3 deletions
|
|
@ -328,6 +328,7 @@ type Mutation {
|
|||
|
||||
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
||||
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
||||
bulkSceneMarkerUpdate(input: BulkSceneMarkerUpdateInput!): [SceneMarker!]
|
||||
sceneMarkerDestroy(id: ID!): Boolean!
|
||||
sceneMarkersDestroy(ids: [ID!]!): Boolean!
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,13 @@ input SceneMarkerUpdateInput {
|
|||
tag_ids: [ID!]
|
||||
}
|
||||
|
||||
input BulkSceneMarkerUpdateInput {
|
||||
ids: [ID!]
|
||||
title: String
|
||||
primary_tag_id: ID
|
||||
tag_ids: BulkUpdateIds
|
||||
}
|
||||
|
||||
type FindSceneMarkersResultType {
|
||||
count: Int!
|
||||
scene_markers: [SceneMarker!]!
|
||||
|
|
|
|||
|
|
@ -820,6 +820,123 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input SceneMar
|
|||
return r.getSceneMarker(ctx, markerID)
|
||||
}
|
||||
|
||||
func (r *mutationResolver) BulkSceneMarkerUpdate(ctx context.Context, input BulkSceneMarkerUpdateInput) ([]*models.SceneMarker, error) {
|
||||
ids, err := stringslice.StringSliceToIntSlice(input.Ids)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting ids: %w", err)
|
||||
}
|
||||
|
||||
translator := changesetTranslator{
|
||||
inputMap: getUpdateInputMap(ctx),
|
||||
}
|
||||
|
||||
// Populate performer from the input
|
||||
partial := models.NewSceneMarkerPartial()
|
||||
|
||||
partial.Title = translator.optionalString(input.Title, "title")
|
||||
|
||||
partial.PrimaryTagID, err = translator.optionalIntFromString(input.PrimaryTagID, "primary_tag_id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting primary tag id: %w", err)
|
||||
}
|
||||
|
||||
partial.TagIDs, err = translator.updateIdsBulk(input.TagIds, "tag_ids")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("converting tag ids: %w", err)
|
||||
}
|
||||
|
||||
ret := []*models.SceneMarker{}
|
||||
|
||||
// Start the transaction and save the performers
|
||||
if err := r.withTxn(ctx, func(ctx context.Context) error {
|
||||
qb := r.repository.SceneMarker
|
||||
|
||||
for _, id := range ids {
|
||||
l := partial
|
||||
|
||||
if err := adjustMarkerPartialForTagExclusion(ctx, r.repository.SceneMarker, id, &l); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
updated, err := qb.UpdatePartial(ctx, id, l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ret = append(ret, updated)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// execute post hooks outside of txn
|
||||
var newRet []*models.SceneMarker
|
||||
for _, m := range ret {
|
||||
r.hookExecutor.ExecutePostHooks(ctx, m.ID, hook.SceneMarkerUpdatePost, input, translator.getFields())
|
||||
|
||||
m, err = r.getSceneMarker(ctx, m.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newRet = append(newRet, m)
|
||||
}
|
||||
|
||||
return newRet, nil
|
||||
}
|
||||
|
||||
// adjustMarkerPartialForTagExclusion adjusts the SceneMarkerPartial to exclude the primary tag from tag updates.
|
||||
func adjustMarkerPartialForTagExclusion(ctx context.Context, r models.SceneMarkerReader, id int, partial *models.SceneMarkerPartial) error {
|
||||
if partial.TagIDs == nil && !partial.PrimaryTagID.Set {
|
||||
return nil
|
||||
}
|
||||
|
||||
// exclude primary tag from tag updates
|
||||
var primaryTagID int
|
||||
if partial.PrimaryTagID.Set {
|
||||
primaryTagID = partial.PrimaryTagID.Value
|
||||
} else {
|
||||
existing, err := r.Find(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("finding existing primary tag id: %w", err)
|
||||
}
|
||||
|
||||
primaryTagID = existing.PrimaryTagID
|
||||
}
|
||||
|
||||
existingTagIDs, err := r.GetTagIDs(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting existing tag ids: %w", err)
|
||||
}
|
||||
|
||||
tagIDAttr := partial.TagIDs
|
||||
|
||||
if tagIDAttr == nil {
|
||||
tagIDAttr = &models.UpdateIDs{
|
||||
IDs: existingTagIDs,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
}
|
||||
|
||||
newTagIDs := tagIDAttr.Apply(existingTagIDs)
|
||||
// Remove primary tag from newTagIDs if present
|
||||
newTagIDs = sliceutil.Exclude(newTagIDs, []int{primaryTagID})
|
||||
|
||||
if len(existingTagIDs) != len(newTagIDs) {
|
||||
partial.TagIDs = &models.UpdateIDs{
|
||||
IDs: newTagIDs,
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
} else {
|
||||
// no change to tags required
|
||||
partial.TagIDs = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (bool, error) {
|
||||
return r.SceneMarkersDestroy(ctx, []string{id})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ type SceneMarkerPartial struct {
|
|||
Seconds OptionalFloat64
|
||||
EndSeconds OptionalFloat64
|
||||
PrimaryTagID OptionalInt
|
||||
TagIDs *UpdateIDs
|
||||
SceneID OptionalInt
|
||||
CreatedAt OptionalTime
|
||||
UpdatedAt OptionalTime
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ import (
|
|||
"github.com/stashapp/stash/pkg/models"
|
||||
)
|
||||
|
||||
const sceneMarkerTable = "scene_markers"
|
||||
const (
|
||||
sceneMarkerTable = "scene_markers"
|
||||
sceneMarkersTagsTable = "scene_markers_tags"
|
||||
sceneMarkerIDColumn = "scene_marker_id"
|
||||
)
|
||||
|
||||
const countSceneMarkersForTagQuery = `
|
||||
SELECT scene_markers.id FROM scene_markers
|
||||
|
|
@ -101,8 +105,8 @@ var (
|
|||
},
|
||||
tags: joinRepository{
|
||||
repository: repository{
|
||||
tableName: "scene_markers_tags",
|
||||
idColumn: "scene_marker_id",
|
||||
tableName: sceneMarkersTagsTable,
|
||||
idColumn: sceneMarkerIDColumn,
|
||||
},
|
||||
fkColumn: tagIDColumn,
|
||||
},
|
||||
|
|
@ -157,6 +161,12 @@ func (qb *SceneMarkerStore) UpdatePartial(ctx context.Context, id int, partial m
|
|||
}
|
||||
}
|
||||
|
||||
if partial.TagIDs != nil {
|
||||
if err := sceneMarkersTagsTableMgr.modifyJoins(ctx, id, partial.TagIDs.IDs, partial.TagIDs.Mode); err != nil {
|
||||
return nil, fmt.Errorf("modifying scene marker tags: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return qb.find(ctx, id)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ var (
|
|||
scenesGroupsJoinTable = goqu.T(groupsScenesTable)
|
||||
scenesURLsJoinTable = goqu.T(scenesURLsTable)
|
||||
|
||||
sceneMarkersTagsJoinTable = goqu.T(sceneMarkersTagsTable)
|
||||
|
||||
performersAliasesJoinTable = goqu.T(performersAliasesTable)
|
||||
performersURLsJoinTable = goqu.T(performerURLsTable)
|
||||
performersTagsJoinTable = goqu.T(performersTagsTable)
|
||||
|
|
@ -160,6 +162,16 @@ var (
|
|||
idColumn: goqu.T(sceneMarkerTable).Col(idColumn),
|
||||
}
|
||||
|
||||
sceneMarkersTagsTableMgr = &joinTable{
|
||||
table: table{
|
||||
table: sceneMarkersTagsJoinTable,
|
||||
idColumn: sceneMarkersTagsJoinTable.Col(sceneMarkerIDColumn),
|
||||
},
|
||||
fkColumn: sceneMarkersTagsJoinTable.Col(tagIDColumn),
|
||||
foreignTable: tagTableMgr,
|
||||
orderBy: tagTableSort,
|
||||
}
|
||||
|
||||
scenesFilesTableMgr = &relatedFilesTable{
|
||||
table: table{
|
||||
table: scenesFilesJoinTable,
|
||||
|
|
|
|||
Loading…
Reference in a new issue