summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorrr- <rr-@sakuya.pl>2016-04-19 15:45:12 +0200
committerrr- <rr-@sakuya.pl>2016-04-19 15:51:26 +0200
commitfe56e376f68c50fd4e1b92b178e2ee2813128dc2 (patch)
tree1eb5f74d3c34f0261ac907c743f7da5d42cb1998 /server
parent884747bbbd0addb4d913037d6ce4d4f071cf835d (diff)
server/tags: export also tag categories
Diffstat (limited to 'server')
-rw-r--r--server/szurubooru/db/tag.py10
-rw-r--r--server/szurubooru/search/search_executor.py10
-rw-r--r--server/szurubooru/tests/api/test_tag_export.py60
-rw-r--r--server/szurubooru/tests/conftest.py32
-rw-r--r--server/szurubooru/util/tags.py23
5 files changed, 103 insertions, 32 deletions
diff --git a/server/szurubooru/db/tag.py b/server/szurubooru/db/tag.py
index bf98745..55e1857 100644
--- a/server/szurubooru/db/tag.py
+++ b/server/szurubooru/db/tag.py
@@ -47,18 +47,20 @@ class Tag(Base):
creation_time = Column('creation_time', DateTime, nullable=False)
last_edit_time = Column('last_edit_time', DateTime)
- category = relationship('TagCategory')
- names = relationship('TagName', cascade='all, delete-orphan')
+ category = relationship('TagCategory', lazy='joined')
+ names = relationship('TagName', cascade='all, delete-orphan', lazy='joined')
suggestions = relationship(
'Tag',
secondary='tag_suggestion',
primaryjoin=tag_id == TagSuggestion.parent_id,
- secondaryjoin=tag_id == TagSuggestion.child_id)
+ secondaryjoin=tag_id == TagSuggestion.child_id,
+ lazy='joined')
implications = relationship(
'Tag',
secondary='tag_implication',
primaryjoin=tag_id == TagImplication.parent_id,
- secondaryjoin=tag_id == TagImplication.child_id)
+ secondaryjoin=tag_id == TagImplication.child_id,
+ lazy='joined')
post_count = column_property(
select([func.count('Post.post_id')]) \
diff --git a/server/szurubooru/search/search_executor.py b/server/szurubooru/search/search_executor.py
index 04d1aa8..d441cd2 100644
--- a/server/szurubooru/search/search_executor.py
+++ b/server/szurubooru/search/search_executor.py
@@ -21,13 +21,17 @@ class SearchExecutor(object):
entities = filter_query \
.offset((page - 1) * page_size).limit(page_size).all()
count_query = filter_query.statement \
- .with_only_columns([sqlalchemy.func.count()]).order_by(None)
- count = filter_query.session.execute(count_query).scalar()
+ .with_only_columns([sqlalchemy.func.count()]) \
+ .order_by(None)
+ count = filter_query \
+ .session.execute(count_query) \
+ .scalar()
return (count, entities)
def _prepare(self, query_text):
''' Parse input and return SQLAlchemy query. '''
- query = self._search_config.create_query()
+ query = self._search_config.create_query() \
+ .options(sqlalchemy.orm.lazyload('*'))
for token in re.split(r'\s+', (query_text or '').lower()):
if not token:
continue
diff --git a/server/szurubooru/tests/api/test_tag_export.py b/server/szurubooru/tests/api/test_tag_export.py
index 0840acf..3e0eb1c 100644
--- a/server/szurubooru/tests/api/test_tag_export.py
+++ b/server/szurubooru/tests/api/test_tag_export.py
@@ -4,17 +4,27 @@ import json
from szurubooru import config, db
from szurubooru.util import tags
-def test_export(tmpdir, session, config_injector, tag_factory):
+def test_export(
+ tmpdir,
+ query_counter,
+ session,
+ config_injector,
+ tag_factory,
+ tag_category_factory):
config_injector({
'data_dir': str(tmpdir)
})
- sug1 = tag_factory(names=['sug1'])
- sug2 = tag_factory(names=['sug2'])
- imp1 = tag_factory(names=['imp1'])
- imp2 = tag_factory(names=['imp2'])
- tag = tag_factory(names=['alias1', 'alias2'])
+ cat1 = tag_category_factory(name='cat1', color='black')
+ cat2 = tag_category_factory(name='cat2', color='white')
+ session.add_all([cat1, cat2])
+ session.flush()
+ sug1 = tag_factory(names=['sug1'], category=cat1)
+ sug2 = tag_factory(names=['sug2'], category=cat1)
+ imp1 = tag_factory(names=['imp1'], category=cat1)
+ imp2 = tag_factory(names=['imp2'], category=cat1)
+ tag = tag_factory(names=['alias1', 'alias2'], category=cat2)
tag.post_count = 1
- session.add_all([tag, sug1, sug2, imp1, imp2])
+ session.add_all([tag, sug1, sug2, imp1, imp2, cat1, cat2])
session.flush()
session.add_all([
db.TagSuggestion(tag.tag_id, sug1.tag_id),
@@ -24,19 +34,29 @@ def test_export(tmpdir, session, config_injector, tag_factory):
])
session.flush()
- tags.export_to_json()
+ with query_counter:
+ tags.export_to_json()
+ assert len(query_counter.statements) == 2
+
export_path = os.path.join(config.config['data_dir'], 'tags.json')
assert os.path.exists(export_path)
with open(export_path, 'r') as handle:
- assert json.loads(handle.read()) == [
- {
- 'names': ['alias1', 'alias2'],
- 'usages': 1,
- 'suggestions': ['sug1', 'sug2'],
- 'implications': ['imp1', 'imp2'],
- },
- {'names': ['sug1'], 'usages': 0},
- {'names': ['sug2'], 'usages': 0},
- {'names': ['imp1'], 'usages': 0},
- {'names': ['imp2'], 'usages': 0},
- ]
+ assert json.loads(handle.read()) == {
+ 'tags': [
+ {
+ 'names': ['alias1', 'alias2'],
+ 'usages': 1,
+ 'category': 'cat2',
+ 'suggestions': ['sug1', 'sug2'],
+ 'implications': ['imp1', 'imp2'],
+ },
+ {'names': ['sug1'], 'usages': 0, 'category': 'cat1'},
+ {'names': ['sug2'], 'usages': 0, 'category': 'cat1'},
+ {'names': ['imp1'], 'usages': 0, 'category': 'cat1'},
+ {'names': ['imp2'], 'usages': 0, 'category': 'cat1'},
+ ],
+ 'categories': [
+ {'name': 'cat1', 'color': 'black'},
+ {'name': 'cat2', 'color': 'white'},
+ ]
+ }
diff --git a/server/szurubooru/tests/conftest.py b/server/szurubooru/tests/conftest.py
index 2981e10..6b70fa7 100644
--- a/server/szurubooru/tests/conftest.py
+++ b/server/szurubooru/tests/conftest.py
@@ -7,6 +7,32 @@ import sqlalchemy
from szurubooru import api, config, db
from szurubooru.util import misc
+class QueryCounter(object):
+ def __init__(self):
+ self._statements = []
+
+ def __enter__(self):
+ self._statements = []
+
+ def __exit__(self, *args, **kwargs):
+ self._statements = []
+
+ def create_before_cursor_execute(self):
+ def before_cursor_execute(
+ _conn, _cursor, statement, _parameters, _context, _executemany):
+ self._statements.append(statement)
+ return before_cursor_execute
+
+ @property
+ def statements(self):
+ return self._statements
+
+_query_counter = QueryCounter()
+
+@pytest.fixture
+def query_counter():
+ return _query_counter
+
def get_unique_name():
return str(uuid.uuid4())
@@ -21,11 +47,15 @@ def fake_datetime():
return injector
@pytest.yield_fixture
-def session(autoload=True):
+def session(query_counter, autoload=True):
import logging
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
engine = sqlalchemy.create_engine('sqlite:///:memory:')
+ sqlalchemy.event.listen(
+ engine,
+ 'before_cursor_execute',
+ query_counter.create_before_cursor_execute())
session_maker = sqlalchemy.orm.sessionmaker(bind=engine)
session = sqlalchemy.orm.scoped_session(session_maker)
db.Base.query = session.query_property()
diff --git a/server/szurubooru/util/tags.py b/server/szurubooru/util/tags.py
index 24b8cad..69cc95e 100644
--- a/server/szurubooru/util/tags.py
+++ b/server/szurubooru/util/tags.py
@@ -28,11 +28,21 @@ def _check_name_intersection(names1, names2):
return len(set(_lower_list(names1)).intersection(_lower_list(names2))) > 0
def export_to_json():
- output = []
- for tag in db.session().query(db.Tag).all():
+ output = {
+ 'tags': [],
+ 'categories': [],
+ }
+ all_tags = db.session() \
+ .query(db.Tag) \
+ .options(
+ sqlalchemy.orm.joinedload('suggestions'),
+ sqlalchemy.orm.joinedload('implications')) \
+ .all()
+ for tag in all_tags:
item = {
'names': [tag_name.name for tag_name in tag.names],
- 'usages': tag.post_count
+ 'usages': tag.post_count,
+ 'category': tag.category.name,
}
if len(tag.suggestions):
item['suggestions'] = \
@@ -40,7 +50,12 @@ def export_to_json():
if len(tag.implications):
item['implications'] = \
[rel.names[0].name for rel in tag.implications]
- output.append(item)
+ output['tags'].append(item)
+ for category in tag_categories.get_all_categories():
+ output['categories'].append({
+ 'name': category.name,
+ 'color': category.color,
+ })
export_path = os.path.join(config.config['data_dir'], 'tags.json')
with open(export_path, 'w') as handle:
handle.write(json.dumps(output, separators=(',', ':')))