server/posts: support note-text search query

This commit is contained in:
rr- 2017-02-05 21:50:58 +01:00
parent 1f14f2fc16
commit 0b21d98c9b
4 changed files with 61 additions and 22 deletions

1
API.md
View file

@ -710,6 +710,7 @@ data.
| `comment-count` | having given number of comments |
| `fav-count` | favorited by given number of users |
| `note-count` | having given number of annotations |
| `note-text` | having given note text (accepts wildcards) |
| `relation-count` | having given number of relations |
| `feature-count` | having been featured given number of times |
| `type` | given type of posts. `<value>` can be either `image`, `animation` (or `animated` or `anim`), `flash` (or `swf`) or `video` (or `webm`). |

View file

@ -54,6 +54,10 @@
<td><code>note-count</code></td>
<td>having given number of annotations</td>
</tr>
<tr>
<td><code>note-text</code></td>
<td>having given note text (accepts wildcards)</td>
</tr>
<tr>
<td><code>relation-count</code></td>
<td>having given number of relations</td>

View file

@ -69,25 +69,35 @@ def _create_score_filter(score: int) -> Filter:
return wrapper
def _create_user_filter() -> Filter:
def wrapper(
query: SaQuery,
criterion: Optional[criteria.BaseCriterion],
negated: bool) -> SaQuery:
assert criterion
if isinstance(criterion, criteria.PlainCriterion) \
and not criterion.value:
# pylint: disable=singleton-comparison
expr = model.Post.user_id == None
if negated:
expr = ~expr
return query.filter(expr)
return search_util.create_subquery_filter(
model.Post.user_id,
model.User.user_id,
model.User.name,
search_util.create_str_filter)(query, criterion, negated)
return wrapper
def _user_filter(
query: SaQuery,
criterion: Optional[criteria.BaseCriterion],
negated: bool) -> SaQuery:
assert criterion
if isinstance(criterion, criteria.PlainCriterion) \
and not criterion.value:
# pylint: disable=singleton-comparison
expr = model.Post.user_id == None
if negated:
expr = ~expr
return query.filter(expr)
return search_util.create_subquery_filter(
model.Post.user_id,
model.User.user_id,
model.User.name,
search_util.create_str_filter)(query, criterion, negated)
def _note_filter(
query: SaQuery,
criterion: Optional[criteria.BaseCriterion],
negated: bool) -> SaQuery:
assert criterion
return search_util.create_subquery_filter(
model.Post.post_id,
model.PostNote.post_id,
model.PostNote.text,
search_util.create_str_filter)(query, criterion, negated)
class PostSearchConfig(BaseSearchConfig):
@ -187,7 +197,7 @@ class PostSearchConfig(BaseSearchConfig):
(
['uploader', 'upload', 'submit'],
_create_user_filter()
_user_filter
),
(
@ -311,6 +321,11 @@ class PostSearchConfig(BaseSearchConfig):
search_util.create_str_filter(
model.Post.safety, _safety_transformer)
),
(
['note-text'],
_note_filter
),
])
@property

View file

@ -27,8 +27,8 @@ def score_factory(user_factory):
@pytest.fixture
def note_factory():
def factory():
return model.PostNote(polygon='...', text='...')
def factory(text='...'):
return model.PostNote(polygon='...', text=text)
return factory
@ -294,6 +294,25 @@ def test_filter_by_note_count(
verify_unpaged(input, expected_post_ids)
@pytest.mark.parametrize('input,expected_post_ids', [
('note-text:*', [1, 2, 3]),
('note-text:text2', [2]),
('note-text:text3*', [3]),
('note-text:text3a,text2', [2, 3]),
])
def test_filter_by_note_count(
verify_unpaged, post_factory, note_factory, input, expected_post_ids):
post1 = post_factory(id=1)
post2 = post_factory(id=2)
post3 = post_factory(id=3)
post1.notes = [note_factory(text='text1')]
post2.notes = [note_factory(text='text2'), note_factory(text='text2')]
post3.notes = [note_factory(text='text3a'), note_factory(text='text3b')]
db.session.add_all([post1, post2, post3])
db.session.flush()
verify_unpaged(input, expected_post_ids)
@pytest.mark.parametrize('input,expected_post_ids', [
('feature-count:1', [1]),
('feature-count:3', [3]),