Skip to content

Commit 4d59edd

Browse files
Added the EmptySearch class (#1780)
(cherry picked from commit 6cfbbe1)
1 parent 889775c commit 4d59edd

File tree

8 files changed

+82
-5
lines changed

8 files changed

+82
-5
lines changed

docs/search_dsl.rst

+7
Original file line numberDiff line numberDiff line change
@@ -666,3 +666,10 @@ If you need to execute multiple searches at the same time you can use the
666666
print("Results for query %r." % response.search.query)
667667
for hit in response:
668668
print(hit.title)
669+
670+
671+
``EmptySearch``
672+
---------------
673+
674+
The ``EmptySearch`` class can be used as a fully compatible version of ``Search``
675+
that will return no results, regardless of any queries configured.

elasticsearch_dsl/__init__.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,14 @@
8181
from .index import AsyncIndex, AsyncIndexTemplate, Index, IndexTemplate
8282
from .mapping import AsyncMapping, Mapping
8383
from .query import Q
84-
from .search import AsyncMultiSearch, AsyncSearch, MultiSearch, Search
84+
from .search import (
85+
AsyncEmptySearch,
86+
AsyncMultiSearch,
87+
AsyncSearch,
88+
EmptySearch,
89+
MultiSearch,
90+
Search,
91+
)
8592
from .update_by_query import AsyncUpdateByQuery, UpdateByQuery
8693
from .utils import AttrDict, AttrList, DslBase
8794
from .wrappers import Range
@@ -92,6 +99,7 @@
9299
__all__ = [
93100
"A",
94101
"AsyncDocument",
102+
"AsyncEmptySearch",
95103
"AsyncFacetedSearch",
96104
"AsyncIndex",
97105
"AsyncIndexTemplate",
@@ -115,6 +123,7 @@
115123
"DoubleRange",
116124
"DslBase",
117125
"ElasticsearchDslException",
126+
"EmptySearch",
118127
"Facet",
119128
"FacetedResponse",
120129
"FacetedSearch",

elasticsearch_dsl/_async/search.py

+15
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,18 @@ async def execute(self, ignore_cache=False, raise_on_error=True):
144144
self._response = out
145145

146146
return self._response
147+
148+
149+
class AsyncEmptySearch(AsyncSearch):
150+
async def count(self):
151+
return 0
152+
153+
async def execute(self, ignore_cache=False):
154+
return self._response_class(self, {"hits": {"total": 0, "hits": []}})
155+
156+
async def scan(self):
157+
return
158+
yield # a bit strange, but this forces an empty generator function
159+
160+
async def delete(self):
161+
return AttrDict({})

elasticsearch_dsl/_sync/search.py

+15
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,18 @@ def execute(self, ignore_cache=False, raise_on_error=True):
136136
self._response = out
137137

138138
return self._response
139+
140+
141+
class EmptySearch(Search):
142+
def count(self):
143+
return 0
144+
145+
def execute(self, ignore_cache=False):
146+
return self._response_class(self, {"hits": {"total": 0, "hits": []}})
147+
148+
def scan(self):
149+
return
150+
yield # a bit strange, but this forces an empty generator function
151+
152+
def delete(self):
153+
return AttrDict({})

elasticsearch_dsl/search.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
from elasticsearch_dsl._async.search import AsyncMultiSearch, AsyncSearch # noqa: F401
19-
from elasticsearch_dsl._sync.search import MultiSearch, Search # noqa: F401
18+
from elasticsearch_dsl._async.search import ( # noqa: F401
19+
AsyncEmptySearch,
20+
AsyncMultiSearch,
21+
AsyncSearch,
22+
)
23+
from elasticsearch_dsl._sync.search import ( # noqa: F401
24+
EmptySearch,
25+
MultiSearch,
26+
Search,
27+
)
2028
from elasticsearch_dsl.search_base import Q # noqa: F401

tests/_async/test_search.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from pytest import raises
2121

22-
from elasticsearch_dsl import AsyncSearch, Document, Q, query
22+
from elasticsearch_dsl import A, AsyncEmptySearch, AsyncSearch, Document, Q, query
2323
from elasticsearch_dsl.exceptions import IllegalOperation
2424

2525

@@ -681,3 +681,14 @@ def test_rescore_query_to_dict():
681681
},
682682
},
683683
}
684+
685+
686+
async def test_empty_search():
687+
s = AsyncEmptySearch(index="index-name")
688+
s = s.query("match", lang="java")
689+
s.aggs.bucket("versions", A("terms", field="version"))
690+
691+
assert await s.count() == 0
692+
assert [hit async for hit in s] == []
693+
assert [hit async for hit in s.scan()] == []
694+
await s.delete() # should not error

tests/_sync/test_search.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from pytest import raises
2121

22-
from elasticsearch_dsl import Document, Q, Search, query
22+
from elasticsearch_dsl import A, Document, EmptySearch, Q, Search, query
2323
from elasticsearch_dsl.exceptions import IllegalOperation
2424

2525

@@ -679,3 +679,14 @@ def test_rescore_query_to_dict():
679679
},
680680
},
681681
}
682+
683+
684+
def test_empty_search():
685+
s = EmptySearch(index="index-name")
686+
s = s.query("match", lang="java")
687+
s.aggs.bucket("versions", A("terms", field="version"))
688+
689+
assert s.count() == 0
690+
assert [hit for hit in s] == []
691+
assert [hit for hit in s.scan()] == []
692+
s.delete() # should not error

utils/run-unasync.py

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def main(check=False):
5252
"AsyncElasticsearch": "Elasticsearch",
5353
"AsyncSearch": "Search",
5454
"AsyncMultiSearch": "MultiSearch",
55+
"AsyncEmptySearch": "EmptySearch",
5556
"AsyncDocument": "Document",
5657
"AsyncIndexMeta": "IndexMeta",
5758
"AsyncIndexTemplate": "IndexTemplate",

0 commit comments

Comments
 (0)