mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 16:34:02 +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
|
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
|
||||||
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
|
||||||
|
bulkSceneMarkerUpdate(input: BulkSceneMarkerUpdateInput!): [SceneMarker!]
|
||||||
sceneMarkerDestroy(id: ID!): Boolean!
|
sceneMarkerDestroy(id: ID!): Boolean!
|
||||||
sceneMarkersDestroy(ids: [ID!]!): Boolean!
|
sceneMarkersDestroy(ids: [ID!]!): Boolean!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,13 @@ input SceneMarkerUpdateInput {
|
||||||
tag_ids: [ID!]
|
tag_ids: [ID!]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input BulkSceneMarkerUpdateInput {
|
||||||
|
ids: [ID!]
|
||||||
|
title: String
|
||||||
|
primary_tag_id: ID
|
||||||
|
tag_ids: BulkUpdateIds
|
||||||
|
}
|
||||||
|
|
||||||
type FindSceneMarkersResultType {
|
type FindSceneMarkersResultType {
|
||||||
count: Int!
|
count: Int!
|
||||||
scene_markers: [SceneMarker!]!
|
scene_markers: [SceneMarker!]!
|
||||||
|
|
|
||||||
|
|
@ -820,6 +820,123 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input SceneMar
|
||||||
return r.getSceneMarker(ctx, markerID)
|
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) {
|
func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (bool, error) {
|
||||||
return r.SceneMarkersDestroy(ctx, []string{id})
|
return r.SceneMarkersDestroy(ctx, []string{id})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ type SceneMarkerPartial struct {
|
||||||
Seconds OptionalFloat64
|
Seconds OptionalFloat64
|
||||||
EndSeconds OptionalFloat64
|
EndSeconds OptionalFloat64
|
||||||
PrimaryTagID OptionalInt
|
PrimaryTagID OptionalInt
|
||||||
|
TagIDs *UpdateIDs
|
||||||
SceneID OptionalInt
|
SceneID OptionalInt
|
||||||
CreatedAt OptionalTime
|
CreatedAt OptionalTime
|
||||||
UpdatedAt OptionalTime
|
UpdatedAt OptionalTime
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,11 @@ import (
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
const sceneMarkerTable = "scene_markers"
|
const (
|
||||||
|
sceneMarkerTable = "scene_markers"
|
||||||
|
sceneMarkersTagsTable = "scene_markers_tags"
|
||||||
|
sceneMarkerIDColumn = "scene_marker_id"
|
||||||
|
)
|
||||||
|
|
||||||
const countSceneMarkersForTagQuery = `
|
const countSceneMarkersForTagQuery = `
|
||||||
SELECT scene_markers.id FROM scene_markers
|
SELECT scene_markers.id FROM scene_markers
|
||||||
|
|
@ -101,8 +105,8 @@ var (
|
||||||
},
|
},
|
||||||
tags: joinRepository{
|
tags: joinRepository{
|
||||||
repository: repository{
|
repository: repository{
|
||||||
tableName: "scene_markers_tags",
|
tableName: sceneMarkersTagsTable,
|
||||||
idColumn: "scene_marker_id",
|
idColumn: sceneMarkerIDColumn,
|
||||||
},
|
},
|
||||||
fkColumn: tagIDColumn,
|
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)
|
return qb.find(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ var (
|
||||||
scenesGroupsJoinTable = goqu.T(groupsScenesTable)
|
scenesGroupsJoinTable = goqu.T(groupsScenesTable)
|
||||||
scenesURLsJoinTable = goqu.T(scenesURLsTable)
|
scenesURLsJoinTable = goqu.T(scenesURLsTable)
|
||||||
|
|
||||||
|
sceneMarkersTagsJoinTable = goqu.T(sceneMarkersTagsTable)
|
||||||
|
|
||||||
performersAliasesJoinTable = goqu.T(performersAliasesTable)
|
performersAliasesJoinTable = goqu.T(performersAliasesTable)
|
||||||
performersURLsJoinTable = goqu.T(performerURLsTable)
|
performersURLsJoinTable = goqu.T(performerURLsTable)
|
||||||
performersTagsJoinTable = goqu.T(performersTagsTable)
|
performersTagsJoinTable = goqu.T(performersTagsTable)
|
||||||
|
|
@ -160,6 +162,16 @@ var (
|
||||||
idColumn: goqu.T(sceneMarkerTable).Col(idColumn),
|
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{
|
scenesFilesTableMgr = &relatedFilesTable{
|
||||||
table: table{
|
table: table{
|
||||||
table: scenesFilesJoinTable,
|
table: scenesFilesJoinTable,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue