server/tags: fix merging tags

It violated unique constraint on post_tag when a given post was already
tagged with the target tag.
This commit is contained in:
rr- 2016-07-03 15:48:39 +02:00
parent af36c90618
commit 5800f0ebc7
2 changed files with 35 additions and 4 deletions

View file

@ -157,10 +157,19 @@ def delete(source_tag):
db.session.delete(source_tag)
def merge_tags(source_tag, target_tag):
db.session.execute(
sqlalchemy.sql.expression.update(db.PostTag) \
.where(db.PostTag.tag_id == source_tag.tag_id) \
.values(tag_id=target_tag.tag_id))
pt1 = sqlalchemy.orm.util.aliased(db.PostTag)
pt2 = sqlalchemy.orm.util.aliased(db.PostTag)
ids_to_be_tagged = sqlalchemy.sql.expression \
.select([pt1.tag_id]) \
.where(pt1.tag_id == source_tag.tag_id) \
.where(~sqlalchemy.exists() \
.where(pt2.post_id == pt1.post_id) \
.where(pt2.tag_id == target_tag.tag_id))
update_stmt = sqlalchemy.sql.expression.update(db.PostTag) \
.where(db.PostTag.tag_id.in_(ids_to_be_tagged)) \
.values(tag_id=target_tag.tag_id)
db.session.execute(update_stmt)
delete(source_tag)
def create_tag(names, category_name, suggestions, implications):

View file

@ -98,6 +98,28 @@ def test_merging_when_related(test_ctx, fake_datetime):
assert tags.try_get_tag_by_name('parent').implications == []
assert tags.try_get_tag_by_name('parent').suggestions == []
def test_merging_when_target_exists(test_ctx, fake_datetime, post_factory):
source_tag = test_ctx.tag_factory(names=['source'], category_name='meta')
target_tag = test_ctx.tag_factory(names=['target'], category_name='meta')
db.session.add_all([source_tag, target_tag])
db.session.flush()
post1 = post_factory()
post1.tags = [source_tag, target_tag]
db.session.add_all([post1])
db.session.commit()
assert source_tag.post_count == 1
assert target_tag.post_count == 1
with fake_datetime('1997-12-01'):
result = test_ctx.api.post(
test_ctx.context_factory(
input={
'remove': 'source',
'mergeTo': 'target',
},
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)))
assert tags.try_get_tag_by_name('source') is None
assert tags.get_tag_by_name('target').post_count == 1
@pytest.mark.parametrize('input,expected_exception', [
({'remove': None}, tags.TagNotFoundError),
({'remove': ''}, tags.TagNotFoundError),