server/tags: simplify relations model
This commit is contained in:
parent
888e8e1aa7
commit
9ac70dbed4
|
@ -8,9 +8,9 @@ def _serialize_tag(tag):
|
||||||
'names': [tag_name.name for tag_name in tag.names],
|
'names': [tag_name.name for tag_name in tag.names],
|
||||||
'category': tag.category,
|
'category': tag.category,
|
||||||
'suggestions': [
|
'suggestions': [
|
||||||
relation.child_tag.names[0].name for relation in tag.suggestions],
|
relation.names[0].name for relation in tag.suggestions],
|
||||||
'implications': [
|
'implications': [
|
||||||
relation.child_tag.names[0].name for relation in tag.implications],
|
relation.names[0].name for relation in tag.implications],
|
||||||
'creationTime': tag.creation_time,
|
'creationTime': tag.creation_time,
|
||||||
'lastEditTime': tag.last_edit_time,
|
'lastEditTime': tag.last_edit_time,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,56 +4,53 @@ from szurubooru.db.base import Base
|
||||||
|
|
||||||
class TagSuggestion(Base):
|
class TagSuggestion(Base):
|
||||||
__tablename__ = 'tag_suggestion'
|
__tablename__ = 'tag_suggestion'
|
||||||
|
|
||||||
parent_id = Column('parent_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
parent_id = Column('parent_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
||||||
child_id = Column('child_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
child_id = Column('child_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
||||||
|
|
||||||
def __init__(self, parent_id, child_id):
|
def __init__(self, parent_id, child_id):
|
||||||
self.parent_id = parent_id
|
self.parent_id = parent_id
|
||||||
self.child_id = child_id
|
self.child_id = child_id
|
||||||
|
|
||||||
class TagImplication(Base):
|
class TagImplication(Base):
|
||||||
__tablename__ = 'tag_implication'
|
__tablename__ = 'tag_implication'
|
||||||
|
|
||||||
parent_id = Column('parent_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
parent_id = Column('parent_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
||||||
child_id = Column('child_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
child_id = Column('child_id', Integer, ForeignKey('tag.id'), primary_key=True)
|
||||||
|
|
||||||
def __init__(self, parent_id, child_id):
|
def __init__(self, parent_id, child_id):
|
||||||
self.parent_id = parent_id
|
self.parent_id = parent_id
|
||||||
self.child_id = child_id
|
self.child_id = child_id
|
||||||
|
|
||||||
class Tag(Base):
|
|
||||||
__tablename__ = 'tag'
|
|
||||||
tag_id = Column('id', Integer, primary_key=True)
|
|
||||||
category = Column('category', String(32), nullable=False)
|
|
||||||
creation_time = Column('creation_time', DateTime, nullable=False)
|
|
||||||
last_edit_time = Column('last_edit_time', DateTime)
|
|
||||||
post_count = Column('auto_post_count', Integer, nullable=False, default=0)
|
|
||||||
names = relationship('TagName', cascade='all, delete-orphan')
|
|
||||||
|
|
||||||
suggestions = relationship(
|
|
||||||
TagSuggestion,
|
|
||||||
backref='parent_tag',
|
|
||||||
primaryjoin=tag_id == TagSuggestion.parent_id,
|
|
||||||
cascade='all, delete-orphan')
|
|
||||||
suggested_by = relationship(
|
|
||||||
TagSuggestion,
|
|
||||||
backref='child_tag',
|
|
||||||
primaryjoin=tag_id == TagSuggestion.child_id,
|
|
||||||
cascade='all, delete-orphan')
|
|
||||||
|
|
||||||
implications = relationship(
|
|
||||||
TagImplication,
|
|
||||||
backref='parent_tag',
|
|
||||||
primaryjoin=tag_id == TagImplication.parent_id,
|
|
||||||
cascade='all, delete-orphan')
|
|
||||||
implied_by = relationship(
|
|
||||||
TagImplication,
|
|
||||||
backref='child_tag',
|
|
||||||
primaryjoin=tag_id == TagImplication.child_id,
|
|
||||||
cascade='all, delete-orphan')
|
|
||||||
|
|
||||||
class TagName(Base):
|
class TagName(Base):
|
||||||
__tablename__ = 'tag_name'
|
__tablename__ = 'tag_name'
|
||||||
|
|
||||||
tag_name_id = Column('tag_name_id', Integer, primary_key=True)
|
tag_name_id = Column('tag_name_id', Integer, primary_key=True)
|
||||||
tag_id = Column('tag_id', Integer, ForeignKey('tag.id'))
|
tag_id = Column('tag_id', Integer, ForeignKey('tag.id'))
|
||||||
name = Column('name', String(64), nullable=False, unique=True)
|
name = Column('name', String(64), nullable=False, unique=True)
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
|
class Tag(Base):
|
||||||
|
__tablename__ = 'tag'
|
||||||
|
|
||||||
|
tag_id = Column('id', Integer, primary_key=True)
|
||||||
|
category = Column('category', String(32), nullable=False)
|
||||||
|
creation_time = Column('creation_time', DateTime, nullable=False)
|
||||||
|
last_edit_time = Column('last_edit_time', DateTime)
|
||||||
|
|
||||||
|
names = relationship('TagName', cascade='all, delete-orphan')
|
||||||
|
suggestions = relationship(
|
||||||
|
'Tag',
|
||||||
|
secondary='tag_suggestion',
|
||||||
|
primaryjoin=tag_id == TagSuggestion.parent_id,
|
||||||
|
secondaryjoin=tag_id == TagSuggestion.child_id)
|
||||||
|
implications = relationship(
|
||||||
|
'Tag',
|
||||||
|
secondary='tag_implication',
|
||||||
|
primaryjoin=tag_id == TagImplication.parent_id,
|
||||||
|
secondaryjoin=tag_id == TagImplication.child_id)
|
||||||
|
|
||||||
|
# TODO: wire this
|
||||||
|
post_count = Column('auto_post_count', Integer, nullable=False, default=0)
|
||||||
|
|
|
@ -11,7 +11,7 @@ def get_tag(session, name):
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
def assert_relations(relations, expected_tag_names):
|
def assert_relations(relations, expected_tag_names):
|
||||||
actual_names = [rel.child_tag.names[0].name for rel in relations]
|
actual_names = [rel.names[0].name for rel in relations]
|
||||||
assert actual_names == expected_tag_names
|
assert actual_names == expected_tag_names
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
|
@ -11,7 +11,7 @@ def get_tag(session, name):
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
def assert_relations(relations, expected_tag_names):
|
def assert_relations(relations, expected_tag_names):
|
||||||
actual_names = [rel.child_tag.names[0].name for rel in relations]
|
actual_names = [rel.names[0].name for rel in relations]
|
||||||
assert actual_names == expected_tag_names
|
assert actual_names == expected_tag_names
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
|
@ -23,10 +23,10 @@ def test_saving_tag(session, tag_factory):
|
||||||
assert suggested_tag2.tag_id is not None
|
assert suggested_tag2.tag_id is not None
|
||||||
assert implied_tag1.tag_id is not None
|
assert implied_tag1.tag_id is not None
|
||||||
assert implied_tag2.tag_id is not None
|
assert implied_tag2.tag_id is not None
|
||||||
tag.suggestions.append(db.TagSuggestion(tag.tag_id, suggested_tag1.tag_id))
|
tag.suggestions.append(suggested_tag1)
|
||||||
tag.suggestions.append(db.TagSuggestion(tag.tag_id, suggested_tag2.tag_id))
|
tag.suggestions.append(suggested_tag2)
|
||||||
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag1.tag_id))
|
tag.implications.append(implied_tag1)
|
||||||
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag2.tag_id))
|
tag.implications.append(implied_tag2)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
tag = session.query(db.Tag) \
|
tag = session.query(db.Tag) \
|
||||||
|
@ -38,9 +38,9 @@ def test_saving_tag(session, tag_factory):
|
||||||
assert tag.creation_time == datetime(1997, 1, 1)
|
assert tag.creation_time == datetime(1997, 1, 1)
|
||||||
assert tag.last_edit_time == datetime(1998, 1, 1)
|
assert tag.last_edit_time == datetime(1998, 1, 1)
|
||||||
assert tag.post_count == 1
|
assert tag.post_count == 1
|
||||||
assert [relation.child_tag.names[0].name for relation in tag.suggestions] \
|
assert [relation.names[0].name for relation in tag.suggestions] \
|
||||||
== ['suggested1', 'suggested2']
|
== ['suggested1', 'suggested2']
|
||||||
assert [relation.child_tag.names[0].name for relation in tag.implications] \
|
assert [relation.names[0].name for relation in tag.implications] \
|
||||||
== ['implied1', 'implied2']
|
== ['implied1', 'implied2']
|
||||||
|
|
||||||
def test_cascade_deletions(session, tag_factory):
|
def test_cascade_deletions(session, tag_factory):
|
||||||
|
@ -65,10 +65,10 @@ def test_cascade_deletions(session, tag_factory):
|
||||||
assert suggested_tag2.tag_id is not None
|
assert suggested_tag2.tag_id is not None
|
||||||
assert implied_tag1.tag_id is not None
|
assert implied_tag1.tag_id is not None
|
||||||
assert implied_tag2.tag_id is not None
|
assert implied_tag2.tag_id is not None
|
||||||
tag.suggestions.append(db.TagSuggestion(tag.tag_id, suggested_tag1.tag_id))
|
tag.suggestions.append(suggested_tag1)
|
||||||
tag.suggestions.append(db.TagSuggestion(tag.tag_id, suggested_tag2.tag_id))
|
tag.suggestions.append(suggested_tag2)
|
||||||
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag1.tag_id))
|
tag.implications.append(implied_tag1)
|
||||||
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag2.tag_id))
|
tag.implications.append(implied_tag2)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
session.delete(tag)
|
session.delete(tag)
|
||||||
|
|
|
@ -133,9 +133,9 @@ def test_order_by_suggestion_count(
|
||||||
tag2 = tag_factory(names=['t2'])
|
tag2 = tag_factory(names=['t2'])
|
||||||
session.add_all([sug1, sug3, tag2, sug2, tag1])
|
session.add_all([sug1, sug3, tag2, sug2, tag1])
|
||||||
session.commit()
|
session.commit()
|
||||||
tag1.suggestions.append(db.TagSuggestion(tag1.tag_id, sug1.tag_id))
|
tag1.suggestions.append(sug1)
|
||||||
tag1.suggestions.append(db.TagSuggestion(tag1.tag_id, sug2.tag_id))
|
tag1.suggestions.append(sug2)
|
||||||
tag2.suggestions.append(db.TagSuggestion(tag2.tag_id, sug3.tag_id))
|
tag2.suggestions.append(sug3)
|
||||||
verify_unpaged(input, expected_tag_names)
|
verify_unpaged(input, expected_tag_names)
|
||||||
|
|
||||||
@pytest.mark.parametrize('input,expected_tag_names', [
|
@pytest.mark.parametrize('input,expected_tag_names', [
|
||||||
|
@ -150,9 +150,9 @@ def test_order_by_implication_count(
|
||||||
tag2 = tag_factory(names=['t2'])
|
tag2 = tag_factory(names=['t2'])
|
||||||
session.add_all([sug1, sug3, tag2, sug2, tag1])
|
session.add_all([sug1, sug3, tag2, sug2, tag1])
|
||||||
session.commit()
|
session.commit()
|
||||||
tag1.implications.append(db.TagImplication(tag1.tag_id, sug1.tag_id))
|
tag1.implications.append(sug1)
|
||||||
tag1.implications.append(db.TagImplication(tag1.tag_id, sug2.tag_id))
|
tag1.implications.append(sug2)
|
||||||
tag2.implications.append(db.TagImplication(tag2.tag_id, sug3.tag_id))
|
tag2.implications.append(sug3)
|
||||||
verify_unpaged(input, expected_tag_names)
|
verify_unpaged(input, expected_tag_names)
|
||||||
|
|
||||||
def test_filter_by_relation_count(session, verify_unpaged, tag_factory):
|
def test_filter_by_relation_count(session, verify_unpaged, tag_factory):
|
||||||
|
|
|
@ -36,10 +36,10 @@ def export_to_json(session):
|
||||||
}
|
}
|
||||||
if len(tag.suggestions):
|
if len(tag.suggestions):
|
||||||
item['suggestions'] = \
|
item['suggestions'] = \
|
||||||
[rel.child_tag.names[0].name for rel in tag.suggestions]
|
[rel.names[0].name for rel in tag.suggestions]
|
||||||
if len(tag.implications):
|
if len(tag.implications):
|
||||||
item['implications'] = \
|
item['implications'] = \
|
||||||
[rel.child_tag.names[0].name for rel in tag.implications]
|
[rel.names[0].name for rel in tag.implications]
|
||||||
output.append(item)
|
output.append(item)
|
||||||
export_path = os.path.join(config.config['data_dir'], 'tags.json')
|
export_path = os.path.join(config.config['data_dir'], 'tags.json')
|
||||||
with open(export_path, 'w') as handle:
|
with open(export_path, 'w') as handle:
|
||||||
|
@ -131,15 +131,11 @@ def update_implications(session, tag, relations):
|
||||||
raise RelationError('Tag cannot imply itself.')
|
raise RelationError('Tag cannot imply itself.')
|
||||||
related_tags, new_tags = get_or_create_by_names(session, relations)
|
related_tags, new_tags = get_or_create_by_names(session, relations)
|
||||||
session.flush()
|
session.flush()
|
||||||
tag.implications = [
|
tag.implications = related_tags + new_tags
|
||||||
db.TagImplication(tag.tag_id, other_tag.tag_id) \
|
|
||||||
for other_tag in related_tags + new_tags]
|
|
||||||
|
|
||||||
def update_suggestions(session, tag, relations):
|
def update_suggestions(session, tag, relations):
|
||||||
if _check_name_intersection(_get_plain_names(tag), relations):
|
if _check_name_intersection(_get_plain_names(tag), relations):
|
||||||
raise RelationError('Tag cannot suggest itself.')
|
raise RelationError('Tag cannot suggest itself.')
|
||||||
related_tags, new_tags = get_or_create_by_names(session, relations)
|
related_tags, new_tags = get_or_create_by_names(session, relations)
|
||||||
session.flush()
|
session.flush()
|
||||||
tag.suggestions = [
|
tag.suggestions = related_tags + new_tags
|
||||||
db.TagSuggestion(tag.tag_id, other_tag.tag_id) \
|
|
||||||
for other_tag in related_tags + new_tags]
|
|
||||||
|
|
Loading…
Reference in New Issue