codekingpro/portable-devtools
114k
1# ext/asyncio/result.py
2# Copyright (C) 2020-2024 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7from __future__ import annotations
8
9import operator
10from typing import Any
11from typing import AsyncIterator
12from typing import Optional
13from typing import overload
14from typing import Sequence
15from typing import Tuple
16from typing import TYPE_CHECKING
17from typing import TypeVar
18
19from . import exc as async_exc
20from ... import util
21from ...engine import Result
22from ...engine.result import _NO_ROW
23from ...engine.result import _R
24from ...engine.result import _WithKeys
25from ...engine.result import FilterResult
26from ...engine.result import FrozenResult
27from ...engine.result import ResultMetaData
28from ...engine.row import Row
29from ...engine.row import RowMapping
30from ...sql.base import _generative
31from ...util.concurrency import greenlet_spawn
32from ...util.typing import Literal
33from ...util.typing import Self
34
35if TYPE_CHECKING:
36 from ...engine import CursorResult
37 from ...engine.result import _KeyIndexType
38 from ...engine.result import _UniqueFilterType
39
40_T = TypeVar("_T", bound=Any)
41_TP = TypeVar("_TP", bound=Tuple[Any, ...])
42
43
44class AsyncCommon(FilterResult[_R]):
45 __slots__ = ()
46
47 _real_result: Result[Any]
48 _metadata: ResultMetaData
49
50 async def close(self) -> None: # type: ignore[override]
51 """Close this result."""
52
53 await greenlet_spawn(self._real_result.close)
54
55 @property
56 def closed(self) -> bool:
57 """proxies the .closed attribute of the underlying result object,
58 if any, else raises ``AttributeError``.
59
60 .. versionadded:: 2.0.0b3
61
62 """
63 return self._real_result.closed
64
65
66class AsyncResult(_WithKeys, AsyncCommon[Row[_TP]]):
67 """An asyncio wrapper around a :class:`_result.Result` object.
68
69 The :class:`_asyncio.AsyncResult` only applies to statement executions that
70 use a server-side cursor. It is returned only from the
71 :meth:`_asyncio.AsyncConnection.stream` and
72 :meth:`_asyncio.AsyncSession.stream` methods.
73
74 .. note:: As is the case with :class:`_engine.Result`, this object is
75 used for ORM results returned by :meth:`_asyncio.AsyncSession.execute`,
76 which can yield instances of ORM mapped objects either individually or
77 within tuple-like rows. Note that these result objects do not
78 deduplicate instances or rows automatically as is the case with the
79 legacy :class:`_orm.Query` object. For in-Python de-duplication of
80 instances or rows, use the :meth:`_asyncio.AsyncResult.unique` modifier
81 method.
82
83 .. versionadded:: 1.4
84
85 """
86
87 __slots__ = ()
88
89 _real_result: Result[_TP]
90
91 def __init__(self, real_result: Result[_TP]):
92 self._real_result = real_result
93
94 self._metadata = real_result._metadata
95 self._unique_filter_state = real_result._unique_filter_state
96 self._post_creational_filter = None
97
98 # BaseCursorResult pre-generates the "_row_getter". Use that
99 # if available rather than building a second one
100 if "_row_getter" in real_result.__dict__:
101 self._set_memoized_attribute(
102 "_row_getter", real_result.__dict__["_row_getter"]
103 )
104
105 @property
106 def t(self) -> AsyncTupleResult[_TP]:
107 """Apply a "typed tuple" typing filter to returned rows.
108
109 The :attr:`_asyncio.AsyncResult.t` attribute is a synonym for
110 calling the :meth:`_asyncio.AsyncResult.tuples` method.
111
112 .. versionadded:: 2.0
113
114 """
115 return self # type: ignore
116
117 def tuples(self) -> AsyncTupleResult[_TP]:
118 """Apply a "typed tuple" typing filter to returned rows.
119
120 This method returns the same :class:`_asyncio.AsyncResult` object
121 at runtime,
122 however annotates as returning a :class:`_asyncio.AsyncTupleResult`
123 object that will indicate to :pep:`484` typing tools that plain typed
124 ``Tuple`` instances are returned rather than rows. This allows
125 tuple unpacking and ``__getitem__`` access of :class:`_engine.Row`
126 objects to by typed, for those cases where the statement invoked
127 itself included typing information.
128
129 .. versionadded:: 2.0
130
131 :return: the :class:`_result.AsyncTupleResult` type at typing time.
132
133 .. seealso::
134
135 :attr:`_asyncio.AsyncResult.t` - shorter synonym
136
137 :attr:`_engine.Row.t` - :class:`_engine.Row` version
138
139 """
140
141 return self # type: ignore
142
143 @_generative
144 def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
145 """Apply unique filtering to the objects returned by this
146 :class:`_asyncio.AsyncResult`.
147
148 Refer to :meth:`_engine.Result.unique` in the synchronous
149 SQLAlchemy API for a complete behavioral description.
150
151 """
152 self._unique_filter_state = (set(), strategy)
153 return self
154
155 def columns(self, *col_expressions: _KeyIndexType) -> Self:
156 r"""Establish the columns that should be returned in each row.
157
158 Refer to :meth:`_engine.Result.columns` in the synchronous
159 SQLAlchemy API for a complete behavioral description.
160
161 """
162 return self._column_slices(col_expressions)
163
164 async def partitions(
165 self, size: Optional[int] = None
166 ) -> AsyncIterator[Sequence[Row[_TP]]]:
167 """Iterate through sub-lists of rows of the size given.
168
169 An async iterator is returned::
170
171 async def scroll_results(connection):
172 result = await connection.stream(select(users_table))
173
174 async for partition in result.partitions(100):
175 print("list of rows: %s" % partition)
176
177 Refer to :meth:`_engine.Result.partitions` in the synchronous
178 SQLAlchemy API for a complete behavioral description.
179
180 """
181
182 getter = self._manyrow_getter
183
184 while True:
185 partition = await greenlet_spawn(getter, self, size)
186 if partition:
187 yield partition
188 else:
189 break
190
191 async def fetchall(self) -> Sequence[Row[_TP]]:
192 """A synonym for the :meth:`_asyncio.AsyncResult.all` method.
193
194 .. versionadded:: 2.0
195
196 """
197
198 return await greenlet_spawn(self._allrows)
199
200 async def fetchone(self) -> Optional[Row[_TP]]:
201 """Fetch one row.
202
203 When all rows are exhausted, returns None.
204
205 This method is provided for backwards compatibility with
206 SQLAlchemy 1.x.x.
207
208 To fetch the first row of a result only, use the
209 :meth:`_asyncio.AsyncResult.first` method. To iterate through all
210 rows, iterate the :class:`_asyncio.AsyncResult` object directly.
211
212 :return: a :class:`_engine.Row` object if no filters are applied,
213 or ``None`` if no rows remain.
214
215 """
216 row = await greenlet_spawn(self._onerow_getter, self)
217 if row is _NO_ROW:
218 return None
219 else:
220 return row
221
222 async def fetchmany(
223 self, size: Optional[int] = None
224 ) -> Sequence[Row[_TP]]:
225 """Fetch many rows.
226
227 When all rows are exhausted, returns an empty list.
228
229 This method is provided for backwards compatibility with
230 SQLAlchemy 1.x.x.
231
232 To fetch rows in groups, use the
233 :meth:`._asyncio.AsyncResult.partitions` method.
234
235 :return: a list of :class:`_engine.Row` objects.
236
237 .. seealso::
238
239 :meth:`_asyncio.AsyncResult.partitions`
240
241 """
242
243 return await greenlet_spawn(self._manyrow_getter, self, size)
244
245 async def all(self) -> Sequence[Row[_TP]]:
246 """Return all rows in a list.
247
248 Closes the result set after invocation. Subsequent invocations
249 will return an empty list.
250
251 :return: a list of :class:`_engine.Row` objects.
252
253 """
254
255 return await greenlet_spawn(self._allrows)
256
257 def __aiter__(self) -> AsyncResult[_TP]:
258 return self
259
260 async def __anext__(self) -> Row[_TP]:
261 row = await greenlet_spawn(self._onerow_getter, self)
262 if row is _NO_ROW:
263 raise StopAsyncIteration()
264 else:
265 return row
266
267 async def first(self) -> Optional[Row[_TP]]:
268 """Fetch the first row or ``None`` if no row is present.
269
270 Closes the result set and discards remaining rows.
271
272 .. note:: This method returns one **row**, e.g. tuple, by default.
273 To return exactly one single scalar value, that is, the first
274 column of the first row, use the
275 :meth:`_asyncio.AsyncResult.scalar` method,
276 or combine :meth:`_asyncio.AsyncResult.scalars` and
277 :meth:`_asyncio.AsyncResult.first`.
278
279 Additionally, in contrast to the behavior of the legacy ORM
280 :meth:`_orm.Query.first` method, **no limit is applied** to the
281 SQL query which was invoked to produce this
282 :class:`_asyncio.AsyncResult`;
283 for a DBAPI driver that buffers results in memory before yielding
284 rows, all rows will be sent to the Python process and all but
285 the first row will be discarded.
286
287 .. seealso::
288
289 :ref:`migration_20_unify_select`
290
291 :return: a :class:`_engine.Row` object, or None
292 if no rows remain.
293
294 .. seealso::
295
296 :meth:`_asyncio.AsyncResult.scalar`
297
298 :meth:`_asyncio.AsyncResult.one`
299
300 """
301 return await greenlet_spawn(self._only_one_row, False, False, False)
302
303 async def one_or_none(self) -> Optional[Row[_TP]]:
304 """Return at most one result or raise an exception.
305
306 Returns ``None`` if the result has no rows.
307 Raises :class:`.MultipleResultsFound`
308 if multiple rows are returned.
309
310 .. versionadded:: 1.4
311
312 :return: The first :class:`_engine.Row` or ``None`` if no row
313 is available.
314
315 :raises: :class:`.MultipleResultsFound`
316
317 .. seealso::
318
319 :meth:`_asyncio.AsyncResult.first`
320
321 :meth:`_asyncio.AsyncResult.one`
322
323 """
324 return await greenlet_spawn(self._only_one_row, True, False, False)
325
326 @overload
327 async def scalar_one(self: AsyncResult[Tuple[_T]]) -> _T: ...
328
329 @overload
330 async def scalar_one(self) -> Any: ...
331
332 async def scalar_one(self) -> Any:
333 """Return exactly one scalar result or raise an exception.
334
335 This is equivalent to calling :meth:`_asyncio.AsyncResult.scalars` and
336 then :meth:`_asyncio.AsyncResult.one`.
337
338 .. seealso::
339
340 :meth:`_asyncio.AsyncResult.one`
341
342 :meth:`_asyncio.AsyncResult.scalars`
343
344 """
345 return await greenlet_spawn(self._only_one_row, True, True, True)
346
347 @overload
348 async def scalar_one_or_none(
349 self: AsyncResult[Tuple[_T]],
350 ) -> Optional[_T]: ...
351
352 @overload
353 async def scalar_one_or_none(self) -> Optional[Any]: ...
354
355 async def scalar_one_or_none(self) -> Optional[Any]:
356 """Return exactly one scalar result or ``None``.
357
358 This is equivalent to calling :meth:`_asyncio.AsyncResult.scalars` and
359 then :meth:`_asyncio.AsyncResult.one_or_none`.
360
361 .. seealso::
362
363 :meth:`_asyncio.AsyncResult.one_or_none`
364
365 :meth:`_asyncio.AsyncResult.scalars`
366
367 """
368 return await greenlet_spawn(self._only_one_row, True, False, True)
369
370 async def one(self) -> Row[_TP]:
371 """Return exactly one row or raise an exception.
372
373 Raises :class:`.NoResultFound` if the result returns no
374 rows, or :class:`.MultipleResultsFound` if multiple rows
375 would be returned.
376
377 .. note:: This method returns one **row**, e.g. tuple, by default.
378 To return exactly one single scalar value, that is, the first
379 column of the first row, use the
380 :meth:`_asyncio.AsyncResult.scalar_one` method, or combine
381 :meth:`_asyncio.AsyncResult.scalars` and
382 :meth:`_asyncio.AsyncResult.one`.
383
384 .. versionadded:: 1.4
385
386 :return: The first :class:`_engine.Row`.
387
388 :raises: :class:`.MultipleResultsFound`, :class:`.NoResultFound`
389
390 .. seealso::
391
392 :meth:`_asyncio.AsyncResult.first`
393
394 :meth:`_asyncio.AsyncResult.one_or_none`
395
396 :meth:`_asyncio.AsyncResult.scalar_one`
397
398 """
399 return await greenlet_spawn(self._only_one_row, True, True, False)
400
401 @overload
402 async def scalar(self: AsyncResult[Tuple[_T]]) -> Optional[_T]: ...
403
404 @overload
405 async def scalar(self) -> Any: ...
406
407 async def scalar(self) -> Any:
408 """Fetch the first column of the first row, and close the result set.
409
410 Returns ``None`` if there are no rows to fetch.
411
412 No validation is performed to test if additional rows remain.
413
414 After calling this method, the object is fully closed,
415 e.g. the :meth:`_engine.CursorResult.close`
416 method will have been called.
417
418 :return: a Python scalar value, or ``None`` if no rows remain.
419
420 """
421 return await greenlet_spawn(self._only_one_row, False, False, True)
422
423 async def freeze(self) -> FrozenResult[_TP]:
424 """Return a callable object that will produce copies of this
425 :class:`_asyncio.AsyncResult` when invoked.
426
427 The callable object returned is an instance of
428 :class:`_engine.FrozenResult`.
429
430 This is used for result set caching. The method must be called
431 on the result when it has been unconsumed, and calling the method
432 will consume the result fully. When the :class:`_engine.FrozenResult`
433 is retrieved from a cache, it can be called any number of times where
434 it will produce a new :class:`_engine.Result` object each time
435 against its stored set of rows.
436
437 .. seealso::
438
439 :ref:`do_orm_execute_re_executing` - example usage within the
440 ORM to implement a result-set cache.
441
442 """
443
444 return await greenlet_spawn(FrozenResult, self)
445
446 @overload
447 def scalars(
448 self: AsyncResult[Tuple[_T]], index: Literal[0]
449 ) -> AsyncScalarResult[_T]: ...
450
451 @overload
452 def scalars(self: AsyncResult[Tuple[_T]]) -> AsyncScalarResult[_T]: ...
453
454 @overload
455 def scalars(self, index: _KeyIndexType = 0) -> AsyncScalarResult[Any]: ...
456
457 def scalars(self, index: _KeyIndexType = 0) -> AsyncScalarResult[Any]:
458 """Return an :class:`_asyncio.AsyncScalarResult` filtering object which
459 will return single elements rather than :class:`_row.Row` objects.
460
461 Refer to :meth:`_result.Result.scalars` in the synchronous
462 SQLAlchemy API for a complete behavioral description.
463
464 :param index: integer or row key indicating the column to be fetched
465 from each row, defaults to ``0`` indicating the first column.
466
467 :return: a new :class:`_asyncio.AsyncScalarResult` filtering object
468 referring to this :class:`_asyncio.AsyncResult` object.
469
470 """
471 return AsyncScalarResult(self._real_result, index)
472
473 def mappings(self) -> AsyncMappingResult:
474 """Apply a mappings filter to returned rows, returning an instance of
475 :class:`_asyncio.AsyncMappingResult`.
476
477 When this filter is applied, fetching rows will return
478 :class:`_engine.RowMapping` objects instead of :class:`_engine.Row`
479 objects.
480
481 :return: a new :class:`_asyncio.AsyncMappingResult` filtering object
482 referring to the underlying :class:`_result.Result` object.
483
484 """
485
486 return AsyncMappingResult(self._real_result)
487
488
489class AsyncScalarResult(AsyncCommon[_R]):
490 """A wrapper for a :class:`_asyncio.AsyncResult` that returns scalar values
491 rather than :class:`_row.Row` values.
492
493 The :class:`_asyncio.AsyncScalarResult` object is acquired by calling the
494 :meth:`_asyncio.AsyncResult.scalars` method.
495
496 Refer to the :class:`_result.ScalarResult` object in the synchronous
497 SQLAlchemy API for a complete behavioral description.
498
499 .. versionadded:: 1.4
500
501 """
502
503 __slots__ = ()
504
505 _generate_rows = False
506
507 def __init__(self, real_result: Result[Any], index: _KeyIndexType):
508 self._real_result = real_result
509
510 if real_result._source_supports_scalars:
511 self._metadata = real_result._metadata
512 self._post_creational_filter = None
513 else:
514 self._metadata = real_result._metadata._reduce([index])
515 self._post_creational_filter = operator.itemgetter(0)
516
517 self._unique_filter_state = real_result._unique_filter_state
518
519 def unique(
520 self,
521 strategy: Optional[_UniqueFilterType] = None,
522 ) -> Self:
523 """Apply unique filtering to the objects returned by this
524 :class:`_asyncio.AsyncScalarResult`.
525
526 See :meth:`_asyncio.AsyncResult.unique` for usage details.
527
528 """
529 self._unique_filter_state = (set(), strategy)
530 return self
531
532 async def partitions(
533 self, size: Optional[int] = None
534 ) -> AsyncIterator[Sequence[_R]]:
535 """Iterate through sub-lists of elements of the size given.
536
537 Equivalent to :meth:`_asyncio.AsyncResult.partitions` except that
538 scalar values, rather than :class:`_engine.Row` objects,
539 are returned.
540
541 """
542
543 getter = self._manyrow_getter
544
545 while True:
546 partition = await greenlet_spawn(getter, self, size)
547 if partition:
548 yield partition
549 else:
550 break
551
552 async def fetchall(self) -> Sequence[_R]:
553 """A synonym for the :meth:`_asyncio.AsyncScalarResult.all` method."""
554
555 return await greenlet_spawn(self._allrows)
556
557 async def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
558 """Fetch many objects.
559
560 Equivalent to :meth:`_asyncio.AsyncResult.fetchmany` except that
561 scalar values, rather than :class:`_engine.Row` objects,
562 are returned.
563
564 """
565 return await greenlet_spawn(self._manyrow_getter, self, size)
566
567 async def all(self) -> Sequence[_R]:
568 """Return all scalar values in a list.
569
570 Equivalent to :meth:`_asyncio.AsyncResult.all` except that
571 scalar values, rather than :class:`_engine.Row` objects,
572 are returned.
573
574 """
575 return await greenlet_spawn(self._allrows)
576
577 def __aiter__(self) -> AsyncScalarResult[_R]:
578 return self
579
580 async def __anext__(self) -> _R:
581 row = await greenlet_spawn(self._onerow_getter, self)
582 if row is _NO_ROW:
583 raise StopAsyncIteration()
584 else:
585 return row
586
587 async def first(self) -> Optional[_R]:
588 """Fetch the first object or ``None`` if no object is present.
589
590 Equivalent to :meth:`_asyncio.AsyncResult.first` except that
591 scalar values, rather than :class:`_engine.Row` objects,
592 are returned.
593
594 """
595 return await greenlet_spawn(self._only_one_row, False, False, False)
596
597 async def one_or_none(self) -> Optional[_R]:
598 """Return at most one object or raise an exception.
599
600 Equivalent to :meth:`_asyncio.AsyncResult.one_or_none` except that
601 scalar values, rather than :class:`_engine.Row` objects,
602 are returned.
603
604 """
605 return await greenlet_spawn(self._only_one_row, True, False, False)
606
607 async def one(self) -> _R:
608 """Return exactly one object or raise an exception.
609
610 Equivalent to :meth:`_asyncio.AsyncResult.one` except that
611 scalar values, rather than :class:`_engine.Row` objects,
612 are returned.
613
614 """
615 return await greenlet_spawn(self._only_one_row, True, True, False)
616
617
618class AsyncMappingResult(_WithKeys, AsyncCommon[RowMapping]):
619 """A wrapper for a :class:`_asyncio.AsyncResult` that returns dictionary
620 values rather than :class:`_engine.Row` values.
621
622 The :class:`_asyncio.AsyncMappingResult` object is acquired by calling the
623 :meth:`_asyncio.AsyncResult.mappings` method.
624
625 Refer to the :class:`_result.MappingResult` object in the synchronous
626 SQLAlchemy API for a complete behavioral description.
627
628 .. versionadded:: 1.4
629
630 """
631
632 __slots__ = ()
633
634 _generate_rows = True
635
636 _post_creational_filter = operator.attrgetter("_mapping")
637
638 def __init__(self, result: Result[Any]):
639 self._real_result = result
640 self._unique_filter_state = result._unique_filter_state
641 self._metadata = result._metadata
642 if result._source_supports_scalars:
643 self._metadata = self._metadata._reduce([0])
644
645 def unique(
646 self,
647 strategy: Optional[_UniqueFilterType] = None,
648 ) -> Self:
649 """Apply unique filtering to the objects returned by this
650 :class:`_asyncio.AsyncMappingResult`.
651
652 See :meth:`_asyncio.AsyncResult.unique` for usage details.
653
654 """
655 self._unique_filter_state = (set(), strategy)
656 return self
657
658 def columns(self, *col_expressions: _KeyIndexType) -> Self:
659 r"""Establish the columns that should be returned in each row."""
660 return self._column_slices(col_expressions)
661
662 async def partitions(
663 self, size: Optional[int] = None
664 ) -> AsyncIterator[Sequence[RowMapping]]:
665 """Iterate through sub-lists of elements of the size given.
666
667 Equivalent to :meth:`_asyncio.AsyncResult.partitions` except that
668 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
669 objects, are returned.
670
671 """
672
673 getter = self._manyrow_getter
674
675 while True:
676 partition = await greenlet_spawn(getter, self, size)
677 if partition:
678 yield partition
679 else:
680 break
681
682 async def fetchall(self) -> Sequence[RowMapping]:
683 """A synonym for the :meth:`_asyncio.AsyncMappingResult.all` method."""
684
685 return await greenlet_spawn(self._allrows)
686
687 async def fetchone(self) -> Optional[RowMapping]:
688 """Fetch one object.
689
690 Equivalent to :meth:`_asyncio.AsyncResult.fetchone` except that
691 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
692 objects, are returned.
693
694 """
695
696 row = await greenlet_spawn(self._onerow_getter, self)
697 if row is _NO_ROW:
698 return None
699 else:
700 return row
701
702 async def fetchmany(
703 self, size: Optional[int] = None
704 ) -> Sequence[RowMapping]:
705 """Fetch many rows.
706
707 Equivalent to :meth:`_asyncio.AsyncResult.fetchmany` except that
708 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
709 objects, are returned.
710
711 """
712
713 return await greenlet_spawn(self._manyrow_getter, self, size)
714
715 async def all(self) -> Sequence[RowMapping]:
716 """Return all rows in a list.
717
718 Equivalent to :meth:`_asyncio.AsyncResult.all` except that
719 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
720 objects, are returned.
721
722 """
723
724 return await greenlet_spawn(self._allrows)
725
726 def __aiter__(self) -> AsyncMappingResult:
727 return self
728
729 async def __anext__(self) -> RowMapping:
730 row = await greenlet_spawn(self._onerow_getter, self)
731 if row is _NO_ROW:
732 raise StopAsyncIteration()
733 else:
734 return row
735
736 async def first(self) -> Optional[RowMapping]:
737 """Fetch the first object or ``None`` if no object is present.
738
739 Equivalent to :meth:`_asyncio.AsyncResult.first` except that
740 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
741 objects, are returned.
742
743 """
744 return await greenlet_spawn(self._only_one_row, False, False, False)
745
746 async def one_or_none(self) -> Optional[RowMapping]:
747 """Return at most one object or raise an exception.
748
749 Equivalent to :meth:`_asyncio.AsyncResult.one_or_none` except that
750 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
751 objects, are returned.
752
753 """
754 return await greenlet_spawn(self._only_one_row, True, False, False)
755
756 async def one(self) -> RowMapping:
757 """Return exactly one object or raise an exception.
758
759 Equivalent to :meth:`_asyncio.AsyncResult.one` except that
760 :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
761 objects, are returned.
762
763 """
764 return await greenlet_spawn(self._only_one_row, True, True, False)
765
766
767class AsyncTupleResult(AsyncCommon[_R], util.TypingOnly):
768 """A :class:`_asyncio.AsyncResult` that's typed as returning plain
769 Python tuples instead of rows.
770
771 Since :class:`_engine.Row` acts like a tuple in every way already,
772 this class is a typing only class, regular :class:`_asyncio.AsyncResult` is
773 still used at runtime.
774
775 """
776
777 __slots__ = ()
778
779 if TYPE_CHECKING:
780
781 async def partitions(
782 self, size: Optional[int] = None
783 ) -> AsyncIterator[Sequence[_R]]:
784 """Iterate through sub-lists of elements of the size given.
785
786 Equivalent to :meth:`_result.Result.partitions` except that
787 tuple values, rather than :class:`_engine.Row` objects,
788 are returned.
789
790 """
791 ...
792
793 async def fetchone(self) -> Optional[_R]:
794 """Fetch one tuple.
795
796 Equivalent to :meth:`_result.Result.fetchone` except that
797 tuple values, rather than :class:`_engine.Row`
798 objects, are returned.
799
800 """
801 ...
802
803 async def fetchall(self) -> Sequence[_R]:
804 """A synonym for the :meth:`_engine.ScalarResult.all` method."""
805 ...
806
807 async def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
808 """Fetch many objects.
809
810 Equivalent to :meth:`_result.Result.fetchmany` except that
811 tuple values, rather than :class:`_engine.Row` objects,
812 are returned.
813
814 """
815 ...
816
817 async def all(self) -> Sequence[_R]: # noqa: A001
818 """Return all scalar values in a list.
819
820 Equivalent to :meth:`_result.Result.all` except that
821 tuple values, rather than :class:`_engine.Row` objects,
822 are returned.
823
824 """
825 ...
826
827 async def __aiter__(self) -> AsyncIterator[_R]: ...
828
829 async def __anext__(self) -> _R: ...
830
831 async def first(self) -> Optional[_R]:
832 """Fetch the first object or ``None`` if no object is present.
833
834 Equivalent to :meth:`_result.Result.first` except that
835 tuple values, rather than :class:`_engine.Row` objects,
836 are returned.
837
838
839 """
840 ...
841
842 async def one_or_none(self) -> Optional[_R]:
843 """Return at most one object or raise an exception.
844
845 Equivalent to :meth:`_result.Result.one_or_none` except that
846 tuple values, rather than :class:`_engine.Row` objects,
847 are returned.
848
849 """
850 ...
851
852 async def one(self) -> _R:
853 """Return exactly one object or raise an exception.
854
855 Equivalent to :meth:`_result.Result.one` except that
856 tuple values, rather than :class:`_engine.Row` objects,
857 are returned.
858
859 """
860 ...
861
862 @overload
863 async def scalar_one(self: AsyncTupleResult[Tuple[_T]]) -> _T: ...
864
865 @overload
866 async def scalar_one(self) -> Any: ...
867
868 async def scalar_one(self) -> Any:
869 """Return exactly one scalar result or raise an exception.
870
871 This is equivalent to calling :meth:`_engine.Result.scalars`
872 and then :meth:`_engine.Result.one`.
873
874 .. seealso::
875
876 :meth:`_engine.Result.one`
877
878 :meth:`_engine.Result.scalars`
879
880 """
881 ...
882
883 @overload
884 async def scalar_one_or_none(
885 self: AsyncTupleResult[Tuple[_T]],
886 ) -> Optional[_T]: ...
887
888 @overload
889 async def scalar_one_or_none(self) -> Optional[Any]: ...
890
891 async def scalar_one_or_none(self) -> Optional[Any]:
892 """Return exactly one or no scalar result.
893
894 This is equivalent to calling :meth:`_engine.Result.scalars`
895 and then :meth:`_engine.Result.one_or_none`.
896
897 .. seealso::
898
899 :meth:`_engine.Result.one_or_none`
900
901 :meth:`_engine.Result.scalars`
902
903 """
904 ...
905
906 @overload
907 async def scalar(
908 self: AsyncTupleResult[Tuple[_T]],
909 ) -> Optional[_T]: ...
910
911 @overload
912 async def scalar(self) -> Any: ...
913
914 async def scalar(self) -> Any:
915 """Fetch the first column of the first row, and close the result
916 set.
917
918 Returns ``None`` if there are no rows to fetch.
919
920 No validation is performed to test if additional rows remain.
921
922 After calling this method, the object is fully closed,
923 e.g. the :meth:`_engine.CursorResult.close`
924 method will have been called.
925
926 :return: a Python scalar value , or ``None`` if no rows remain.
927
928 """
929 ...
930
931
932_RT = TypeVar("_RT", bound="Result[Any]")
933
934
935async def _ensure_sync_result(result: _RT, calling_method: Any) -> _RT:
936 cursor_result: CursorResult[Any]
937
938 try:
939 is_cursor = result._is_cursor
940 except AttributeError:
941 # legacy execute(DefaultGenerator) case
942 return result
943
944 if not is_cursor:
945 cursor_result = getattr(result, "raw", None) # type: ignore
946 else:
947 cursor_result = result # type: ignore
948 if cursor_result and cursor_result.context._is_server_side:
949 await greenlet_spawn(cursor_result.close)
950 raise async_exc.AsyncMethodRequired(
951 "Can't use the %s.%s() method with a "
952 "server-side cursor. "
953 "Use the %s.stream() method for an async "
954 "streaming result set."
955 % (
956 calling_method.__self__.__class__.__name__,
957 calling_method.__name__,
958 calling_method.__self__.__class__.__name__,
959 )
960 )
961 return result
962 