diff options
| author | Hunternif | 2019-05-01 05:45:43 +0700 |
|---|---|---|
| committer | Hunternif | 2019-05-01 05:45:43 +0700 |
| commit | 82facef4aa1f1ede518acf1435d6ed98d37f8df1 (patch) | |
| tree | 5d260cdbc80fa0c5f878e72a7a8ed89b0540ff7c | |
| parent | 25ea3bd0a25b32c670491ecb2e1590a6086eb2fc (diff) | |
server: implement median of post metrics
| -rw-r--r-- | server/szurubooru/api/metric_api.py | 20 | ||||
| -rw-r--r-- | server/szurubooru/search/executor.py | 14 | ||||
| -rw-r--r-- | server/szurubooru/tests/api/test_metric_retrieving.py | 50 |
3 files changed, 82 insertions, 2 deletions
diff --git a/server/szurubooru/api/metric_api.py b/server/szurubooru/api/metric_api.py index 15f48d7..2b87a5d 100644 --- a/server/szurubooru/api/metric_api.py +++ b/server/szurubooru/api/metric_api.py @@ -1,3 +1,4 @@ +from math import ceil from typing import Optional, List, Dict from szurubooru import db, model, search, rest from szurubooru.func import ( @@ -23,7 +24,7 @@ def _serialize_post_metric( ) -def _get_metric(params: Dict[str, str]) -> model.Tag: +def _get_metric(params: Dict[str, str]) -> model.Metric: return metrics.get_metric_by_tag_name(params['tag_name']) @@ -68,6 +69,21 @@ def delete_metric(ctx: rest.Context, params: Dict[str, str]) -> rest.Response: def get_post_metrics( ctx: rest.Context, params: Dict[str, str] = {}) -> rest.Response: auth.verify_privilege(ctx.user, 'metrics:list') - _search_executor_config.user = ctx.user return _search_executor.execute_and_serialize( ctx, lambda post_metric: _serialize_post_metric(ctx, post_metric)) + + +@rest.routes.get('/post-metrics/median/(?P<tag_name>.+)') +def get_post_metrics_median( + ctx: rest.Context, params: Dict[str, str] = {}) -> rest.Response: + auth.verify_privilege(ctx.user, 'metrics:list') + metric = _get_metric(params) + tag_name = params['tag_name'] + query_text = ctx.get_param_as_string( + 'query', + default='%s:%f..%f' % (tag_name, metric.min, metric.max)) + count = _search_executor.count(query_text) + _, results = _search_executor.execute(query_text, ceil(count/2) - 1, 1) + return { + 'results': list([_serialize_post_metric(ctx, pm) for pm in results]) + } diff --git a/server/szurubooru/search/executor.py b/server/szurubooru/search/executor.py index ca55c6d..3a8ec68 100644 --- a/server/szurubooru/search/executor.py +++ b/server/szurubooru/search/executor.py @@ -140,6 +140,20 @@ class Executor: 'results': list([serializer(entity) for entity in entities]), } + def count(self, query_text:str) -> int: + search_query = self.parser.parse(query_text) + self.config.on_search_query_parsed(search_query) + count_query = self.config.create_count_query(True) + count_query = count_query.options(sa.orm.lazyload('*')) + count_query = self._prepare_db_query(count_query, search_query, False) + count_statement = ( + count_query + .statement + .with_only_columns([sa.func.count()]) + .order_by(None)) + count = db.session.execute(count_statement).scalar() + return count + def _prepare_db_query( self, db_query: SaQuery, diff --git a/server/szurubooru/tests/api/test_metric_retrieving.py b/server/szurubooru/tests/api/test_metric_retrieving.py new file mode 100644 index 0000000..901786d --- /dev/null +++ b/server/szurubooru/tests/api/test_metric_retrieving.py @@ -0,0 +1,50 @@ +import pytest +from szurubooru import api, db, model + + +@pytest.mark.parametrize('query,expected_value', [ + ('', 5), + ('mytag:0..', 5), + ('mytag:..10', 5), + ('mytag:0..10', 5), + ('mytag:2..8', 5), + ('mytag:0..8', 4), + ('mytag:0..6', 4), + ('mytag:0..5.5', 4), + ('mytag:0..4', 1), + ('mytag:1..4', 1), + ('mytag:2..3', None), +]) +def test_median( + query, + expected_value, + tag_factory, + post_factory, + metric_factory, + post_metric_factory, + context_factory, + user_factory): + tag = tag_factory(names=['mytag']) + post1 = post_factory(tags=[tag]) + post4 = post_factory(tags=[tag]) + post5 = post_factory(tags=[tag]) + post6 = post_factory(tags=[tag]) + post10 = post_factory(tags=[tag]) + metric = metric_factory(tag=tag, min=0, max=10) + pm1 = post_metric_factory(metric=metric, post=post1, value=1) + pm4 = post_metric_factory(metric=metric, post=post4, value=4) + pm5 = post_metric_factory(metric=metric, post=post5, value=5) + pm6 = post_metric_factory(metric=metric, post=post6, value=6) + pm10 = post_metric_factory(metric=metric, post=post10, value=10) + db.session.add_all([tag, metric, pm1, pm4, pm5, pm6, pm10, + post1, post4, post5, post6, post10]) + db.session.flush() + response = api.metric_api.get_post_metrics_median( + context_factory( + params={'query': query}, + user=user_factory(rank=model.User.RANK_REGULAR)), + {'tag_name': 'mytag'}) + if not expected_value: + assert len(response['results']) == 0 + else: + assert response['results'][0]['value'] == expected_value |