16
16
# under the License.
17
17
18
18
import collections .abc
19
+ from typing import TYPE_CHECKING , Any , Dict , List , Optional , Tuple , Union , cast
19
20
20
21
from elasticsearch .exceptions import NotFoundError , RequestError
21
- from typing_extensions import dataclass_transform
22
+ from typing_extensions import Self , dataclass_transform
22
23
23
24
from .._async .index import AsyncIndex
24
25
from ..async_connections import get_connection
25
26
from ..document_base import DocumentBase , DocumentMeta , mapped_field
26
27
from ..exceptions import IllegalOperation
27
- from ..utils import DOC_META_FIELDS , META_FIELDS , merge
28
+ from ..utils import DOC_META_FIELDS , META_FIELDS , AsyncUsingType , merge
28
29
from .search import AsyncSearch
29
30
31
+ if TYPE_CHECKING :
32
+ from elasticsearch import AsyncElasticsearch
33
+
30
34
31
35
class AsyncIndexMeta (DocumentMeta ):
36
+ _index : AsyncIndex
37
+
32
38
# global flag to guard us from associating an Index with the base Document
33
39
# class, only user defined subclasses should have an _index attr
34
40
_document_initialized = False
35
41
36
- def __new__ (cls , name , bases , attrs ):
42
+ def __new__ (
43
+ cls , name : str , bases : Tuple [type , ...], attrs : Dict [str , Any ]
44
+ ) -> "AsyncIndexMeta" :
37
45
new_cls = super ().__new__ (cls , name , bases , attrs )
38
46
if cls ._document_initialized :
39
47
index_opts = attrs .pop ("Index" , None )
40
48
index = cls .construct_index (index_opts , bases )
41
49
new_cls ._index = index
42
50
index .document (new_cls )
43
51
cls ._document_initialized = True
44
- return new_cls
52
+ return cast ( AsyncIndexMeta , new_cls )
45
53
46
54
@classmethod
47
- def construct_index (cls , opts , bases ):
55
+ def construct_index (
56
+ cls , opts : Dict [str , Any ], bases : Tuple [type , ...]
57
+ ) -> AsyncIndex :
48
58
if opts is None :
49
59
for b in bases :
50
60
if hasattr (b , "_index" ):
@@ -69,12 +79,23 @@ class AsyncDocument(DocumentBase, metaclass=AsyncIndexMeta):
69
79
Model-like class for persisting documents in elasticsearch.
70
80
"""
71
81
82
+ if TYPE_CHECKING :
83
+ _index : AsyncIndex
84
+
72
85
@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" :
74
93
return get_connection (cls ._get_using (using ))
75
94
76
95
@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 :
78
99
"""
79
100
Create the index and populate the mappings in elasticsearch.
80
101
"""
@@ -84,7 +105,9 @@ async def init(cls, index=None, using=None):
84
105
await i .save (using = using )
85
106
86
107
@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 ]:
88
111
"""
89
112
Create an :class:`~elasticsearch_dsl.Search` instance that will search
90
113
over this ``Document``.
@@ -94,7 +117,13 @@ def search(cls, using=None, index=None):
94
117
)
95
118
96
119
@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 ]:
98
127
"""
99
128
Retrieve a single document from elasticsearch using its ``id``.
100
129
@@ -113,7 +142,13 @@ async def get(cls, id, using=None, index=None, **kwargs):
113
142
return cls .from_es (doc )
114
143
115
144
@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 :
117
152
"""
118
153
check if exists a single document from elasticsearch using its ``id``.
119
154
@@ -126,12 +161,18 @@ async def exists(cls, id, using=None, index=None, **kwargs):
126
161
``Elasticsearch.exists`` unchanged.
127
162
"""
128
163
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 ) )
130
165
131
166
@classmethod
132
167
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 ]]:
135
176
r"""
136
177
Retrieve multiple document by their ``id``\s. Returns a list of instances
137
178
in the same order as requested.
@@ -160,7 +201,9 @@ async def mget(
160
201
}
161
202
results = await es .mget (index = cls ._default_index (index ), body = body , ** kwargs )
162
203
163
- objs , error_docs , missing_docs = [], [], []
204
+ objs : List [Optional [Self ]] = []
205
+ error_docs : List [Self ] = []
206
+ missing_docs : List [Self ] = []
164
207
for doc in results ["docs" ]:
165
208
if doc .get ("found" ):
166
209
if error_docs or missing_docs :
@@ -186,14 +229,19 @@ async def mget(
186
229
error_ids = [doc ["_id" ] for doc in error_docs ]
187
230
message = "Required routing not provided for documents %s."
188
231
message %= ", " .join (error_ids )
189
- raise RequestError (400 , message , error_docs )
232
+ raise RequestError (400 , message , error_docs ) # type: ignore
190
233
if missing_docs :
191
234
missing_ids = [doc ["_id" ] for doc in missing_docs ]
192
235
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
194
237
return objs
195
238
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 :
197
245
"""
198
246
Delete the instance in elasticsearch.
199
247
@@ -214,23 +262,26 @@ async def delete(self, using=None, index=None, **kwargs):
214
262
doc_meta ["if_primary_term" ] = self .meta ["primary_term" ]
215
263
216
264
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 )
218
269
219
270
async def update (
220
271
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 :
234
285
"""
235
286
Partial update of the document, specify fields you wish to update and
236
287
both the instance and the document in elasticsearch will be updated::
@@ -261,7 +312,7 @@ async def update(
261
312
262
313
:return: operation result noop/updated
263
314
"""
264
- body = {
315
+ body : Dict [ str , Any ] = {
265
316
"doc_as_upsert" : doc_as_upsert ,
266
317
"detect_noop" : detect_noop ,
267
318
}
@@ -317,9 +368,13 @@ async def update(
317
368
doc_meta ["if_seq_no" ] = self .meta ["seq_no" ]
318
369
doc_meta ["if_primary_term" ] = self .meta ["primary_term" ]
319
370
371
+ i = self ._get_index (index )
372
+ assert i is not None
373
+
320
374
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
322
376
)
377
+
323
378
# update meta information from ES
324
379
for k in META_FIELDS :
325
380
if "_" + k in meta :
@@ -329,13 +384,13 @@ async def update(
329
384
330
385
async def save (
331
386
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 :
339
394
"""
340
395
Save the document into elasticsearch. If the document doesn't exist it
341
396
is created, it is overwritten otherwise. Returns ``True`` if this
@@ -369,8 +424,11 @@ async def save(
369
424
doc_meta ["if_primary_term" ] = self .meta ["primary_term" ]
370
425
371
426
doc_meta .update (kwargs )
427
+ i = self ._get_index (index )
428
+ assert i is not None
429
+
372
430
meta = await es .index (
373
- index = self . _get_index ( index ) ,
431
+ index = i ,
374
432
body = self .to_dict (skip_empty = skip_empty ),
375
433
** doc_meta ,
376
434
)
0 commit comments