Skip to content

Commit

Permalink
Added the EmptySearch class (#1780)
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Apr 15, 2024
1 parent 9ade575 commit 6cfbbe1
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 5 deletions.
7 changes: 7 additions & 0 deletions docs/search_dsl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -666,3 +666,10 @@ If you need to execute multiple searches at the same time you can use the
print("Results for query %r." % response.search.query)
for hit in response:
print(hit.title)
``EmptySearch``
---------------

The ``EmptySearch`` class can be used as a fully compatible version of ``Search``
that will return no results, regardless of any queries configured.
11 changes: 10 additions & 1 deletion elasticsearch_dsl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,14 @@
from .index import AsyncIndex, AsyncIndexTemplate, Index, IndexTemplate
from .mapping import AsyncMapping, Mapping
from .query import Q
from .search import AsyncMultiSearch, AsyncSearch, MultiSearch, Search
from .search import (
AsyncEmptySearch,
AsyncMultiSearch,
AsyncSearch,
EmptySearch,
MultiSearch,
Search,
)
from .update_by_query import AsyncUpdateByQuery, UpdateByQuery
from .utils import AttrDict, AttrList, DslBase
from .wrappers import Range
Expand All @@ -92,6 +99,7 @@
__all__ = [
"A",
"AsyncDocument",
"AsyncEmptySearch",
"AsyncFacetedSearch",
"AsyncIndex",
"AsyncIndexTemplate",
Expand All @@ -115,6 +123,7 @@
"DoubleRange",
"DslBase",
"ElasticsearchDslException",
"EmptySearch",
"Facet",
"FacetedResponse",
"FacetedSearch",
Expand Down
15 changes: 15 additions & 0 deletions elasticsearch_dsl/_async/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,18 @@ async def execute(self, ignore_cache=False, raise_on_error=True):
self._response = out

return self._response


class AsyncEmptySearch(AsyncSearch):
async def count(self):
return 0

async def execute(self, ignore_cache=False):
return self._response_class(self, {"hits": {"total": 0, "hits": []}})

async def scan(self):
return
yield # a bit strange, but this forces an empty generator function

async def delete(self):
return AttrDict({})
15 changes: 15 additions & 0 deletions elasticsearch_dsl/_sync/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,18 @@ def execute(self, ignore_cache=False, raise_on_error=True):
self._response = out

return self._response


class EmptySearch(Search):
def count(self):
return 0

def execute(self, ignore_cache=False):
return self._response_class(self, {"hits": {"total": 0, "hits": []}})

def scan(self):
return
yield # a bit strange, but this forces an empty generator function

def delete(self):
return AttrDict({})
12 changes: 10 additions & 2 deletions elasticsearch_dsl/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
# specific language governing permissions and limitations
# under the License.

from elasticsearch_dsl._async.search import AsyncMultiSearch, AsyncSearch # noqa: F401
from elasticsearch_dsl._sync.search import MultiSearch, Search # noqa: F401
from elasticsearch_dsl._async.search import ( # noqa: F401
AsyncEmptySearch,
AsyncMultiSearch,
AsyncSearch,
)
from elasticsearch_dsl._sync.search import ( # noqa: F401
EmptySearch,
MultiSearch,
Search,
)
from elasticsearch_dsl.search_base import Q # noqa: F401
13 changes: 12 additions & 1 deletion tests/_async/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from pytest import raises, warns

from elasticsearch_dsl import AsyncSearch, Document, Q, query
from elasticsearch_dsl import A, AsyncEmptySearch, AsyncSearch, Document, Q, query
from elasticsearch_dsl.exceptions import IllegalOperation


Expand Down Expand Up @@ -687,3 +687,14 @@ def test_rescore_query_to_dict():
},
},
}


async def test_empty_search():
s = AsyncEmptySearch(index="index-name")
s = s.query("match", lang="java")
s.aggs.bucket("versions", A("terms", field="version"))

assert await s.count() == 0
assert [hit async for hit in s] == []
assert [hit async for hit in s.scan()] == []
await s.delete() # should not error
13 changes: 12 additions & 1 deletion tests/_sync/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from pytest import raises, warns

from elasticsearch_dsl import Document, Q, Search, query
from elasticsearch_dsl import A, Document, EmptySearch, Q, Search, query
from elasticsearch_dsl.exceptions import IllegalOperation


Expand Down Expand Up @@ -685,3 +685,14 @@ def test_rescore_query_to_dict():
},
},
}


def test_empty_search():
s = EmptySearch(index="index-name")
s = s.query("match", lang="java")
s.aggs.bucket("versions", A("terms", field="version"))

assert s.count() == 0
assert [hit for hit in s] == []
assert [hit for hit in s.scan()] == []
s.delete() # should not error
1 change: 1 addition & 0 deletions utils/run-unasync.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def main(check=False):
"AsyncElasticsearch": "Elasticsearch",
"AsyncSearch": "Search",
"AsyncMultiSearch": "MultiSearch",
"AsyncEmptySearch": "EmptySearch",
"AsyncDocument": "Document",
"AsyncIndexMeta": "IndexMeta",
"AsyncIndexTemplate": "IndexTemplate",
Expand Down

0 comments on commit 6cfbbe1

Please sign in to comment.