Annotations: Improve updating annotation tags queries (#71201)

Annotations: Improve annotation tag updates
This commit is contained in:
Emil Tullstedt
2023-07-31 17:19:59 +02:00
committed by GitHub
parent cdfbcb2ec6
commit ab0a115372
2 changed files with 83 additions and 29 deletions

View File

@@ -66,7 +66,7 @@ func (r *xormRepositoryImpl) Add(ctx context.Context, item *annotations.Item) er
if _, err := sess.Table("annotation").Insert(item); err != nil {
return err
}
return r.synchronizeTags(ctx, item)
return r.ensureTags(ctx, item.ID, item.Tags)
})
}
@@ -115,7 +115,8 @@ func (r *xormRepositoryImpl) AddMany(ctx context.Context, items []annotations.It
if _, err := sess.Table("annotation").Insert(item); err != nil {
return err
}
if err := r.synchronizeTags(ctx, &hasTags[i]); err != nil {
itemWithID := &hasTags[i]
if err := r.ensureTags(ctx, itemWithID.ID, itemWithID.Tags); err != nil {
return err
}
}
@@ -124,24 +125,6 @@ func (r *xormRepositoryImpl) AddMany(ctx context.Context, items []annotations.It
})
}
func (r *xormRepositoryImpl) synchronizeTags(ctx context.Context, item *annotations.Item) error {
// Will re-use session if one has already been opened with the same ctx.
return r.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
if item.Tags != nil {
tags, err := r.tagService.EnsureTagsExist(ctx, tag.ParseTagPairs(item.Tags))
if err != nil {
return err
}
for _, tag := range tags {
if _, err := sess.Exec("INSERT INTO annotation_tag (annotation_id, tag_id) VALUES(?,?)", item.ID, tag.Id); err != nil {
return err
}
}
}
return nil
})
}
func (r *xormRepositoryImpl) Update(ctx context.Context, item *annotations.Item) error {
return r.db.InTransaction(ctx, func(ctx context.Context) error {
return r.update(ctx, item)
@@ -180,18 +163,10 @@ func (r *xormRepositoryImpl) update(ctx context.Context, item *annotations.Item)
}
if item.Tags != nil {
tags, err := r.tagService.EnsureTagsExist(ctx, tag.ParseTagPairs(item.Tags))
err := r.ensureTags(ctx, existing.ID, item.Tags)
if err != nil {
return err
}
if _, err := sess.Exec("DELETE FROM annotation_tag WHERE annotation_id = ?", existing.ID); err != nil {
return err
}
for _, tag := range tags {
if _, err := sess.Exec("INSERT INTO annotation_tag (annotation_id, tag_id) VALUES(?,?)", existing.ID, tag.Id); err != nil {
return err
}
}
}
existing.Tags = item.Tags
@@ -205,6 +180,63 @@ func (r *xormRepositoryImpl) update(ctx context.Context, item *annotations.Item)
})
}
func (r *xormRepositoryImpl) ensureTags(ctx context.Context, annotationID int64, tags []string) error {
return r.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
var tagsInsert []annotationTag
var tagsDelete []int64
expectedTags, err := r.tagService.EnsureTagsExist(ctx, tag.ParseTagPairs(tags))
if err != nil {
return err
}
expected := tagSet(func(t *tag.Tag) int64 {
return t.Id
}, expectedTags)
existingTags := make([]annotationTag, 0)
if err := sess.SQL("SELECT annotation_id, tag_id FROM annotation_tag WHERE annotation_id = ?", annotationID).Find(&existingTags); err != nil {
return err
}
existing := tagSet(func(t annotationTag) int64 {
return t.TagID
}, existingTags)
for t := range expected {
if _, exists := existing[t]; !exists {
tagsInsert = append(tagsInsert, annotationTag{
AnnotationID: annotationID,
TagID: t,
})
}
}
for t := range existing {
if _, exists := expected[t]; !exists {
tagsDelete = append(tagsDelete, t)
}
}
if len(tagsDelete) != 0 {
if _, err := sess.MustCols("annotation_id", "tag_id").In("tag_id", tagsDelete).Delete(annotationTag{AnnotationID: annotationID}); err != nil {
return err
}
}
if len(tagsInsert) != 0 {
if _, err := sess.InsertMulti(tagsInsert); err != nil {
return err
}
}
return nil
})
}
func tagSet[T any](fn func(T) int64, list []T) map[int64]struct{} {
set := make(map[int64]struct{}, len(list))
for _, item := range list {
set[fn(item)] = struct{}{}
}
return set
}
func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
var sql bytes.Buffer
params := make([]interface{}, 0)
@@ -574,3 +606,8 @@ func (r *xormRepositoryImpl) executeUntilDoneOrCancelled(ctx context.Context, sq
}
}
}
type annotationTag struct {
AnnotationID int64 `xorm:"annotation_id"`
TagID int64 `xorm:"tag_id"`
}