server/db: introduce tags
This commit is contained in:
parent
3bf9d6b462
commit
ec4cba94a9
8 changed files with 236 additions and 14 deletions
|
@ -1,4 +1,3 @@
|
||||||
''' Database layer. '''
|
|
||||||
|
|
||||||
from szurubooru.db.base import Base
|
from szurubooru.db.base import Base
|
||||||
from szurubooru.db.user import User
|
from szurubooru.db.user import User
|
||||||
|
from szurubooru.db.tag import Tag, TagName, TagSuggestion, TagImplication
|
||||||
|
|
59
server/szurubooru/db/tag.py
Normal file
59
server/szurubooru/db/tag.py
Normal 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
|
|
@ -1,4 +1,4 @@
|
||||||
import sqlalchemy as sa
|
from sqlalchemy import Column, Integer, String, DateTime
|
||||||
from szurubooru.db.base import Base
|
from szurubooru.db.base import Base
|
||||||
|
|
||||||
class User(Base):
|
class User(Base):
|
||||||
|
@ -7,13 +7,13 @@ class User(Base):
|
||||||
AVATAR_GRAVATAR = 'gravatar'
|
AVATAR_GRAVATAR = 'gravatar'
|
||||||
AVATAR_MANUAL = 'manual'
|
AVATAR_MANUAL = 'manual'
|
||||||
|
|
||||||
user_id = sa.Column('id', sa.Integer, primary_key=True)
|
user_id = Column('id', Integer, primary_key=True)
|
||||||
name = sa.Column('name', sa.String(50), nullable=False, unique=True)
|
name = Column('name', String(50), nullable=False, unique=True)
|
||||||
password_hash = sa.Column('password_hash', sa.String(64), nullable=False)
|
password_hash = Column('password_hash', String(64), nullable=False)
|
||||||
password_salt = sa.Column('password_salt', sa.String(32))
|
password_salt = Column('password_salt', String(32))
|
||||||
email = sa.Column('email', sa.String(200), nullable=True)
|
email = Column('email', String(200), nullable=True)
|
||||||
rank = sa.Column('rank', sa.String(32), nullable=False)
|
rank = Column('rank', String(32), nullable=False)
|
||||||
creation_time = sa.Column('creation_time', sa.DateTime, nullable=False)
|
creation_time = Column('creation_time', DateTime, nullable=False)
|
||||||
last_login_time = sa.Column('last_login_time', sa.DateTime)
|
last_login_time = Column('last_login_time', DateTime)
|
||||||
avatar_style = sa.Column(
|
avatar_style = Column(
|
||||||
'avatar_style', sa.String(32), nullable=False, default=AVATAR_GRAVATAR)
|
'avatar_style', String(32), nullable=False, default=AVATAR_GRAVATAR)
|
||||||
|
|
|
@ -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')
|
|
@ -48,3 +48,13 @@ def user_factory():
|
||||||
user.avatar_style = db.User.AVATAR_GRAVATAR
|
user.avatar_style = db.User.AVATAR_GRAVATAR
|
||||||
return user
|
return user
|
||||||
return factory
|
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
|
||||||
|
|
79
server/szurubooru/tests/db/test_tag.py
Normal file
79
server/szurubooru/tests/db/test_tag.py
Normal 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
|
21
server/szurubooru/tests/db/test_user.py
Normal file
21
server/szurubooru/tests/db/test_user.py
Normal 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
|
|
@ -1 +0,0 @@
|
||||||
''' Cool functions. '''
|
|
Loading…
Reference in a new issue