serevr/tags: fix search by post count and category

This commit is contained in:
rr- 2016-05-09 22:32:16 +02:00
parent 6405fbe9f2
commit fcbfa90879
3 changed files with 224 additions and 80 deletions

View file

@ -17,4 +17,4 @@ class TagCategory(Base):
tag_count = column_property( tag_count = column_property(
select([func.count('Tag.tag_id')]) \ select([func.count('Tag.tag_id')]) \
.where(Tag.category_id == tag_category_id) \ .where(Tag.category_id == tag_category_id) \
.correlate(table('TagCategory'))) .correlate_except(table('Tag')))

View file

@ -1,16 +1,19 @@
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from sqlalchemy.sql.expression import func from sqlalchemy.sql.expression import func
from szurubooru import db from szurubooru import db
from szurubooru.func import util
from szurubooru.search.base_search_config import BaseSearchConfig from szurubooru.search.base_search_config import BaseSearchConfig
class TagSearchConfig(BaseSearchConfig): class TagSearchConfig(BaseSearchConfig):
def create_filter_query(self): def create_filter_query(self):
return self.create_count_query().options( return self.create_count_query() \
joinedload(db.Tag.names), .join(db.TagCategory) \
joinedload(db.Tag.category), .options(
joinedload(db.Tag.suggestions).joinedload(db.Tag.names), joinedload(db.Tag.names),
joinedload(db.Tag.implications).joinedload(db.Tag.names) joinedload(db.Tag.category),
) joinedload(db.Tag.suggestions).joinedload(db.Tag.names),
joinedload(db.Tag.implications).joinedload(db.Tag.names)
)
def create_count_query(self): def create_count_query(self):
return db.session.query(db.Tag) return db.session.query(db.Tag)
@ -24,37 +27,35 @@ class TagSearchConfig(BaseSearchConfig):
@property @property
def named_filters(self): def named_filters(self):
return { return util.unalias_dict({
'name': self._create_str_filter(db.Tag.first_name), 'name': self._create_str_filter(db.Tag.first_name),
'category': self._create_str_filter(db.Tag.category), 'category': self._create_subquery_filter(
'creation-date': self._create_date_filter(db.Tag.creation_time), db.Tag.category_id,
'creation-time': self._create_date_filter(db.Tag.creation_time), db.TagCategory.tag_category_id,
'last-edit-date': self._create_date_filter(db.Tag.last_edit_time), db.TagCategory.name,
'last-edit-time': self._create_date_filter(db.Tag.last_edit_time), self._create_str_filter),
'edit-date': self._create_date_filter(db.Tag.last_edit_time), ('creation-date', 'creation-time'):
'edit-time': self._create_date_filter(db.Tag.last_edit_time), self._create_date_filter(db.Tag.creation_time),
'usages': self._create_num_filter(db.Tag.post_count), ('last-edit-date', 'last-edit-time', 'edit-date', 'edit-time'):
'usage-count': self._create_num_filter(db.Tag.post_count), self._create_date_filter(db.Tag.last_edit_time),
'post-count': self._create_num_filter(db.Tag.post_count), ('usage-count', 'post-count', 'usages'):
self._create_num_filter(db.Tag.post_count),
'suggestion-count': self._create_num_filter(db.Tag.suggestion_count), 'suggestion-count': self._create_num_filter(db.Tag.suggestion_count),
'implication-count': self._create_num_filter(db.Tag.implication_count), 'implication-count': self._create_num_filter(db.Tag.implication_count),
} })
@property @property
def sort_columns(self): def sort_columns(self):
return { return util.unalias_dict({
'random': (func.random(), None), 'random': (func.random(), None),
'name': (db.Tag.first_name, self.SORT_ASC), 'name': (db.Tag.first_name, self.SORT_ASC),
'category': (db.Tag.category, self.SORT_ASC), 'category': (db.TagCategory.name, self.SORT_ASC),
'creation-date': (db.Tag.creation_time, self.SORT_DESC), ('creation-date', 'creation-time'):
'creation-time': (db.Tag.creation_time, self.SORT_DESC), (db.Tag.creation_time, self.SORT_DESC),
'last-edit-date': (db.Tag.last_edit_time, self.SORT_DESC), ('last-edit-date', 'last-edit-time', 'edit-date', 'edit-time'):
'last-edit-time': (db.Tag.last_edit_time, self.SORT_DESC), (db.Tag.last_edit_time, self.SORT_DESC),
'edit-date': (db.Tag.last_edit_time, self.SORT_DESC), ('usage-count', 'post-count', 'usages'):
'edit-time': (db.Tag.last_edit_time, self.SORT_DESC), (db.Tag.post_count, self.SORT_DESC),
'usages': (db.Tag.post_count, self.SORT_DESC),
'usage-count': (db.Tag.post_count, self.SORT_DESC),
'post-count': (db.Tag.post_count, self.SORT_DESC),
'suggestion-count': (db.Tag.suggestion_count, self.SORT_DESC), 'suggestion-count': (db.Tag.suggestion_count, self.SORT_DESC),
'implication-count': (db.Tag.implication_count, self.SORT_DESC), 'implication-count': (db.Tag.implication_count, self.SORT_DESC),
} })

View file

@ -17,6 +17,63 @@ def verify_unpaged(executor):
assert actual_tag_names == expected_tag_names assert actual_tag_names == expected_tag_names
return verify return verify
@pytest.mark.parametrize('input,expected_tag_names', [
('', ['t1', 't2']),
('t1', ['t1']),
('t2', ['t2']),
('t1,t2', ['t1', 't2']),
])
def test_filter_anonymous(verify_unpaged, tag_factory, input, expected_tag_names):
db.session.add(tag_factory(names=['t1']))
db.session.add(tag_factory(names=['t2']))
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [
('name:tag1', ['tag1']),
('name:tag2', ['tag2']),
('name:none', []),
('name:', []),
('name:*1', ['tag1']),
('name:*2', ['tag2']),
('name:*', ['tag1', 'tag2', 'tag3', 'tag4']),
('name:t*', ['tag1', 'tag2', 'tag3', 'tag4']),
('name:*a*', ['tag1', 'tag2', 'tag3', 'tag4']),
('name:*!*', []),
('name:!*', []),
('name:*!', []),
('-name:tag1', ['tag2', 'tag3', 'tag4']),
('-name:tag2', ['tag1', 'tag3', 'tag4']),
('name:tag1,tag2', ['tag1', 'tag2']),
('-name:tag1,tag3', ['tag2', 'tag4']),
('name:tag4', ['tag4']),
('name:tag4,tag5', ['tag4']),
])
def test_filter_by_name(verify_unpaged, tag_factory, input, expected_tag_names):
db.session.add(tag_factory(names=['tag1']))
db.session.add(tag_factory(names=['tag2']))
db.session.add(tag_factory(names=['tag3']))
db.session.add(tag_factory(names=['tag4', 'tag5', 'tag6']))
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [
('category:cat1', ['t1', 't2']),
('category:cat2', ['t3']),
('category:cat1,cat2', ['t1', 't2', 't3']),
])
def test_filter_by_category(
verify_unpaged,
tag_factory,
tag_category_factory,
input,
expected_tag_names):
cat1 = tag_category_factory(name='cat1')
cat2 = tag_category_factory(name='cat2')
tag1 = tag_factory(names=['t1'], category=cat1)
tag2 = tag_factory(names=['t2'], category=cat1)
tag3 = tag_factory(names=['t3'], category=cat2)
db.session.add_all([tag1, tag2, tag3])
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [ @pytest.mark.parametrize('input,expected_tag_names', [
('creation-time:2014', ['t1', 't2']), ('creation-time:2014', ['t1', 't2']),
('creation-date:2014', ['t1', 't2']), ('creation-date:2014', ['t1', 't2']),
@ -51,41 +108,79 @@ def test_filter_by_creation_time(
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', [
('name:tag1', ['tag1']), ('last-edit-date:2014', ['t1', 't3']),
('name:tag2', ['tag2']), ('last-edit-time:2014', ['t1', 't3']),
('name:none', []), ('edit-date:2014', ['t1', 't3']),
('name:', []), ('edit-time:2014', ['t1', 't3']),
('name:*1', ['tag1']),
('name:*2', ['tag2']),
('name:*', ['tag1', 'tag2', 'tag3', 'tag4']),
('name:t*', ['tag1', 'tag2', 'tag3', 'tag4']),
('name:*a*', ['tag1', 'tag2', 'tag3', 'tag4']),
('name:*!*', []),
('name:!*', []),
('name:*!', []),
('-name:tag1', ['tag2', 'tag3', 'tag4']),
('-name:tag2', ['tag1', 'tag3', 'tag4']),
('name:tag1,tag2', ['tag1', 'tag2']),
('-name:tag1,tag3', ['tag2', 'tag4']),
('name:tag4', ['tag4']),
('name:tag4,tag5', ['tag4']),
]) ])
def test_filter_by_name(verify_unpaged, tag_factory, input, expected_tag_names): def test_filter_by_edit_time(
db.session.add(tag_factory(names=['tag1'])) verify_unpaged, tag_factory, input, expected_tag_names):
db.session.add(tag_factory(names=['tag2'])) tag1 = tag_factory(names=['t1'])
db.session.add(tag_factory(names=['tag3'])) tag2 = tag_factory(names=['t2'])
db.session.add(tag_factory(names=['tag4', 'tag5', 'tag6'])) tag3 = tag_factory(names=['t3'])
tag1.last_edit_time = datetime.datetime(2014, 1, 1)
tag2.last_edit_time = datetime.datetime(2015, 1, 1)
tag3.last_edit_time = datetime.datetime(2014, 1, 1)
db.session.add_all([tag1, tag2, tag3])
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', [
('', ['t1', 't2']), ('post-count:2', ['t1']),
('t1', ['t1']), ('post-count:1', ['t2']),
('t2', ['t2']), ('usage-count:2', ['t1']),
('t1,t2', ['t1', 't2']), ('usage-count:1', ['t2']),
('usages:2', ['t1']),
('usages:1', ['t2']),
]) ])
def test_anonymous(verify_unpaged, tag_factory, input, expected_tag_names): def test_filter_by_post_count(
db.session.add(tag_factory(names=['t1'])) verify_unpaged, tag_factory, post_factory, input, expected_tag_names):
db.session.add(tag_factory(names=['t2'])) post1 = post_factory()
post2 = post_factory()
tag1 = tag_factory(names=['t1'])
tag2 = tag_factory(names=['t2'])
db.session.add_all([post1, post2, tag1, tag2])
db.session.commit()
post1.tags.append(tag1)
post1.tags.append(tag2)
post2.tags.append(tag1)
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [
('suggestion-count:2', ['t1']),
('suggestion-count:1', ['t2']),
('suggestion-count:0', ['sug1', 'sug2', 'sug3']),
])
def test_filter_by_suggestion_count(
verify_unpaged, tag_factory, input, expected_tag_names):
sug1 = tag_factory(names=['sug1'])
sug2 = tag_factory(names=['sug2'])
sug3 = tag_factory(names=['sug3'])
tag1 = tag_factory(names=['t1'])
tag2 = tag_factory(names=['t2'])
db.session.add_all([sug1, sug3, tag2, sug2, tag1])
db.session.commit()
tag1.suggestions.append(sug1)
tag1.suggestions.append(sug2)
tag2.suggestions.append(sug3)
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [
('implication-count:2', ['t1']),
('implication-count:1', ['t2']),
('implication-count:0', ['sug1', 'sug2', 'sug3']),
])
def test_filter_by_implication_count(
verify_unpaged, tag_factory, input, expected_tag_names):
sug1 = tag_factory(names=['sug1'])
sug2 = tag_factory(names=['sug2'])
sug3 = tag_factory(names=['sug3'])
tag1 = tag_factory(names=['t1'])
tag2 = tag_factory(names=['t2'])
db.session.add_all([sug1, sug3, tag2, sug2, tag1])
db.session.commit()
tag1.implications.append(sug1)
tag1.implications.append(sug2)
tag2.implications.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', [
@ -118,6 +213,42 @@ def test_sort_by_creation_time(
db.session.add_all([tag3, tag1, tag2]) db.session.add_all([tag3, tag1, tag2])
verify_unpaged(input, expected_tag_names) verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [
('', ['t1', 't2', 't3']),
('sort:last-edit-date', ['t3', 't2', 't1']),
('sort:last-edit-time', ['t3', 't2', 't1']),
('sort:edit-date', ['t3', 't2', 't1']),
('sort:edit-time', ['t3', 't2', 't1']),
])
def test_sort_by_last_edit_time(
verify_unpaged, tag_factory, input, expected_tag_names):
tag1 = tag_factory(names=['t1'])
tag2 = tag_factory(names=['t2'])
tag3 = tag_factory(names=['t3'])
tag1.last_edit_time = datetime.datetime(1991, 1, 1)
tag2.last_edit_time = datetime.datetime(1991, 1, 2)
tag3.last_edit_time = datetime.datetime(1991, 1, 3)
db.session.add_all([tag3, tag1, tag2])
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [
('sort:post-count', ['t2', 't1']),
('sort:usage-count', ['t2', 't1']),
('sort:usages', ['t2', 't1']),
])
def test_sort_by_post_count(
verify_unpaged, tag_factory, post_factory, input, expected_tag_names):
post1 = post_factory()
post2 = post_factory()
tag1 = tag_factory(names=['t1'])
tag2 = tag_factory(names=['t2'])
db.session.add_all([post1, post2, tag1, tag2])
db.session.commit()
post1.tags.append(tag1)
post1.tags.append(tag2)
post2.tags.append(tag2)
verify_unpaged(input, expected_tag_names)
@pytest.mark.parametrize('input,expected_tag_names', [ @pytest.mark.parametrize('input,expected_tag_names', [
('sort:suggestion-count', ['t1', 't2', 'sug1', 'sug2', 'sug3']), ('sort:suggestion-count', ['t1', 't2', 'sug1', 'sug2', 'sug3']),
]) ])
@ -152,22 +283,34 @@ def test_sort_by_implication_count(
tag2.implications.append(sug3) tag2.implications.append(sug3)
verify_unpaged(input, expected_tag_names) verify_unpaged(input, expected_tag_names)
def test_filter_by_relation_count(verify_unpaged, tag_factory): @pytest.mark.parametrize('input,expected_tag_names', [
sug1 = tag_factory(names=['sug1']) ('sort:category', ['t3', 't1', 't2']),
sug2 = tag_factory(names=['sug2']) ])
imp1 = tag_factory(names=['imp1']) def test_sort_by_category(
tag1 = tag_factory(names=['t1']) verify_unpaged,
tag2 = tag_factory(names=['t2']) tag_factory,
db.session.add_all([sug1, tag1, sug2, imp1, tag2]) tag_category_factory,
db.session.commit() input,
db.session.add_all([ expected_tag_names):
db.TagSuggestion(tag1.tag_id, sug1.tag_id), cat1 = tag_category_factory(name='cat1')
db.TagSuggestion(tag1.tag_id, sug2.tag_id), cat2 = tag_category_factory(name='cat2')
db.TagImplication(tag2.tag_id, imp1.tag_id)]) tag1 = tag_factory(names=['t1'], category=cat2)
db.session.commit() tag2 = tag_factory(names=['t2'], category=cat2)
verify_unpaged('suggestion-count:0', ['imp1', 'sug1', 'sug2', 't2']) tag3 = tag_factory(names=['t3'], category=cat1)
verify_unpaged('suggestion-count:1', []) db.session.add_all([tag1, tag2, tag3])
verify_unpaged('suggestion-count:2', ['t1']) import sqlalchemy
verify_unpaged('implication-count:0', ['imp1', 'sug1', 'sug2', 't1']) from sqlalchemy.orm import joinedload
verify_unpaged('implication-count:1', ['t2']) print('test', [tag.first_name for tag in db.session.query(db.Tag)
verify_unpaged('implication-count:2', []) .join(db.TagCategory).options(
joinedload(db.Tag.names),
joinedload(db.Tag.category),
joinedload(db.Tag.suggestions).joinedload(db.Tag.names),
joinedload(db.Tag.implications).joinedload(db.Tag.names)
)
.options(sqlalchemy.orm.lazyload('*'))
.order_by(db.TagCategory.name.asc())
.order_by(db.Tag.first_name.asc())
.offset(0)
.limit(100)
.all()])
verify_unpaged(input, expected_tag_names)