Skip to content

Commit

Permalink
Add descriptors for more convenient access to .query etc on Search
Browse files Browse the repository at this point in the history
  • Loading branch information
honzakral committed Jan 30, 2015
1 parent 34c5545 commit 97774f0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 4 deletions.
6 changes: 6 additions & 0 deletions docs/search_dsl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ The method also accepts all the parameters as the ``Q`` shortcut:
s = s.query('match', query='python django', field='title', operator='or')
If you already have a query object, or a ``dict`` representing one, you can
just override the query used in the ``Search`` object:

.. code:: python
s.query = Q('bool', must=[Q('match', title='python'), Q('match', body='best')])
Query combination
^^^^^^^^^^^^^^^^^
Expand Down
36 changes: 32 additions & 4 deletions elasticsearch_dsl/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
from .result import Response, Result
from .connections import connections


class BaseProxy(object):
"""
Simple proxy around DSL objects (queries and filters) that can be called
(to add query/filter) and also allows attribute access which is proxied to
the wrapped query/filter.
"""
def __init__(self, search, attr_name):
self._search = search
self._proxied = self._empty
Expand All @@ -37,6 +41,25 @@ def __setattr__(self, attr_name, value):
super(BaseProxy, self).__setattr__(attr_name, value)


class ProxyDesriptor(object):
"""
Simple descriptor to enable setting of queries and filters as:
s = Search()
s.query = Q(...)
"""
def __init__(self, name):
self._attr_name = '_%s_proxy' % name

def __get__(self, instance, owner):
return getattr(instance, self._attr_name)

def __set__(self, instance, value):
proxy = getattr(instance, self._attr_name)
proxy._proxied = proxy._shortcut(value)


class ProxyQuery(BaseProxy):
_empty = EMPTY_QUERY
_shortcut = staticmethod(Q)
Expand All @@ -58,6 +81,10 @@ def to_dict(self):


class Search(object):
query = ProxyDesriptor('query')
filter = ProxyDesriptor('filter')
post_filter = ProxyDesriptor('post_filter')

def __init__(self, using='default', index=None, doc_type=None, extra=None):
"""
Search request to elasticsearch.
Expand Down Expand Up @@ -88,9 +115,6 @@ def __init__(self, using='default', index=None, doc_type=None, extra=None):
elif doc_type:
self._add_doc_type(doc_type)

self.query = ProxyQuery(self, 'query')
self.filter = ProxyFilter(self, 'filter')
self.post_filter = ProxyFilter(self, 'post_filter')
self.aggs = AggsProxy(self)
self._sort = []
self._extra = extra or {}
Expand All @@ -100,6 +124,10 @@ def __init__(self, using='default', index=None, doc_type=None, extra=None):
self._highlight_opts = {}
self._suggest = {}

self._query_proxy = ProxyQuery(self, 'query')
self._filter_proxy = ProxyFilter(self, 'filter')
self._post_filter_proxy = ProxyFilter(self, 'post_filter')

def __getitem__(self, n):
"""
Support slicing the `Search` instance for pagination.
Expand Down
8 changes: 8 additions & 0 deletions test_elasticsearch_dsl/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ def test_search_query_combines_query():
assert s2.query._proxied == query.Match(f=42)
assert s3.query._proxied == query.Bool(must=[query.Match(f=42), query.Match(f=43)])

def test_query_can_be_assigned_to():
s = search.Search()

q = Q('match', title='python')
s.query = q

assert s.query._proxied is q

def test_using():
o = object()
o2 = object()
Expand Down

0 comments on commit 97774f0

Please sign in to comment.