Permalink
Browse files

Reorganise `h.api.search` into package

  • Loading branch information...
nickstenning committed Jul 29, 2015
1 parent ac901e1 commit 8d05ab565a78bc0acac7f430ea8db2c31b2b77e1
View
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
from h.api.search.core import index
from h.api.search.core import search
__all__ = (
'index',
'search',
)
View
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
import logging
from elasticsearch import helpers
import webob.multidict
from h.api import models
from h.api.search import query
log = logging.getLogger(__name__)
def search(request_params, user=None):
"""
Search with the given params and return the matching annotations.
:param request_params: the HTTP request params that were posted to the
h search API
:type request_params: webob.multidict.NestedMultiDict
:param user: the authorized user, or None
:type user: h.accounts.models.User or None
:returns: a dict with keys "rows" (the list of matching annotations, as
dicts) and "total" (the number of matching annotations, an int)
:rtype: dict
"""
userid = user.id if user else None
log.debug("Searching with user=%s, for uri=%s",
str(userid), request_params.get('uri'))
body = query.build(request_params, userid=userid)
results = models.Annotation.search_raw(body, user=user, raw_result=True)
total = results['hits']['total']
docs = results['hits']['hits']
rows = [models.Annotation(d['_source'], id=d['_id']) for d in docs]
return {"rows": rows, "total": total}
def index(user=None):
"""
Return the 20 most recent annotations, most-recent first.
Returns the 20 most recent annotations that are visible to the given user,
or that are public if user is None.
"""
return search(webob.multidict.NestedMultiDict({"limit": 20}), user=user)
@@ -1,40 +1,10 @@
"""The h API search functions.
All search (Annotation.search(), Annotation.search_raw()) and Elasticsearch
stuff should be encapsulated in this module.
"""
import logging
from elasticsearch import helpers
import webob.multidict
from h.api import models
from h.api import uri
from h.api import nipsa
log = logging.getLogger(__name__)
def _match_clause_for_uri(uristr):
"""Return an Elasticsearch match clause dict for the given URI."""
if not uristr:
return None
uristrs = uri.expand(uri.normalise(uristr))
matchers = [{"match": {"uri": uri.normalise(u)}} for u in uristrs]
if len(matchers) == 1:
return matchers[0]
return {
"bool": {
"minimum_should_match": 1,
"should": matchers
}
}
def build_query(request_params, userid=None):
"""Return an Elasticsearch query dict for the given h search API params.
def build(request_params, userid=None):
"""
Return an Elasticsearch query dict for the given h search API params.
Translates the HTTP request params accepted by the h search API into an
Elasticsearch query dict.
@@ -49,7 +19,6 @@ def build_query(request_params, userid=None):
:returns: an Elasticsearch query dict corresponding to the given h search
API params
:rtype: dict
"""
# NestedMultiDict objects are read-only, so we need to copy to make it
# modifiable.
@@ -113,40 +82,19 @@ def build_query(request_params, userid=None):
return query
def search(request_params, user=None):
"""Search with the given params and return the matching annotations.
:param request_params: the HTTP request params that were posted to the
h search API
:type request_params: webob.multidict.NestedMultiDict
:param user: the authorized user, or None
:type user: h.accounts.models.User or None
:returns: a dict with keys "rows" (the list of matching annotations, as
dicts) and "total" (the number of matching annotations, an int)
:rtype: dict
"""
userid = user.id if user else None
log.debug("Searching with user=%s, for uri=%s",
str(userid), request_params.get('uri'))
query = build_query(request_params, userid=userid)
results = models.Annotation.search_raw(query, user=user, raw_result=True)
total = results['hits']['total']
docs = results['hits']['hits']
rows = [models.Annotation(d['_source'], id=d['_id']) for d in docs]
return {"rows": rows, "total": total}
def index(user=None):
"""Return the 20 most recent annotations, most-recent first.
def _match_clause_for_uri(uristr):
"""Return an Elasticsearch match clause dict for the given URI."""
if not uristr:
return None
Returns the 20 most recent annotations that are visible to the given user,
or that are public if user is None.
uristrs = uri.expand(uristr)
matchers = [{"match": {"uri": u}} for u in uristrs]
"""
return search(webob.multidict.NestedMultiDict({"limit": 20}), user=user)
if len(matchers) == 1:
return matchers[0]
return {
"bool": {
"minimum_should_match": 1,
"should": matchers
}
}
No changes.
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
import mock
from webob import multidict
from h.api.search import core
@mock.patch("annotator.annotation.Annotation.search_raw")
@mock.patch("h.api.search.query.build")
def test_search_with_user_object(_, search_raw):
"""If search() gets a user arg it passes it to search_raw().
Note: This test is testing the function's user param. You can also
pass one or more user arguments in the request.params, those are
tested elsewhere.
"""
user = mock.MagicMock()
core.search(request_params=multidict.NestedMultiDict(), user=user)
first_call = search_raw.call_args_list[0]
assert first_call[1]["user"] == user
@mock.patch("annotator.annotation.Annotation.search_raw")
@mock.patch("h.api.search.query.build")
def test_search_does_not_pass_userid_to_build(build, _):
core.search(multidict.NestedMultiDict())
assert build.call_args[1]["userid"] is None
@mock.patch("annotator.annotation.Annotation.search_raw")
@mock.patch("h.api.search.query.build")
def test_search_does_pass_userid_to_build(build, _):
user = mock.Mock(id="test_id")
core.search(multidict.NestedMultiDict(), user=user)
assert build.call_args[1]["userid"] == "test_id"
@mock.patch("h.api.search.core.search")
def test_index_limit_is_20(search_func):
"""index() calls search with "limit": 20."""
core.index()
first_call = search_func.call_args_list[0]
assert first_call[0][0]["limit"] == 20
Oops, something went wrong.

0 comments on commit 8d05ab5

Please sign in to comment.