aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHunternif2019-05-01 05:45:43 +0700
committerHunternif2019-05-01 05:45:43 +0700
commit82facef4aa1f1ede518acf1435d6ed98d37f8df1 (patch)
tree5d260cdbc80fa0c5f878e72a7a8ed89b0540ff7c
parent25ea3bd0a25b32c670491ecb2e1590a6086eb2fc (diff)
server: implement median of post metrics
-rw-r--r--server/szurubooru/api/metric_api.py20
-rw-r--r--server/szurubooru/search/executor.py14
-rw-r--r--server/szurubooru/tests/api/test_metric_retrieving.py50
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

© 2015 - 2026 Jakob L. Kreuze