server/db: introduce tags

This commit is contained in:
rr- 2016-04-15 20:40:12 +02:00
parent 3bf9d6b462
commit ec4cba94a9
8 changed files with 236 additions and 14 deletions

View file

@ -1,4 +1,3 @@
''' Database layer. '''
from szurubooru.db.base import Base
from szurubooru.db.user import User
from szurubooru.db.tag import Tag, TagName, TagSuggestion, TagImplication

View file

@ -0,0 +1,59 @@
from sqlalchemy import Column, Integer, DateTime, String, ForeignKey
from sqlalchemy.orm import relationship
from szurubooru.db.base import Base
class TagSuggestion(Base):
__tablename__ = 'tag_suggestion'
parent_id = Column('parent_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):
self.parent_id = parent_id
self.child_id = child_id
class TagImplication(Base):
__tablename__ = 'tag_implication'
parent_id = Column('parent_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):
self.parent_id = parent_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('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):
__tablename__ = 'tag_name'
tag_name_id = Column('tag_name_id', Integer, primary_key=True)
tag_id = Column('tag_id', Integer, ForeignKey('tag.id'))
name = Column('name', String(50), nullable=False, unique=True)
def __init__(self, name):
self.name = name

View file

@ -1,4 +1,4 @@
import sqlalchemy as sa
from sqlalchemy import Column, Integer, String, DateTime
from szurubooru.db.base import Base
class User(Base):
@ -7,13 +7,13 @@ class User(Base):
AVATAR_GRAVATAR = 'gravatar'
AVATAR_MANUAL = 'manual'
user_id = sa.Column('id', sa.Integer, primary_key=True)
name = sa.Column('name', sa.String(50), nullable=False, unique=True)
password_hash = sa.Column('password_hash', sa.String(64), nullable=False)
password_salt = sa.Column('password_salt', sa.String(32))
email = sa.Column('email', sa.String(200), nullable=True)
rank = sa.Column('rank', sa.String(32), nullable=False)
creation_time = sa.Column('creation_time', sa.DateTime, nullable=False)
last_login_time = sa.Column('last_login_time', sa.DateTime)
avatar_style = sa.Column(
'avatar_style', sa.String(32), nullable=False, default=AVATAR_GRAVATAR)
user_id = Column('id', Integer, primary_key=True)
name = Column('name', String(50), nullable=False, unique=True)
password_hash = Column('password_hash', String(64), nullable=False)
password_salt = Column('password_salt', String(32))
email = Column('email', String(200), nullable=True)
rank = Column('rank', String(32), nullable=False)
creation_time = Column('creation_time', DateTime, nullable=False)
last_login_time = Column('last_login_time', DateTime)
avatar_style = Column(
'avatar_style', String(32), nullable=False, default=AVATAR_GRAVATAR)

View file

@ -0,0 +1,55 @@
'''
Create tags tables
Revision ID: 00cb3a2734db
Created at: 2016-04-15 23:15:36.255429
'''
import sqlalchemy as sa
from alembic import op
revision = '00cb3a2734db'
down_revision = 'e5c1216a8503'
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
'tag',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('category', sa.String(length=32), nullable=False),
sa.Column('creation_time', sa.DateTime(), nullable=False),
sa.Column('last_edit_time', sa.DateTime(), nullable=True),
sa.Column('post_count', sa.Integer(), nullable=False),
sa.PrimaryKeyConstraint('id'))
op.create_table(
'tag_name',
sa.Column('tag_name_id', sa.Integer(), nullable=False),
sa.Column('tag_id', sa.Integer(), nullable=True),
sa.Column('name', sa.String(length=50), nullable=False),
sa.ForeignKeyConstraint(['tag_id'], ['tag.id']),
sa.PrimaryKeyConstraint('tag_name_id'),
sa.UniqueConstraint('name'))
op.create_table(
'tag_implication',
sa.Column('parent_id', sa.Integer(), nullable=False),
sa.Column('child_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['parent_id'], ['tag.id']),
sa.ForeignKeyConstraint(['child_id'], ['tag.id']),
sa.PrimaryKeyConstraint('parent_id', 'child_id'))
op.create_table(
'tag_suggestion',
sa.Column('parent_id', sa.Integer(), nullable=False),
sa.Column('child_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['parent_id'], ['tag.id']),
sa.ForeignKeyConstraint(['child_id'], ['tag.id']),
sa.PrimaryKeyConstraint('parent_id', 'child_id'))
def downgrade():
op.drop_table('tag_suggestion')
op.drop_table('tag_name')
op.drop_table('tag_implication')
op.drop_table('tag')

View file

@ -48,3 +48,13 @@ def user_factory():
user.avatar_style = db.User.AVATAR_GRAVATAR
return user
return factory
@pytest.fixture
def tag_factory():
def factory(names=None, category='dummy'):
tag = db.Tag()
tag.names = [db.TagName(name) for name in (names or ['dummy'])]
tag.category = category
tag.creation_time = datetime(1996, 1, 1)
return tag
return factory

View file

@ -0,0 +1,79 @@
from datetime import datetime
from szurubooru import db
def test_saving_tag(session, tag_factory):
suggested_tag1 = tag_factory(names=['suggested1'])
suggested_tag2 = tag_factory(names=['suggested2'])
implied_tag1 = tag_factory(names=['implied1'])
implied_tag2 = tag_factory(names=['implied2'])
tag = db.Tag()
tag.names = [db.TagName('alias1'), db.TagName('alias2')]
tag.suggestions = []
tag.implications = []
tag.category = 'category'
tag.creation_time = datetime(1997, 1, 1)
tag.last_edit_time = datetime(1998, 1, 1)
tag.post_count = 1
session.add_all([
tag, suggested_tag1, suggested_tag2, implied_tag1, implied_tag2])
session.commit()
assert tag.tag_id is not None
assert suggested_tag1.tag_id is not None
assert suggested_tag2.tag_id is not None
assert implied_tag1.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(db.TagSuggestion(tag.tag_id, suggested_tag2.tag_id))
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag1.tag_id))
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag2.tag_id))
session.commit()
tag = session.query(db.Tag) \
.join(db.TagName) \
.filter(db.TagName.name=='alias1') \
.one()
assert [tag_name.name for tag_name in tag.names] == ['alias1', 'alias2']
assert tag.category == 'category'
assert tag.creation_time == datetime(1997, 1, 1)
assert tag.last_edit_time == datetime(1998, 1, 1)
assert tag.post_count == 1
assert [relation.child_tag.names[0].name for relation in tag.suggestions] \
== ['suggested1', 'suggested2']
assert [relation.child_tag.names[0].name for relation in tag.implications] \
== ['implied1', 'implied2']
def test_cascade_deletions(session, tag_factory):
suggested_tag1 = tag_factory(names=['suggested1'])
suggested_tag2 = tag_factory(names=['suggested2'])
implied_tag1 = tag_factory(names=['implied1'])
implied_tag2 = tag_factory(names=['implied2'])
tag = db.Tag()
tag.names = [db.TagName('alias1'), db.TagName('alias2')]
tag.suggestions = []
tag.implications = []
tag.category = 'category'
tag.creation_time = datetime(1997, 1, 1)
tag.last_edit_time = datetime(1998, 1, 1)
tag.post_count = 1
session.add_all([
tag, suggested_tag1, suggested_tag2, implied_tag1, implied_tag2])
session.commit()
assert tag.tag_id is not None
assert suggested_tag1.tag_id is not None
assert suggested_tag2.tag_id is not None
assert implied_tag1.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(db.TagSuggestion(tag.tag_id, suggested_tag2.tag_id))
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag1.tag_id))
tag.implications.append(db.TagImplication(tag.tag_id, implied_tag2.tag_id))
session.commit()
session.delete(tag)
session.commit()
assert session.query(db.Tag).count() == 4
assert session.query(db.TagName).count() == 4
assert session.query(db.TagImplication).count() == 0
assert session.query(db.TagSuggestion).count() == 0

View file

@ -0,0 +1,21 @@
from datetime import datetime
from szurubooru import db
def test_saving_user(session):
user = db.User()
user.name = 'name'
user.password_salt = 'salt'
user.password_hash = 'hash'
user.email = 'email'
user.rank = 'rank'
user.creation_time = datetime(1997, 1, 1)
user.avatar_style = db.User.AVATAR_GRAVATAR
session.add(user)
user = session.query(db.User).one()
assert user.name == 'name'
assert user.password_salt == 'salt'
assert user.password_hash == 'hash'
assert user.email == 'email'
assert user.rank == 'rank'
assert user.creation_time == datetime(1997, 1, 1)
assert user.avatar_style == db.User.AVATAR_GRAVATAR

View file

@ -1 +0,0 @@
''' Cool functions. '''