1616# under the License.
1717
1818import collections .abc
19+ from typing import TYPE_CHECKING , Any , Dict , List , Optional , Tuple , Union , cast
1920
2021from elasticsearch .exceptions import NotFoundError , RequestError
21- from typing_extensions import dataclass_transform
22+ from typing_extensions import Self , dataclass_transform
2223
2324from .._async .index import AsyncIndex
2425from ..async_connections import get_connection
2526from ..document_base import DocumentBase , DocumentMeta , mapped_field
2627from ..exceptions import IllegalOperation
27- from ..utils import DOC_META_FIELDS , META_FIELDS , merge
28+ from ..utils import DOC_META_FIELDS , META_FIELDS , AsyncUsingType , merge
2829from .search import AsyncSearch
2930
31+ if TYPE_CHECKING :
32+ from elasticsearch import AsyncElasticsearch
33+
3034
3135class AsyncIndexMeta (DocumentMeta ):
36+ _index : AsyncIndex
37+
3238 # global flag to guard us from associating an Index with the base Document
3339 # class, only user defined subclasses should have an _index attr
3440 _document_initialized = False
3541
36- def __new__ (cls , name , bases , attrs ):
42+ def __new__ (
43+ cls , name : str , bases : Tuple [type , ...], attrs : Dict [str , Any ]
44+ ) -> "AsyncIndexMeta" :
3745 new_cls = super ().__new__ (cls , name , bases , attrs )
3846 if cls ._document_initialized :
3947 index_opts = attrs .pop ("Index" , None )
4048 index = cls .construct_index (index_opts , bases )
4149 new_cls ._index = index
4250 index .document (new_cls )
4351 cls ._document_initialized = True
44- return new_cls
52+ return cast ( AsyncIndexMeta , new_cls )
4553
4654 @classmethod
47- def construct_index (cls , opts , bases ):
55+ def construct_index (
56+ cls , opts : Dict [str , Any ], bases : Tuple [type , ...]
57+ ) -> AsyncIndex :
4858 if opts is None :
4959 for b in bases :
5060 if hasattr (b , "_index" ):
@@ -69,12 +79,23 @@ class AsyncDocument(DocumentBase, metaclass=AsyncIndexMeta):
6979 Model-like class for persisting documents in elasticsearch.
7080 """
7181
82+ if TYPE_CHECKING :
83+ _index : AsyncIndex
84+
7285 @classmethod
73- def _get_connection (cls , using = None ):
86+ def _get_using (cls , using : Optional [AsyncUsingType ] = None ) -> AsyncUsingType :
87+ return using or cls ._index ._using
88+
89+ @classmethod
90+ def _get_connection (
91+ cls , using : Optional [AsyncUsingType ] = None
92+ ) -> "AsyncElasticsearch" :
7493 return get_connection (cls ._get_using (using ))
7594
7695 @classmethod
77- async def init (cls , index = None , using = None ):
96+ async def init (
97+ cls , index : Optional [str ] = None , using : Optional [AsyncUsingType ] = None
98+ ) -> None :
7899 """
79100 Create the index and populate the mappings in elasticsearch.
80101 """
@@ -84,7 +105,9 @@ async def init(cls, index=None, using=None):
84105 await i .save (using = using )
85106
86107 @classmethod
87- def search (cls , using = None , index = None ):
108+ def search (
109+ cls , using : Optional [AsyncUsingType ] = None , index : Optional [str ] = None
110+ ) -> AsyncSearch [Self ]:
88111 """
89112 Create an :class:`~elasticsearch_dsl.Search` instance that will search
90113 over this ``Document``.
@@ -94,7 +117,13 @@ def search(cls, using=None, index=None):
94117 )
95118
96119 @classmethod
97- async def get (cls , id , using = None , index = None , ** kwargs ):
120+ async def get (
121+ cls ,
122+ id : str ,
123+ using : Optional [AsyncUsingType ] = None ,
124+ index : Optional [str ] = None ,
125+ ** kwargs : Any ,
126+ ) -> Optional [Self ]:
98127 """
99128 Retrieve a single document from elasticsearch using its ``id``.
100129
@@ -113,7 +142,13 @@ async def get(cls, id, using=None, index=None, **kwargs):
113142 return cls .from_es (doc )
114143
115144 @classmethod
116- async def exists (cls , id , using = None , index = None , ** kwargs ):
145+ async def exists (
146+ cls ,
147+ id : str ,
148+ using : Optional [AsyncUsingType ] = None ,
149+ index : Optional [str ] = None ,
150+ ** kwargs : Any ,
151+ ) -> bool :
117152 """
118153 check if exists a single document from elasticsearch using its ``id``.
119154
@@ -126,12 +161,18 @@ async def exists(cls, id, using=None, index=None, **kwargs):
126161 ``Elasticsearch.exists`` unchanged.
127162 """
128163 es = cls ._get_connection (using )
129- return await es .exists (index = cls ._default_index (index ), id = id , ** kwargs )
164+ return bool ( await es .exists (index = cls ._default_index (index ), id = id , ** kwargs ) )
130165
131166 @classmethod
132167 async def mget (
133- cls , docs , using = None , index = None , raise_on_error = True , missing = "none" , ** kwargs
134- ):
168+ cls ,
169+ docs : List [Dict [str , Any ]],
170+ using : Optional [AsyncUsingType ] = None ,
171+ index : Optional [str ] = None ,
172+ raise_on_error : bool = True ,
173+ missing : str = "none" ,
174+ ** kwargs : Any ,
175+ ) -> List [Optional [Self ]]:
135176 r"""
136177 Retrieve multiple document by their ``id``\s. Returns a list of instances
137178 in the same order as requested.
@@ -160,7 +201,9 @@ async def mget(
160201 }
161202 results = await es .mget (index = cls ._default_index (index ), body = body , ** kwargs )
162203
163- objs , error_docs , missing_docs = [], [], []
204+ objs : List [Optional [Self ]] = []
205+ error_docs : List [Self ] = []
206+ missing_docs : List [Self ] = []
164207 for doc in results ["docs" ]:
165208 if doc .get ("found" ):
166209 if error_docs or missing_docs :
@@ -186,14 +229,19 @@ async def mget(
186229 error_ids = [doc ["_id" ] for doc in error_docs ]
187230 message = "Required routing not provided for documents %s."
188231 message %= ", " .join (error_ids )
189- raise RequestError (400 , message , error_docs )
232+ raise RequestError (400 , message , error_docs ) # type: ignore
190233 if missing_docs :
191234 missing_ids = [doc ["_id" ] for doc in missing_docs ]
192235 message = f"Documents { ', ' .join (missing_ids )} not found."
193- raise NotFoundError (404 , message , {"docs" : missing_docs })
236+ raise NotFoundError (404 , message , {"docs" : missing_docs }) # type: ignore
194237 return objs
195238
196- async def delete (self , using = None , index = None , ** kwargs ):
239+ async def delete (
240+ self ,
241+ using : Optional [AsyncUsingType ] = None ,
242+ index : Optional [str ] = None ,
243+ ** kwargs : Any ,
244+ ) -> None :
197245 """
198246 Delete the instance in elasticsearch.
199247
@@ -214,23 +262,26 @@ async def delete(self, using=None, index=None, **kwargs):
214262 doc_meta ["if_primary_term" ] = self .meta ["primary_term" ]
215263
216264 doc_meta .update (kwargs )
217- await es .delete (index = self ._get_index (index ), ** doc_meta )
265+ i = self ._get_index (index )
266+ assert i is not None
267+
268+ await es .delete (index = i , ** doc_meta )
218269
219270 async def update (
220271 self ,
221- using = None ,
222- index = None ,
223- detect_noop = True ,
224- doc_as_upsert = False ,
225- refresh = False ,
226- retry_on_conflict = None ,
227- script = None ,
228- script_id = None ,
229- scripted_upsert = False ,
230- upsert = None ,
231- return_doc_meta = False ,
232- ** fields ,
233- ):
272+ using : Optional [ AsyncUsingType ] = None ,
273+ index : Optional [ str ] = None ,
274+ detect_noop : bool = True ,
275+ doc_as_upsert : bool = False ,
276+ refresh : bool = False ,
277+ retry_on_conflict : Optional [ int ] = None ,
278+ script : Optional [ Union [ str , Dict [ str , Any ]]] = None ,
279+ script_id : Optional [ str ] = None ,
280+ scripted_upsert : bool = False ,
281+ upsert : Optional [ Dict [ str , Any ]] = None ,
282+ return_doc_meta : bool = False ,
283+ ** fields : Any ,
284+ ) -> Any :
234285 """
235286 Partial update of the document, specify fields you wish to update and
236287 both the instance and the document in elasticsearch will be updated::
@@ -261,7 +312,7 @@ async def update(
261312
262313 :return: operation result noop/updated
263314 """
264- body = {
315+ body : Dict [ str , Any ] = {
265316 "doc_as_upsert" : doc_as_upsert ,
266317 "detect_noop" : detect_noop ,
267318 }
@@ -317,9 +368,13 @@ async def update(
317368 doc_meta ["if_seq_no" ] = self .meta ["seq_no" ]
318369 doc_meta ["if_primary_term" ] = self .meta ["primary_term" ]
319370
371+ i = self ._get_index (index )
372+ assert i is not None
373+
320374 meta = await self ._get_connection (using ).update (
321- index = self . _get_index ( index ) , body = body , refresh = refresh , ** doc_meta
375+ index = i , body = body , refresh = refresh , ** doc_meta
322376 )
377+
323378 # update meta information from ES
324379 for k in META_FIELDS :
325380 if "_" + k in meta :
@@ -329,13 +384,13 @@ async def update(
329384
330385 async def save (
331386 self ,
332- using = None ,
333- index = None ,
334- validate = True ,
335- skip_empty = True ,
336- return_doc_meta = False ,
337- ** kwargs ,
338- ):
387+ using : Optional [ AsyncUsingType ] = None ,
388+ index : Optional [ str ] = None ,
389+ validate : bool = True ,
390+ skip_empty : bool = True ,
391+ return_doc_meta : bool = False ,
392+ ** kwargs : Any ,
393+ ) -> Any :
339394 """
340395 Save the document into elasticsearch. If the document doesn't exist it
341396 is created, it is overwritten otherwise. Returns ``True`` if this
@@ -369,8 +424,11 @@ async def save(
369424 doc_meta ["if_primary_term" ] = self .meta ["primary_term" ]
370425
371426 doc_meta .update (kwargs )
427+ i = self ._get_index (index )
428+ assert i is not None
429+
372430 meta = await es .index (
373- index = self . _get_index ( index ) ,
431+ index = i ,
374432 body = self .to_dict (skip_empty = skip_empty ),
375433 ** doc_meta ,
376434 )
0 commit comments