result.py 76 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399
  1. # engine/result.py
  2. # Copyright (C) 2005-2026 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
  7. """Define generic result set constructs."""
  8. from __future__ import annotations
  9. from enum import Enum
  10. import functools
  11. import itertools
  12. import operator
  13. import typing
  14. from typing import Any
  15. from typing import Callable
  16. from typing import cast
  17. from typing import Dict
  18. from typing import Generic
  19. from typing import Iterable
  20. from typing import Iterator
  21. from typing import List
  22. from typing import Mapping
  23. from typing import NoReturn
  24. from typing import Optional
  25. from typing import overload
  26. from typing import Sequence
  27. from typing import Set
  28. from typing import Tuple
  29. from typing import TYPE_CHECKING
  30. from typing import TypeVar
  31. from typing import Union
  32. from .row import Row
  33. from .row import RowMapping
  34. from .. import exc
  35. from .. import util
  36. from ..sql.base import _generative
  37. from ..sql.base import HasMemoized
  38. from ..sql.base import InPlaceGenerative
  39. from ..util import HasMemoized_ro_memoized_attribute
  40. from ..util import NONE_SET
  41. from ..util._has_cy import HAS_CYEXTENSION
  42. from ..util.typing import Literal
  43. from ..util.typing import Self
  44. if typing.TYPE_CHECKING or not HAS_CYEXTENSION:
  45. from ._py_row import tuplegetter as tuplegetter
  46. else:
  47. from sqlalchemy.cyextension.resultproxy import tuplegetter as tuplegetter
  48. if typing.TYPE_CHECKING:
  49. from typing import Type
  50. from .. import inspection
  51. from ..sql import roles
  52. from ..sql._typing import _HasClauseElement
  53. from ..sql.elements import SQLCoreOperations
  54. from ..sql.type_api import _ResultProcessorType
  55. _KeyType = Union[
  56. str,
  57. "SQLCoreOperations[Any]",
  58. "roles.TypedColumnsClauseRole[Any]",
  59. "roles.ColumnsClauseRole",
  60. "Type[Any]",
  61. "inspection.Inspectable[_HasClauseElement[Any]]",
  62. ]
  63. _KeyIndexType = Union[_KeyType, int]
  64. # is overridden in cursor using _CursorKeyMapRecType
  65. _KeyMapRecType = Any
  66. _KeyMapType = Mapping[_KeyType, _KeyMapRecType]
  67. _RowData = Union[Row[Any], RowMapping, Any]
  68. """A generic form of "row" that accommodates for the different kinds of
  69. "rows" that different result objects return, including row, row mapping, and
  70. scalar values"""
  71. _RawRowType = Tuple[Any, ...]
  72. """represents the kind of row we get from a DBAPI cursor"""
  73. _R = TypeVar("_R", bound=_RowData)
  74. _T = TypeVar("_T", bound=Any)
  75. _TP = TypeVar("_TP", bound=Tuple[Any, ...])
  76. _InterimRowType = Union[_R, _RawRowType]
  77. """a catchall "anything" kind of return type that can be applied
  78. across all the result types
  79. """
  80. _InterimSupportsScalarsRowType = Union[Row[Any], Any]
  81. _ProcessorsType = Sequence[Optional["_ResultProcessorType[Any]"]]
  82. _TupleGetterType = Callable[[Sequence[Any]], Sequence[Any]]
  83. _UniqueFilterType = Callable[[Any], Any]
  84. _UniqueFilterStateType = Tuple[Set[Any], Optional[_UniqueFilterType]]
  85. class ResultMetaData:
  86. """Base for metadata about result rows."""
  87. __slots__ = ()
  88. _tuplefilter: Optional[_TupleGetterType] = None
  89. _translated_indexes: Optional[Sequence[int]] = None
  90. _unique_filters: Optional[Sequence[Callable[[Any], Any]]] = None
  91. _keymap: _KeyMapType
  92. _keys: Sequence[str]
  93. _processors: Optional[_ProcessorsType]
  94. _key_to_index: Mapping[_KeyType, int]
  95. @property
  96. def keys(self) -> RMKeyView:
  97. return RMKeyView(self)
  98. def _has_key(self, key: object) -> bool:
  99. raise NotImplementedError()
  100. def _for_freeze(self) -> ResultMetaData:
  101. raise NotImplementedError()
  102. @overload
  103. def _key_fallback(
  104. self, key: Any, err: Optional[Exception], raiseerr: Literal[True] = ...
  105. ) -> NoReturn: ...
  106. @overload
  107. def _key_fallback(
  108. self,
  109. key: Any,
  110. err: Optional[Exception],
  111. raiseerr: Literal[False] = ...,
  112. ) -> None: ...
  113. @overload
  114. def _key_fallback(
  115. self, key: Any, err: Optional[Exception], raiseerr: bool = ...
  116. ) -> Optional[NoReturn]: ...
  117. def _key_fallback(
  118. self, key: Any, err: Optional[Exception], raiseerr: bool = True
  119. ) -> Optional[NoReturn]:
  120. assert raiseerr
  121. raise KeyError(key) from err
  122. def _raise_for_ambiguous_column_name(
  123. self, rec: _KeyMapRecType
  124. ) -> NoReturn:
  125. raise NotImplementedError(
  126. "ambiguous column name logic is implemented for "
  127. "CursorResultMetaData"
  128. )
  129. def _index_for_key(
  130. self, key: _KeyIndexType, raiseerr: bool
  131. ) -> Optional[int]:
  132. raise NotImplementedError()
  133. def _indexes_for_keys(
  134. self, keys: Sequence[_KeyIndexType]
  135. ) -> Sequence[int]:
  136. raise NotImplementedError()
  137. def _metadata_for_keys(
  138. self, keys: Sequence[_KeyIndexType]
  139. ) -> Iterator[_KeyMapRecType]:
  140. raise NotImplementedError()
  141. def _reduce(self, keys: Sequence[_KeyIndexType]) -> ResultMetaData:
  142. raise NotImplementedError()
  143. def _getter(
  144. self, key: Any, raiseerr: bool = True
  145. ) -> Optional[Callable[[Row[Any]], Any]]:
  146. index = self._index_for_key(key, raiseerr)
  147. if index is not None:
  148. return operator.itemgetter(index)
  149. else:
  150. return None
  151. def _row_as_tuple_getter(
  152. self, keys: Sequence[_KeyIndexType]
  153. ) -> _TupleGetterType:
  154. indexes = self._indexes_for_keys(keys)
  155. return tuplegetter(*indexes)
  156. def _make_key_to_index(
  157. self, keymap: Mapping[_KeyType, Sequence[Any]], index: int
  158. ) -> Mapping[_KeyType, int]:
  159. return {
  160. key: rec[index]
  161. for key, rec in keymap.items()
  162. if rec[index] is not None
  163. }
  164. def _key_not_found(self, key: Any, attr_error: bool) -> NoReturn:
  165. if key in self._keymap:
  166. # the index must be none in this case
  167. self._raise_for_ambiguous_column_name(self._keymap[key])
  168. else:
  169. # unknown key
  170. if attr_error:
  171. try:
  172. self._key_fallback(key, None)
  173. except KeyError as ke:
  174. raise AttributeError(ke.args[0]) from ke
  175. else:
  176. self._key_fallback(key, None)
  177. @property
  178. def _effective_processors(self) -> Optional[_ProcessorsType]:
  179. if not self._processors or NONE_SET.issuperset(self._processors):
  180. return None
  181. else:
  182. return self._processors
  183. class RMKeyView(typing.KeysView[Any]):
  184. __slots__ = ("_parent", "_keys")
  185. _parent: ResultMetaData
  186. _keys: Sequence[str]
  187. def __init__(self, parent: ResultMetaData):
  188. self._parent = parent
  189. self._keys = [k for k in parent._keys if k is not None]
  190. def __len__(self) -> int:
  191. return len(self._keys)
  192. def __repr__(self) -> str:
  193. return "{0.__class__.__name__}({0._keys!r})".format(self)
  194. def __iter__(self) -> Iterator[str]:
  195. return iter(self._keys)
  196. def __contains__(self, item: Any) -> bool:
  197. if isinstance(item, int):
  198. return False
  199. # note this also includes special key fallback behaviors
  200. # which also don't seem to be tested in test_resultset right now
  201. return self._parent._has_key(item)
  202. def __eq__(self, other: Any) -> bool:
  203. return list(other) == list(self)
  204. def __ne__(self, other: Any) -> bool:
  205. return list(other) != list(self)
  206. class SimpleResultMetaData(ResultMetaData):
  207. """result metadata for in-memory collections."""
  208. __slots__ = (
  209. "_keys",
  210. "_keymap",
  211. "_processors",
  212. "_tuplefilter",
  213. "_translated_indexes",
  214. "_unique_filters",
  215. "_key_to_index",
  216. )
  217. _keys: Sequence[str]
  218. def __init__(
  219. self,
  220. keys: Sequence[str],
  221. extra: Optional[Sequence[Any]] = None,
  222. _processors: Optional[_ProcessorsType] = None,
  223. _tuplefilter: Optional[_TupleGetterType] = None,
  224. _translated_indexes: Optional[Sequence[int]] = None,
  225. _unique_filters: Optional[Sequence[Callable[[Any], Any]]] = None,
  226. ):
  227. self._keys = list(keys)
  228. self._tuplefilter = _tuplefilter
  229. self._translated_indexes = _translated_indexes
  230. self._unique_filters = _unique_filters
  231. if extra:
  232. recs_names = [
  233. (
  234. (name,) + (extras if extras else ()),
  235. (index, name, extras),
  236. )
  237. for index, (name, extras) in enumerate(zip(self._keys, extra))
  238. ]
  239. else:
  240. recs_names = [
  241. ((name,), (index, name, ()))
  242. for index, name in enumerate(self._keys)
  243. ]
  244. self._keymap = {key: rec for keys, rec in recs_names for key in keys}
  245. self._processors = _processors
  246. self._key_to_index = self._make_key_to_index(self._keymap, 0)
  247. def _has_key(self, key: object) -> bool:
  248. return key in self._keymap
  249. def _for_freeze(self) -> ResultMetaData:
  250. unique_filters = self._unique_filters
  251. if unique_filters and self._tuplefilter:
  252. unique_filters = self._tuplefilter(unique_filters)
  253. # TODO: are we freezing the result with or without uniqueness
  254. # applied?
  255. return SimpleResultMetaData(
  256. self._keys,
  257. extra=[self._keymap[key][2] for key in self._keys],
  258. _unique_filters=unique_filters,
  259. )
  260. def __getstate__(self) -> Dict[str, Any]:
  261. return {
  262. "_keys": self._keys,
  263. "_translated_indexes": self._translated_indexes,
  264. }
  265. def __setstate__(self, state: Dict[str, Any]) -> None:
  266. if state["_translated_indexes"]:
  267. _translated_indexes = state["_translated_indexes"]
  268. _tuplefilter = tuplegetter(*_translated_indexes)
  269. else:
  270. _translated_indexes = _tuplefilter = None
  271. self.__init__( # type: ignore
  272. state["_keys"],
  273. _translated_indexes=_translated_indexes,
  274. _tuplefilter=_tuplefilter,
  275. )
  276. def _index_for_key(self, key: Any, raiseerr: bool = True) -> int:
  277. if int in key.__class__.__mro__:
  278. key = self._keys[key]
  279. try:
  280. rec = self._keymap[key]
  281. except KeyError as ke:
  282. rec = self._key_fallback(key, ke, raiseerr)
  283. return rec[0] # type: ignore[no-any-return]
  284. def _indexes_for_keys(self, keys: Sequence[Any]) -> Sequence[int]:
  285. return [self._keymap[key][0] for key in keys]
  286. def _metadata_for_keys(
  287. self, keys: Sequence[Any]
  288. ) -> Iterator[_KeyMapRecType]:
  289. for key in keys:
  290. if int in key.__class__.__mro__:
  291. key = self._keys[key]
  292. try:
  293. rec = self._keymap[key]
  294. except KeyError as ke:
  295. rec = self._key_fallback(key, ke, True)
  296. yield rec
  297. def _reduce(self, keys: Sequence[Any]) -> ResultMetaData:
  298. try:
  299. metadata_for_keys = [
  300. self._keymap[
  301. self._keys[key] if int in key.__class__.__mro__ else key
  302. ]
  303. for key in keys
  304. ]
  305. except KeyError as ke:
  306. self._key_fallback(ke.args[0], ke, True)
  307. indexes: Sequence[int]
  308. new_keys: Sequence[str]
  309. extra: Sequence[Any]
  310. indexes, new_keys, extra = zip(*metadata_for_keys)
  311. if self._translated_indexes:
  312. indexes = [self._translated_indexes[idx] for idx in indexes]
  313. tup = tuplegetter(*indexes)
  314. new_metadata = SimpleResultMetaData(
  315. new_keys,
  316. extra=extra,
  317. _tuplefilter=tup,
  318. _translated_indexes=indexes,
  319. _processors=self._processors,
  320. _unique_filters=self._unique_filters,
  321. )
  322. return new_metadata
  323. def result_tuple(
  324. fields: Sequence[str], extra: Optional[Any] = None
  325. ) -> Callable[[Iterable[Any]], Row[Any]]:
  326. parent = SimpleResultMetaData(fields, extra)
  327. return functools.partial(
  328. Row, parent, parent._effective_processors, parent._key_to_index
  329. )
  330. # a symbol that indicates to internal Result methods that
  331. # "no row is returned". We can't use None for those cases where a scalar
  332. # filter is applied to rows.
  333. class _NoRow(Enum):
  334. _NO_ROW = 0
  335. _NO_ROW = _NoRow._NO_ROW
  336. class ResultInternal(InPlaceGenerative, Generic[_R]):
  337. __slots__ = ()
  338. _real_result: Optional[Result[Any]] = None
  339. _generate_rows: bool = True
  340. _row_logging_fn: Optional[Callable[[Any], Any]]
  341. _unique_filter_state: Optional[_UniqueFilterStateType] = None
  342. _post_creational_filter: Optional[Callable[[Any], Any]] = None
  343. _is_cursor = False
  344. _metadata: ResultMetaData
  345. _source_supports_scalars: bool
  346. def _fetchiter_impl(self) -> Iterator[_InterimRowType[Row[Any]]]:
  347. raise NotImplementedError()
  348. def _fetchone_impl(
  349. self, hard_close: bool = False
  350. ) -> Optional[_InterimRowType[Row[Any]]]:
  351. raise NotImplementedError()
  352. def _fetchmany_impl(
  353. self, size: Optional[int] = None
  354. ) -> List[_InterimRowType[Row[Any]]]:
  355. raise NotImplementedError()
  356. def _fetchall_impl(self) -> List[_InterimRowType[Row[Any]]]:
  357. raise NotImplementedError()
  358. def _soft_close(self, hard: bool = False) -> None:
  359. raise NotImplementedError()
  360. @HasMemoized_ro_memoized_attribute
  361. def _row_getter(self) -> Optional[Callable[..., _R]]:
  362. real_result: Result[Any] = (
  363. self._real_result
  364. if self._real_result
  365. else cast("Result[Any]", self)
  366. )
  367. if real_result._source_supports_scalars:
  368. if not self._generate_rows:
  369. return None
  370. else:
  371. _proc = Row
  372. def process_row(
  373. metadata: ResultMetaData,
  374. processors: Optional[_ProcessorsType],
  375. key_to_index: Mapping[_KeyType, int],
  376. scalar_obj: Any,
  377. ) -> Row[Any]:
  378. return _proc(
  379. metadata, processors, key_to_index, (scalar_obj,)
  380. )
  381. else:
  382. process_row = Row # type: ignore
  383. metadata = self._metadata
  384. key_to_index = metadata._key_to_index
  385. processors = metadata._effective_processors
  386. tf = metadata._tuplefilter
  387. if tf and not real_result._source_supports_scalars:
  388. if processors:
  389. processors = tf(processors)
  390. _make_row_orig: Callable[..., _R] = functools.partial( # type: ignore # noqa E501
  391. process_row, metadata, processors, key_to_index
  392. )
  393. fixed_tf = tf
  394. def make_row(row: _InterimRowType[Row[Any]]) -> _R:
  395. return _make_row_orig(fixed_tf(row))
  396. else:
  397. make_row = functools.partial( # type: ignore
  398. process_row, metadata, processors, key_to_index
  399. )
  400. if real_result._row_logging_fn:
  401. _log_row = real_result._row_logging_fn
  402. _make_row = make_row
  403. def make_row(row: _InterimRowType[Row[Any]]) -> _R:
  404. return _log_row(_make_row(row)) # type: ignore
  405. return make_row
  406. @HasMemoized_ro_memoized_attribute
  407. def _iterator_getter(self) -> Callable[..., Iterator[_R]]:
  408. make_row = self._row_getter
  409. post_creational_filter = self._post_creational_filter
  410. if self._unique_filter_state:
  411. uniques, strategy = self._unique_strategy
  412. def iterrows(self: Result[Any]) -> Iterator[_R]:
  413. for raw_row in self._fetchiter_impl():
  414. obj: _InterimRowType[Any] = (
  415. make_row(raw_row) if make_row else raw_row
  416. )
  417. hashed = strategy(obj) if strategy else obj
  418. if hashed in uniques:
  419. continue
  420. uniques.add(hashed)
  421. if post_creational_filter:
  422. obj = post_creational_filter(obj)
  423. yield obj # type: ignore
  424. else:
  425. def iterrows(self: Result[Any]) -> Iterator[_R]:
  426. for raw_row in self._fetchiter_impl():
  427. row: _InterimRowType[Any] = (
  428. make_row(raw_row) if make_row else raw_row
  429. )
  430. if post_creational_filter:
  431. row = post_creational_filter(row)
  432. yield row # type: ignore
  433. return iterrows
  434. def _raw_all_rows(self) -> List[_R]:
  435. make_row = self._row_getter
  436. assert make_row is not None
  437. rows = self._fetchall_impl()
  438. return [make_row(row) for row in rows]
  439. def _allrows(self) -> List[_R]:
  440. post_creational_filter = self._post_creational_filter
  441. make_row = self._row_getter
  442. rows = self._fetchall_impl()
  443. made_rows: List[_InterimRowType[_R]]
  444. if make_row:
  445. made_rows = [make_row(row) for row in rows]
  446. else:
  447. made_rows = rows # type: ignore
  448. interim_rows: List[_R]
  449. if self._unique_filter_state:
  450. uniques, strategy = self._unique_strategy
  451. interim_rows = [
  452. made_row # type: ignore
  453. for made_row, sig_row in [
  454. (
  455. made_row,
  456. strategy(made_row) if strategy else made_row,
  457. )
  458. for made_row in made_rows
  459. ]
  460. if sig_row not in uniques and not uniques.add(sig_row) # type: ignore # noqa: E501
  461. ]
  462. else:
  463. interim_rows = made_rows # type: ignore
  464. if post_creational_filter:
  465. interim_rows = [
  466. post_creational_filter(row) for row in interim_rows
  467. ]
  468. return interim_rows
  469. @HasMemoized_ro_memoized_attribute
  470. def _onerow_getter(
  471. self,
  472. ) -> Callable[..., Union[Literal[_NoRow._NO_ROW], _R]]:
  473. make_row = self._row_getter
  474. post_creational_filter = self._post_creational_filter
  475. if self._unique_filter_state:
  476. uniques, strategy = self._unique_strategy
  477. def onerow(self: Result[Any]) -> Union[_NoRow, _R]:
  478. _onerow = self._fetchone_impl
  479. while True:
  480. row = _onerow()
  481. if row is None:
  482. return _NO_ROW
  483. else:
  484. obj: _InterimRowType[Any] = (
  485. make_row(row) if make_row else row
  486. )
  487. hashed = strategy(obj) if strategy else obj
  488. if hashed in uniques:
  489. continue
  490. else:
  491. uniques.add(hashed)
  492. if post_creational_filter:
  493. obj = post_creational_filter(obj)
  494. return obj # type: ignore
  495. else:
  496. def onerow(self: Result[Any]) -> Union[_NoRow, _R]:
  497. row = self._fetchone_impl()
  498. if row is None:
  499. return _NO_ROW
  500. else:
  501. interim_row: _InterimRowType[Any] = (
  502. make_row(row) if make_row else row
  503. )
  504. if post_creational_filter:
  505. interim_row = post_creational_filter(interim_row)
  506. return interim_row # type: ignore
  507. return onerow
  508. @HasMemoized_ro_memoized_attribute
  509. def _manyrow_getter(self) -> Callable[..., List[_R]]:
  510. make_row = self._row_getter
  511. post_creational_filter = self._post_creational_filter
  512. if self._unique_filter_state:
  513. uniques, strategy = self._unique_strategy
  514. def filterrows(
  515. make_row: Optional[Callable[..., _R]],
  516. rows: List[Any],
  517. strategy: Optional[Callable[[List[Any]], Any]],
  518. uniques: Set[Any],
  519. ) -> List[_R]:
  520. if make_row:
  521. rows = [make_row(row) for row in rows]
  522. if strategy:
  523. made_rows = (
  524. (made_row, strategy(made_row)) for made_row in rows
  525. )
  526. else:
  527. made_rows = ((made_row, made_row) for made_row in rows)
  528. return [
  529. made_row
  530. for made_row, sig_row in made_rows
  531. if sig_row not in uniques and not uniques.add(sig_row) # type: ignore # noqa: E501
  532. ]
  533. def manyrows(
  534. self: ResultInternal[_R], num: Optional[int]
  535. ) -> List[_R]:
  536. collect: List[_R] = []
  537. _manyrows = self._fetchmany_impl
  538. if num is None:
  539. # if None is passed, we don't know the default
  540. # manyrows number, DBAPI has this as cursor.arraysize
  541. # different DBAPIs / fetch strategies may be different.
  542. # do a fetch to find what the number is. if there are
  543. # only fewer rows left, then it doesn't matter.
  544. real_result = (
  545. self._real_result
  546. if self._real_result
  547. else cast("Result[Any]", self)
  548. )
  549. if real_result._yield_per:
  550. num_required = num = real_result._yield_per
  551. else:
  552. rows = _manyrows(num)
  553. num = len(rows)
  554. assert make_row is not None
  555. collect.extend(
  556. filterrows(make_row, rows, strategy, uniques)
  557. )
  558. num_required = num - len(collect)
  559. else:
  560. num_required = num
  561. assert num is not None
  562. while num_required:
  563. rows = _manyrows(num_required)
  564. if not rows:
  565. break
  566. collect.extend(
  567. filterrows(make_row, rows, strategy, uniques)
  568. )
  569. num_required = num - len(collect)
  570. if post_creational_filter:
  571. collect = [post_creational_filter(row) for row in collect]
  572. return collect
  573. else:
  574. def manyrows(
  575. self: ResultInternal[_R], num: Optional[int]
  576. ) -> List[_R]:
  577. if num is None:
  578. real_result = (
  579. self._real_result
  580. if self._real_result
  581. else cast("Result[Any]", self)
  582. )
  583. num = real_result._yield_per
  584. rows: List[_InterimRowType[Any]] = self._fetchmany_impl(num)
  585. if make_row:
  586. rows = [make_row(row) for row in rows]
  587. if post_creational_filter:
  588. rows = [post_creational_filter(row) for row in rows]
  589. return rows # type: ignore
  590. return manyrows
  591. @overload
  592. def _only_one_row(
  593. self: ResultInternal[Row[Any]],
  594. raise_for_second_row: bool,
  595. raise_for_none: bool,
  596. scalar: Literal[True],
  597. ) -> Any: ...
  598. @overload
  599. def _only_one_row(
  600. self,
  601. raise_for_second_row: bool,
  602. raise_for_none: Literal[True],
  603. scalar: bool,
  604. ) -> _R: ...
  605. @overload
  606. def _only_one_row(
  607. self,
  608. raise_for_second_row: bool,
  609. raise_for_none: bool,
  610. scalar: bool,
  611. ) -> Optional[_R]: ...
  612. def _only_one_row(
  613. self,
  614. raise_for_second_row: bool,
  615. raise_for_none: bool,
  616. scalar: bool,
  617. ) -> Optional[_R]:
  618. onerow = self._fetchone_impl
  619. row: Optional[_InterimRowType[Any]] = onerow(hard_close=True)
  620. if row is None:
  621. if raise_for_none:
  622. raise exc.NoResultFound(
  623. "No row was found when one was required"
  624. )
  625. else:
  626. return None
  627. if scalar and self._source_supports_scalars:
  628. self._generate_rows = False
  629. make_row = None
  630. else:
  631. make_row = self._row_getter
  632. try:
  633. row = make_row(row) if make_row else row
  634. except:
  635. self._soft_close(hard=True)
  636. raise
  637. if raise_for_second_row:
  638. if self._unique_filter_state:
  639. # for no second row but uniqueness, need to essentially
  640. # consume the entire result :(
  641. uniques, strategy = self._unique_strategy
  642. existing_row_hash = strategy(row) if strategy else row
  643. while True:
  644. next_row: Any = onerow(hard_close=True)
  645. if next_row is None:
  646. next_row = _NO_ROW
  647. break
  648. try:
  649. next_row = make_row(next_row) if make_row else next_row
  650. if strategy:
  651. assert next_row is not _NO_ROW
  652. if existing_row_hash == strategy(next_row):
  653. continue
  654. elif row == next_row:
  655. continue
  656. # here, we have a row and it's different
  657. break
  658. except:
  659. self._soft_close(hard=True)
  660. raise
  661. else:
  662. next_row = onerow(hard_close=True)
  663. if next_row is None:
  664. next_row = _NO_ROW
  665. if next_row is not _NO_ROW:
  666. self._soft_close(hard=True)
  667. raise exc.MultipleResultsFound(
  668. "Multiple rows were found when exactly one was required"
  669. if raise_for_none
  670. else "Multiple rows were found when one or none "
  671. "was required"
  672. )
  673. else:
  674. # if we checked for second row then that would have
  675. # closed us :)
  676. self._soft_close(hard=True)
  677. if not scalar:
  678. post_creational_filter = self._post_creational_filter
  679. if post_creational_filter:
  680. row = post_creational_filter(row)
  681. if scalar and make_row:
  682. return row[0] # type: ignore
  683. else:
  684. return row # type: ignore
  685. def _iter_impl(self) -> Iterator[_R]:
  686. return self._iterator_getter(self)
  687. def _next_impl(self) -> _R:
  688. row = self._onerow_getter(self)
  689. if row is _NO_ROW:
  690. raise StopIteration()
  691. else:
  692. return row
  693. @_generative
  694. def _column_slices(self, indexes: Sequence[_KeyIndexType]) -> Self:
  695. real_result = (
  696. self._real_result
  697. if self._real_result
  698. else cast("Result[Any]", self)
  699. )
  700. if not real_result._source_supports_scalars or len(indexes) != 1:
  701. self._metadata = self._metadata._reduce(indexes)
  702. assert self._generate_rows
  703. return self
  704. @HasMemoized.memoized_attribute
  705. def _unique_strategy(self) -> _UniqueFilterStateType:
  706. assert self._unique_filter_state is not None
  707. uniques, strategy = self._unique_filter_state
  708. real_result = (
  709. self._real_result
  710. if self._real_result is not None
  711. else cast("Result[Any]", self)
  712. )
  713. if not strategy and self._metadata._unique_filters:
  714. if (
  715. real_result._source_supports_scalars
  716. and not self._generate_rows
  717. ):
  718. strategy = self._metadata._unique_filters[0]
  719. else:
  720. filters = self._metadata._unique_filters
  721. if self._metadata._tuplefilter:
  722. filters = self._metadata._tuplefilter(filters)
  723. strategy = operator.methodcaller("_filter_on_values", filters)
  724. return uniques, strategy
  725. class _WithKeys:
  726. __slots__ = ()
  727. _metadata: ResultMetaData
  728. # used mainly to share documentation on the keys method.
  729. def keys(self) -> RMKeyView:
  730. """Return an iterable view which yields the string keys that would
  731. be represented by each :class:`_engine.Row`.
  732. The keys can represent the labels of the columns returned by a core
  733. statement or the names of the orm classes returned by an orm
  734. execution.
  735. The view also can be tested for key containment using the Python
  736. ``in`` operator, which will test both for the string keys represented
  737. in the view, as well as for alternate keys such as column objects.
  738. .. versionchanged:: 1.4 a key view object is returned rather than a
  739. plain list.
  740. """
  741. return self._metadata.keys
  742. class Result(_WithKeys, ResultInternal[Row[_TP]]):
  743. """Represent a set of database results.
  744. .. versionadded:: 1.4 The :class:`_engine.Result` object provides a
  745. completely updated usage model and calling facade for SQLAlchemy
  746. Core and SQLAlchemy ORM. In Core, it forms the basis of the
  747. :class:`_engine.CursorResult` object which replaces the previous
  748. :class:`_engine.ResultProxy` interface. When using the ORM, a
  749. higher level object called :class:`_engine.ChunkedIteratorResult`
  750. is normally used.
  751. .. note:: In SQLAlchemy 1.4 and above, this object is
  752. used for ORM results returned by :meth:`_orm.Session.execute`, which can
  753. yield instances of ORM mapped objects either individually or within
  754. tuple-like rows. Note that the :class:`_engine.Result` object does not
  755. deduplicate instances or rows automatically as is the case with the
  756. legacy :class:`_orm.Query` object. For in-Python de-duplication of
  757. instances or rows, use the :meth:`_engine.Result.unique` modifier
  758. method.
  759. .. seealso::
  760. :ref:`tutorial_fetching_rows` - in the :doc:`/tutorial/index`
  761. """
  762. __slots__ = ("_metadata", "__dict__")
  763. _row_logging_fn: Optional[Callable[[Row[Any]], Row[Any]]] = None
  764. _source_supports_scalars: bool = False
  765. _yield_per: Optional[int] = None
  766. _attributes: util.immutabledict[Any, Any] = util.immutabledict()
  767. def __init__(self, cursor_metadata: ResultMetaData):
  768. self._metadata = cursor_metadata
  769. def __enter__(self) -> Self:
  770. return self
  771. def __exit__(self, type_: Any, value: Any, traceback: Any) -> None:
  772. self.close()
  773. def close(self) -> None:
  774. """close this :class:`_engine.Result`.
  775. The behavior of this method is implementation specific, and is
  776. not implemented by default. The method should generally end
  777. the resources in use by the result object and also cause any
  778. subsequent iteration or row fetching to raise
  779. :class:`.ResourceClosedError`.
  780. .. versionadded:: 1.4.27 - ``.close()`` was previously not generally
  781. available for all :class:`_engine.Result` classes, instead only
  782. being available on the :class:`_engine.CursorResult` returned for
  783. Core statement executions. As most other result objects, namely the
  784. ones used by the ORM, are proxying a :class:`_engine.CursorResult`
  785. in any case, this allows the underlying cursor result to be closed
  786. from the outside facade for the case when the ORM query is using
  787. the ``yield_per`` execution option where it does not immediately
  788. exhaust and autoclose the database cursor.
  789. """
  790. self._soft_close(hard=True)
  791. @property
  792. def _soft_closed(self) -> bool:
  793. raise NotImplementedError()
  794. @property
  795. def closed(self) -> bool:
  796. """return ``True`` if this :class:`_engine.Result` reports .closed
  797. .. versionadded:: 1.4.43
  798. """
  799. raise NotImplementedError()
  800. @_generative
  801. def yield_per(self, num: int) -> Self:
  802. """Configure the row-fetching strategy to fetch ``num`` rows at a time.
  803. This impacts the underlying behavior of the result when iterating over
  804. the result object, or otherwise making use of methods such as
  805. :meth:`_engine.Result.fetchone` that return one row at a time. Data
  806. from the underlying cursor or other data source will be buffered up to
  807. this many rows in memory, and the buffered collection will then be
  808. yielded out one row at a time or as many rows are requested. Each time
  809. the buffer clears, it will be refreshed to this many rows or as many
  810. rows remain if fewer remain.
  811. The :meth:`_engine.Result.yield_per` method is generally used in
  812. conjunction with the
  813. :paramref:`_engine.Connection.execution_options.stream_results`
  814. execution option, which will allow the database dialect in use to make
  815. use of a server side cursor, if the DBAPI supports a specific "server
  816. side cursor" mode separate from its default mode of operation.
  817. .. tip::
  818. Consider using the
  819. :paramref:`_engine.Connection.execution_options.yield_per`
  820. execution option, which will simultaneously set
  821. :paramref:`_engine.Connection.execution_options.stream_results`
  822. to ensure the use of server side cursors, as well as automatically
  823. invoke the :meth:`_engine.Result.yield_per` method to establish
  824. a fixed row buffer size at once.
  825. The :paramref:`_engine.Connection.execution_options.yield_per`
  826. execution option is available for ORM operations, with
  827. :class:`_orm.Session`-oriented use described at
  828. :ref:`orm_queryguide_yield_per`. The Core-only version which works
  829. with :class:`_engine.Connection` is new as of SQLAlchemy 1.4.40.
  830. .. versionadded:: 1.4
  831. :param num: number of rows to fetch each time the buffer is refilled.
  832. If set to a value below 1, fetches all rows for the next buffer.
  833. .. seealso::
  834. :ref:`engine_stream_results` - describes Core behavior for
  835. :meth:`_engine.Result.yield_per`
  836. :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel`
  837. """
  838. self._yield_per = num
  839. return self
  840. @_generative
  841. def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
  842. """Apply unique filtering to the objects returned by this
  843. :class:`_engine.Result`.
  844. When this filter is applied with no arguments, the rows or objects
  845. returned will filtered such that each row is returned uniquely. The
  846. algorithm used to determine this uniqueness is by default the Python
  847. hashing identity of the whole tuple. In some cases a specialized
  848. per-entity hashing scheme may be used, such as when using the ORM, a
  849. scheme is applied which works against the primary key identity of
  850. returned objects.
  851. The unique filter is applied **after all other filters**, which means
  852. if the columns returned have been refined using a method such as the
  853. :meth:`_engine.Result.columns` or :meth:`_engine.Result.scalars`
  854. method, the uniquing is applied to **only the column or columns
  855. returned**. This occurs regardless of the order in which these
  856. methods have been called upon the :class:`_engine.Result` object.
  857. The unique filter also changes the calculus used for methods like
  858. :meth:`_engine.Result.fetchmany` and :meth:`_engine.Result.partitions`.
  859. When using :meth:`_engine.Result.unique`, these methods will continue
  860. to yield the number of rows or objects requested, after uniquing
  861. has been applied. However, this necessarily impacts the buffering
  862. behavior of the underlying cursor or datasource, such that multiple
  863. underlying calls to ``cursor.fetchmany()`` may be necessary in order
  864. to accumulate enough objects in order to provide a unique collection
  865. of the requested size.
  866. :param strategy: a callable that will be applied to rows or objects
  867. being iterated, which should return an object that represents the
  868. unique value of the row. A Python ``set()`` is used to store
  869. these identities. If not passed, a default uniqueness strategy
  870. is used which may have been assembled by the source of this
  871. :class:`_engine.Result` object.
  872. """
  873. self._unique_filter_state = (set(), strategy)
  874. return self
  875. def columns(self, *col_expressions: _KeyIndexType) -> Self:
  876. r"""Establish the columns that should be returned in each row.
  877. This method may be used to limit the columns returned as well
  878. as to reorder them. The given list of expressions are normally
  879. a series of integers or string key names. They may also be
  880. appropriate :class:`.ColumnElement` objects which correspond to
  881. a given statement construct.
  882. .. versionchanged:: 2.0 Due to a bug in 1.4, the
  883. :meth:`_engine.Result.columns` method had an incorrect behavior
  884. where calling upon the method with just one index would cause the
  885. :class:`_engine.Result` object to yield scalar values rather than
  886. :class:`_engine.Row` objects. In version 2.0, this behavior
  887. has been corrected such that calling upon
  888. :meth:`_engine.Result.columns` with a single index will
  889. produce a :class:`_engine.Result` object that continues
  890. to yield :class:`_engine.Row` objects, which include
  891. only a single column.
  892. E.g.::
  893. statement = select(table.c.x, table.c.y, table.c.z)
  894. result = connection.execute(statement)
  895. for z, y in result.columns("z", "y"):
  896. ...
  897. Example of using the column objects from the statement itself::
  898. for z, y in result.columns(
  899. statement.selected_columns.c.z, statement.selected_columns.c.y
  900. ):
  901. ...
  902. .. versionadded:: 1.4
  903. :param \*col_expressions: indicates columns to be returned. Elements
  904. may be integer row indexes, string column names, or appropriate
  905. :class:`.ColumnElement` objects corresponding to a select construct.
  906. :return: this :class:`_engine.Result` object with the modifications
  907. given.
  908. """
  909. return self._column_slices(col_expressions)
  910. @overload
  911. def scalars(self: Result[Tuple[_T]]) -> ScalarResult[_T]: ...
  912. @overload
  913. def scalars(
  914. self: Result[Tuple[_T]], index: Literal[0]
  915. ) -> ScalarResult[_T]: ...
  916. @overload
  917. def scalars(self, index: _KeyIndexType = 0) -> ScalarResult[Any]: ...
  918. def scalars(self, index: _KeyIndexType = 0) -> ScalarResult[Any]:
  919. """Return a :class:`_engine.ScalarResult` filtering object which
  920. will return single elements rather than :class:`_row.Row` objects.
  921. E.g.::
  922. >>> result = conn.execute(text("select int_id from table"))
  923. >>> result.scalars().all()
  924. [1, 2, 3]
  925. When results are fetched from the :class:`_engine.ScalarResult`
  926. filtering object, the single column-row that would be returned by the
  927. :class:`_engine.Result` is instead returned as the column's value.
  928. .. versionadded:: 1.4
  929. :param index: integer or row key indicating the column to be fetched
  930. from each row, defaults to ``0`` indicating the first column.
  931. :return: a new :class:`_engine.ScalarResult` filtering object referring
  932. to this :class:`_engine.Result` object.
  933. """
  934. return ScalarResult(self, index)
  935. def _getter(
  936. self, key: _KeyIndexType, raiseerr: bool = True
  937. ) -> Optional[Callable[[Row[Any]], Any]]:
  938. """return a callable that will retrieve the given key from a
  939. :class:`_engine.Row`.
  940. """
  941. if self._source_supports_scalars:
  942. raise NotImplementedError(
  943. "can't use this function in 'only scalars' mode"
  944. )
  945. return self._metadata._getter(key, raiseerr)
  946. def _tuple_getter(self, keys: Sequence[_KeyIndexType]) -> _TupleGetterType:
  947. """return a callable that will retrieve the given keys from a
  948. :class:`_engine.Row`.
  949. """
  950. if self._source_supports_scalars:
  951. raise NotImplementedError(
  952. "can't use this function in 'only scalars' mode"
  953. )
  954. return self._metadata._row_as_tuple_getter(keys)
  955. def mappings(self) -> MappingResult:
  956. """Apply a mappings filter to returned rows, returning an instance of
  957. :class:`_engine.MappingResult`.
  958. When this filter is applied, fetching rows will return
  959. :class:`_engine.RowMapping` objects instead of :class:`_engine.Row`
  960. objects.
  961. .. versionadded:: 1.4
  962. :return: a new :class:`_engine.MappingResult` filtering object
  963. referring to this :class:`_engine.Result` object.
  964. """
  965. return MappingResult(self)
  966. @property
  967. def t(self) -> TupleResult[_TP]:
  968. """Apply a "typed tuple" typing filter to returned rows.
  969. The :attr:`_engine.Result.t` attribute is a synonym for
  970. calling the :meth:`_engine.Result.tuples` method.
  971. .. versionadded:: 2.0
  972. """
  973. return self # type: ignore
  974. def tuples(self) -> TupleResult[_TP]:
  975. """Apply a "typed tuple" typing filter to returned rows.
  976. This method returns the same :class:`_engine.Result` object
  977. at runtime,
  978. however annotates as returning a :class:`_engine.TupleResult` object
  979. that will indicate to :pep:`484` typing tools that plain typed
  980. ``Tuple`` instances are returned rather than rows. This allows
  981. tuple unpacking and ``__getitem__`` access of :class:`_engine.Row`
  982. objects to by typed, for those cases where the statement invoked
  983. itself included typing information.
  984. .. versionadded:: 2.0
  985. :return: the :class:`_engine.TupleResult` type at typing time.
  986. .. seealso::
  987. :attr:`_engine.Result.t` - shorter synonym
  988. :attr:`_engine.Row._t` - :class:`_engine.Row` version
  989. """
  990. return self # type: ignore
  991. def _raw_row_iterator(self) -> Iterator[_RowData]:
  992. """Return a safe iterator that yields raw row data.
  993. This is used by the :meth:`_engine.Result.merge` method
  994. to merge multiple compatible results together.
  995. """
  996. raise NotImplementedError()
  997. def __iter__(self) -> Iterator[Row[_TP]]:
  998. return self._iter_impl()
  999. def __next__(self) -> Row[_TP]:
  1000. return self._next_impl()
  1001. def partitions(
  1002. self, size: Optional[int] = None
  1003. ) -> Iterator[Sequence[Row[_TP]]]:
  1004. """Iterate through sub-lists of rows of the size given.
  1005. Each list will be of the size given, excluding the last list to
  1006. be yielded, which may have a small number of rows. No empty
  1007. lists will be yielded.
  1008. The result object is automatically closed when the iterator
  1009. is fully consumed.
  1010. Note that the backend driver will usually buffer the entire result
  1011. ahead of time unless the
  1012. :paramref:`.Connection.execution_options.stream_results` execution
  1013. option is used indicating that the driver should not pre-buffer
  1014. results, if possible. Not all drivers support this option and
  1015. the option is silently ignored for those who do not.
  1016. When using the ORM, the :meth:`_engine.Result.partitions` method
  1017. is typically more effective from a memory perspective when it is
  1018. combined with use of the
  1019. :ref:`yield_per execution option <orm_queryguide_yield_per>`,
  1020. which instructs both the DBAPI driver to use server side cursors,
  1021. if available, as well as instructs the ORM loading internals to only
  1022. build a certain amount of ORM objects from a result at a time before
  1023. yielding them out.
  1024. .. versionadded:: 1.4
  1025. :param size: indicate the maximum number of rows to be present
  1026. in each list yielded. If None, makes use of the value set by
  1027. the :meth:`_engine.Result.yield_per`, method, if it were called,
  1028. or the :paramref:`_engine.Connection.execution_options.yield_per`
  1029. execution option, which is equivalent in this regard. If
  1030. yield_per weren't set, it makes use of the
  1031. :meth:`_engine.Result.fetchmany` default, which may be backend
  1032. specific and not well defined.
  1033. :return: iterator of lists
  1034. .. seealso::
  1035. :ref:`engine_stream_results`
  1036. :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel`
  1037. """
  1038. getter = self._manyrow_getter
  1039. while True:
  1040. partition = getter(self, size)
  1041. if partition:
  1042. yield partition
  1043. else:
  1044. break
  1045. def fetchall(self) -> Sequence[Row[_TP]]:
  1046. """A synonym for the :meth:`_engine.Result.all` method."""
  1047. return self._allrows()
  1048. def fetchone(self) -> Optional[Row[_TP]]:
  1049. """Fetch one row.
  1050. When all rows are exhausted, returns None.
  1051. This method is provided for backwards compatibility with
  1052. SQLAlchemy 1.x.x.
  1053. To fetch the first row of a result only, use the
  1054. :meth:`_engine.Result.first` method. To iterate through all
  1055. rows, iterate the :class:`_engine.Result` object directly.
  1056. :return: a :class:`_engine.Row` object if no filters are applied,
  1057. or ``None`` if no rows remain.
  1058. """
  1059. row = self._onerow_getter(self)
  1060. if row is _NO_ROW:
  1061. return None
  1062. else:
  1063. return row
  1064. def fetchmany(self, size: Optional[int] = None) -> Sequence[Row[_TP]]:
  1065. """Fetch many rows.
  1066. When all rows are exhausted, returns an empty sequence.
  1067. This method is provided for backwards compatibility with
  1068. SQLAlchemy 1.x.x.
  1069. To fetch rows in groups, use the :meth:`_engine.Result.partitions`
  1070. method.
  1071. :return: a sequence of :class:`_engine.Row` objects.
  1072. .. seealso::
  1073. :meth:`_engine.Result.partitions`
  1074. """
  1075. return self._manyrow_getter(self, size)
  1076. def all(self) -> Sequence[Row[_TP]]:
  1077. """Return all rows in a sequence.
  1078. Closes the result set after invocation. Subsequent invocations
  1079. will return an empty sequence.
  1080. .. versionadded:: 1.4
  1081. :return: a sequence of :class:`_engine.Row` objects.
  1082. .. seealso::
  1083. :ref:`engine_stream_results` - How to stream a large result set
  1084. without loading it completely in python.
  1085. """
  1086. return self._allrows()
  1087. def first(self) -> Optional[Row[_TP]]:
  1088. """Fetch the first row or ``None`` if no row is present.
  1089. Closes the result set and discards remaining rows.
  1090. .. note:: This method returns one **row**, e.g. tuple, by default.
  1091. To return exactly one single scalar value, that is, the first
  1092. column of the first row, use the
  1093. :meth:`_engine.Result.scalar` method,
  1094. or combine :meth:`_engine.Result.scalars` and
  1095. :meth:`_engine.Result.first`.
  1096. Additionally, in contrast to the behavior of the legacy ORM
  1097. :meth:`_orm.Query.first` method, **no limit is applied** to the
  1098. SQL query which was invoked to produce this
  1099. :class:`_engine.Result`;
  1100. for a DBAPI driver that buffers results in memory before yielding
  1101. rows, all rows will be sent to the Python process and all but
  1102. the first row will be discarded.
  1103. .. seealso::
  1104. :ref:`migration_20_unify_select`
  1105. :return: a :class:`_engine.Row` object, or None
  1106. if no rows remain.
  1107. .. seealso::
  1108. :meth:`_engine.Result.scalar`
  1109. :meth:`_engine.Result.one`
  1110. """
  1111. return self._only_one_row(
  1112. raise_for_second_row=False, raise_for_none=False, scalar=False
  1113. )
  1114. def one_or_none(self) -> Optional[Row[_TP]]:
  1115. """Return at most one result or raise an exception.
  1116. Returns ``None`` if the result has no rows.
  1117. Raises :class:`.MultipleResultsFound`
  1118. if multiple rows are returned.
  1119. .. versionadded:: 1.4
  1120. :return: The first :class:`_engine.Row` or ``None`` if no row
  1121. is available.
  1122. :raises: :class:`.MultipleResultsFound`
  1123. .. seealso::
  1124. :meth:`_engine.Result.first`
  1125. :meth:`_engine.Result.one`
  1126. """
  1127. return self._only_one_row(
  1128. raise_for_second_row=True, raise_for_none=False, scalar=False
  1129. )
  1130. @overload
  1131. def scalar_one(self: Result[Tuple[_T]]) -> _T: ...
  1132. @overload
  1133. def scalar_one(self) -> Any: ...
  1134. def scalar_one(self) -> Any:
  1135. """Return exactly one scalar result or raise an exception.
  1136. This is equivalent to calling :meth:`_engine.Result.scalars` and
  1137. then :meth:`_engine.ScalarResult.one`.
  1138. .. seealso::
  1139. :meth:`_engine.ScalarResult.one`
  1140. :meth:`_engine.Result.scalars`
  1141. """
  1142. return self._only_one_row(
  1143. raise_for_second_row=True, raise_for_none=True, scalar=True
  1144. )
  1145. @overload
  1146. def scalar_one_or_none(self: Result[Tuple[_T]]) -> Optional[_T]: ...
  1147. @overload
  1148. def scalar_one_or_none(self) -> Optional[Any]: ...
  1149. def scalar_one_or_none(self) -> Optional[Any]:
  1150. """Return exactly one scalar result or ``None``.
  1151. This is equivalent to calling :meth:`_engine.Result.scalars` and
  1152. then :meth:`_engine.ScalarResult.one_or_none`.
  1153. .. seealso::
  1154. :meth:`_engine.ScalarResult.one_or_none`
  1155. :meth:`_engine.Result.scalars`
  1156. """
  1157. return self._only_one_row(
  1158. raise_for_second_row=True, raise_for_none=False, scalar=True
  1159. )
  1160. def one(self) -> Row[_TP]:
  1161. """Return exactly one row or raise an exception.
  1162. Raises :class:`_exc.NoResultFound` if the result returns no
  1163. rows, or :class:`_exc.MultipleResultsFound` if multiple rows
  1164. would be returned.
  1165. .. note:: This method returns one **row**, e.g. tuple, by default.
  1166. To return exactly one single scalar value, that is, the first
  1167. column of the first row, use the
  1168. :meth:`_engine.Result.scalar_one` method, or combine
  1169. :meth:`_engine.Result.scalars` and
  1170. :meth:`_engine.Result.one`.
  1171. .. versionadded:: 1.4
  1172. :return: The first :class:`_engine.Row`.
  1173. :raises: :class:`.MultipleResultsFound`, :class:`.NoResultFound`
  1174. .. seealso::
  1175. :meth:`_engine.Result.first`
  1176. :meth:`_engine.Result.one_or_none`
  1177. :meth:`_engine.Result.scalar_one`
  1178. """
  1179. return self._only_one_row(
  1180. raise_for_second_row=True, raise_for_none=True, scalar=False
  1181. )
  1182. @overload
  1183. def scalar(self: Result[Tuple[_T]]) -> Optional[_T]: ...
  1184. @overload
  1185. def scalar(self) -> Any: ...
  1186. def scalar(self) -> Any:
  1187. """Fetch the first column of the first row, and close the result set.
  1188. Returns ``None`` if there are no rows to fetch.
  1189. No validation is performed to test if additional rows remain.
  1190. After calling this method, the object is fully closed,
  1191. e.g. the :meth:`_engine.CursorResult.close`
  1192. method will have been called.
  1193. :return: a Python scalar value, or ``None`` if no rows remain.
  1194. """
  1195. return self._only_one_row(
  1196. raise_for_second_row=False, raise_for_none=False, scalar=True
  1197. )
  1198. def freeze(self) -> FrozenResult[_TP]:
  1199. """Return a callable object that will produce copies of this
  1200. :class:`_engine.Result` when invoked.
  1201. The callable object returned is an instance of
  1202. :class:`_engine.FrozenResult`.
  1203. This is used for result set caching. The method must be called
  1204. on the result when it has been unconsumed, and calling the method
  1205. will consume the result fully. When the :class:`_engine.FrozenResult`
  1206. is retrieved from a cache, it can be called any number of times where
  1207. it will produce a new :class:`_engine.Result` object each time
  1208. against its stored set of rows.
  1209. .. seealso::
  1210. :ref:`do_orm_execute_re_executing` - example usage within the
  1211. ORM to implement a result-set cache.
  1212. """
  1213. return FrozenResult(self)
  1214. def merge(self, *others: Result[Any]) -> MergedResult[_TP]:
  1215. """Merge this :class:`_engine.Result` with other compatible result
  1216. objects.
  1217. The object returned is an instance of :class:`_engine.MergedResult`,
  1218. which will be composed of iterators from the given result
  1219. objects.
  1220. The new result will use the metadata from this result object.
  1221. The subsequent result objects must be against an identical
  1222. set of result / cursor metadata, otherwise the behavior is
  1223. undefined.
  1224. """
  1225. return MergedResult(self._metadata, (self,) + others)
  1226. class FilterResult(ResultInternal[_R]):
  1227. """A wrapper for a :class:`_engine.Result` that returns objects other than
  1228. :class:`_engine.Row` objects, such as dictionaries or scalar objects.
  1229. :class:`_engine.FilterResult` is the common base for additional result
  1230. APIs including :class:`_engine.MappingResult`,
  1231. :class:`_engine.ScalarResult` and :class:`_engine.AsyncResult`.
  1232. """
  1233. __slots__ = (
  1234. "_real_result",
  1235. "_post_creational_filter",
  1236. "_metadata",
  1237. "_unique_filter_state",
  1238. "__dict__",
  1239. )
  1240. _post_creational_filter: Optional[Callable[[Any], Any]]
  1241. _real_result: Result[Any]
  1242. def __enter__(self) -> Self:
  1243. return self
  1244. def __exit__(self, type_: Any, value: Any, traceback: Any) -> None:
  1245. self._real_result.__exit__(type_, value, traceback)
  1246. @_generative
  1247. def yield_per(self, num: int) -> Self:
  1248. """Configure the row-fetching strategy to fetch ``num`` rows at a time.
  1249. The :meth:`_engine.FilterResult.yield_per` method is a pass through
  1250. to the :meth:`_engine.Result.yield_per` method. See that method's
  1251. documentation for usage notes.
  1252. .. versionadded:: 1.4.40 - added :meth:`_engine.FilterResult.yield_per`
  1253. so that the method is available on all result set implementations
  1254. .. seealso::
  1255. :ref:`engine_stream_results` - describes Core behavior for
  1256. :meth:`_engine.Result.yield_per`
  1257. :ref:`orm_queryguide_yield_per` - in the :ref:`queryguide_toplevel`
  1258. """
  1259. self._real_result = self._real_result.yield_per(num)
  1260. return self
  1261. def _soft_close(self, hard: bool = False) -> None:
  1262. self._real_result._soft_close(hard=hard)
  1263. @property
  1264. def _soft_closed(self) -> bool:
  1265. return self._real_result._soft_closed
  1266. @property
  1267. def closed(self) -> bool:
  1268. """Return ``True`` if the underlying :class:`_engine.Result` reports
  1269. closed
  1270. .. versionadded:: 1.4.43
  1271. """
  1272. return self._real_result.closed
  1273. def close(self) -> None:
  1274. """Close this :class:`_engine.FilterResult`.
  1275. .. versionadded:: 1.4.43
  1276. """
  1277. self._real_result.close()
  1278. @property
  1279. def _attributes(self) -> Dict[Any, Any]:
  1280. return self._real_result._attributes
  1281. def _fetchiter_impl(self) -> Iterator[_InterimRowType[Row[Any]]]:
  1282. return self._real_result._fetchiter_impl()
  1283. def _fetchone_impl(
  1284. self, hard_close: bool = False
  1285. ) -> Optional[_InterimRowType[Row[Any]]]:
  1286. return self._real_result._fetchone_impl(hard_close=hard_close)
  1287. def _fetchall_impl(self) -> List[_InterimRowType[Row[Any]]]:
  1288. return self._real_result._fetchall_impl()
  1289. def _fetchmany_impl(
  1290. self, size: Optional[int] = None
  1291. ) -> List[_InterimRowType[Row[Any]]]:
  1292. return self._real_result._fetchmany_impl(size=size)
  1293. class ScalarResult(FilterResult[_R]):
  1294. """A wrapper for a :class:`_engine.Result` that returns scalar values
  1295. rather than :class:`_row.Row` values.
  1296. The :class:`_engine.ScalarResult` object is acquired by calling the
  1297. :meth:`_engine.Result.scalars` method.
  1298. A special limitation of :class:`_engine.ScalarResult` is that it has
  1299. no ``fetchone()`` method; since the semantics of ``fetchone()`` are that
  1300. the ``None`` value indicates no more results, this is not compatible
  1301. with :class:`_engine.ScalarResult` since there is no way to distinguish
  1302. between ``None`` as a row value versus ``None`` as an indicator. Use
  1303. ``next(result)`` to receive values individually.
  1304. """
  1305. __slots__ = ()
  1306. _generate_rows = False
  1307. _post_creational_filter: Optional[Callable[[Any], Any]]
  1308. def __init__(self, real_result: Result[Any], index: _KeyIndexType):
  1309. self._real_result = real_result
  1310. if real_result._source_supports_scalars:
  1311. self._metadata = real_result._metadata
  1312. self._post_creational_filter = None
  1313. else:
  1314. self._metadata = real_result._metadata._reduce([index])
  1315. self._post_creational_filter = operator.itemgetter(0)
  1316. self._unique_filter_state = real_result._unique_filter_state
  1317. def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
  1318. """Apply unique filtering to the objects returned by this
  1319. :class:`_engine.ScalarResult`.
  1320. See :meth:`_engine.Result.unique` for usage details.
  1321. """
  1322. self._unique_filter_state = (set(), strategy)
  1323. return self
  1324. def partitions(self, size: Optional[int] = None) -> Iterator[Sequence[_R]]:
  1325. """Iterate through sub-lists of elements of the size given.
  1326. Equivalent to :meth:`_engine.Result.partitions` except that
  1327. scalar values, rather than :class:`_engine.Row` objects,
  1328. are returned.
  1329. """
  1330. getter = self._manyrow_getter
  1331. while True:
  1332. partition = getter(self, size)
  1333. if partition:
  1334. yield partition
  1335. else:
  1336. break
  1337. def fetchall(self) -> Sequence[_R]:
  1338. """A synonym for the :meth:`_engine.ScalarResult.all` method."""
  1339. return self._allrows()
  1340. def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
  1341. """Fetch many objects.
  1342. Equivalent to :meth:`_engine.Result.fetchmany` except that
  1343. scalar values, rather than :class:`_engine.Row` objects,
  1344. are returned.
  1345. """
  1346. return self._manyrow_getter(self, size)
  1347. def all(self) -> Sequence[_R]:
  1348. """Return all scalar values in a sequence.
  1349. Equivalent to :meth:`_engine.Result.all` except that
  1350. scalar values, rather than :class:`_engine.Row` objects,
  1351. are returned.
  1352. """
  1353. return self._allrows()
  1354. def __iter__(self) -> Iterator[_R]:
  1355. return self._iter_impl()
  1356. def __next__(self) -> _R:
  1357. return self._next_impl()
  1358. def first(self) -> Optional[_R]:
  1359. """Fetch the first object or ``None`` if no object is present.
  1360. Equivalent to :meth:`_engine.Result.first` except that
  1361. scalar values, rather than :class:`_engine.Row` objects,
  1362. are returned.
  1363. """
  1364. return self._only_one_row(
  1365. raise_for_second_row=False, raise_for_none=False, scalar=False
  1366. )
  1367. def one_or_none(self) -> Optional[_R]:
  1368. """Return at most one object or raise an exception.
  1369. Equivalent to :meth:`_engine.Result.one_or_none` except that
  1370. scalar values, rather than :class:`_engine.Row` objects,
  1371. are returned.
  1372. """
  1373. return self._only_one_row(
  1374. raise_for_second_row=True, raise_for_none=False, scalar=False
  1375. )
  1376. def one(self) -> _R:
  1377. """Return exactly one object or raise an exception.
  1378. Equivalent to :meth:`_engine.Result.one` except that
  1379. scalar values, rather than :class:`_engine.Row` objects,
  1380. are returned.
  1381. """
  1382. return self._only_one_row(
  1383. raise_for_second_row=True, raise_for_none=True, scalar=False
  1384. )
  1385. class TupleResult(FilterResult[_R], util.TypingOnly):
  1386. """A :class:`_engine.Result` that's typed as returning plain
  1387. Python tuples instead of rows.
  1388. Since :class:`_engine.Row` acts like a tuple in every way already,
  1389. this class is a typing only class, regular :class:`_engine.Result` is
  1390. still used at runtime.
  1391. """
  1392. __slots__ = ()
  1393. if TYPE_CHECKING:
  1394. def partitions(
  1395. self, size: Optional[int] = None
  1396. ) -> Iterator[Sequence[_R]]:
  1397. """Iterate through sub-lists of elements of the size given.
  1398. Equivalent to :meth:`_engine.Result.partitions` except that
  1399. tuple values, rather than :class:`_engine.Row` objects,
  1400. are returned.
  1401. """
  1402. ...
  1403. def fetchone(self) -> Optional[_R]:
  1404. """Fetch one tuple.
  1405. Equivalent to :meth:`_engine.Result.fetchone` except that
  1406. tuple values, rather than :class:`_engine.Row`
  1407. objects, are returned.
  1408. """
  1409. ...
  1410. def fetchall(self) -> Sequence[_R]:
  1411. """A synonym for the :meth:`_engine.ScalarResult.all` method."""
  1412. ...
  1413. def fetchmany(self, size: Optional[int] = None) -> Sequence[_R]:
  1414. """Fetch many objects.
  1415. Equivalent to :meth:`_engine.Result.fetchmany` except that
  1416. tuple values, rather than :class:`_engine.Row` objects,
  1417. are returned.
  1418. """
  1419. ...
  1420. def all(self) -> Sequence[_R]: # noqa: A001
  1421. """Return all scalar values in a sequence.
  1422. Equivalent to :meth:`_engine.Result.all` except that
  1423. tuple values, rather than :class:`_engine.Row` objects,
  1424. are returned.
  1425. """
  1426. ...
  1427. def __iter__(self) -> Iterator[_R]: ...
  1428. def __next__(self) -> _R: ...
  1429. def first(self) -> Optional[_R]:
  1430. """Fetch the first object or ``None`` if no object is present.
  1431. Equivalent to :meth:`_engine.Result.first` except that
  1432. tuple values, rather than :class:`_engine.Row` objects,
  1433. are returned.
  1434. """
  1435. ...
  1436. def one_or_none(self) -> Optional[_R]:
  1437. """Return at most one object or raise an exception.
  1438. Equivalent to :meth:`_engine.Result.one_or_none` except that
  1439. tuple values, rather than :class:`_engine.Row` objects,
  1440. are returned.
  1441. """
  1442. ...
  1443. def one(self) -> _R:
  1444. """Return exactly one object or raise an exception.
  1445. Equivalent to :meth:`_engine.Result.one` except that
  1446. tuple values, rather than :class:`_engine.Row` objects,
  1447. are returned.
  1448. """
  1449. ...
  1450. @overload
  1451. def scalar_one(self: TupleResult[Tuple[_T]]) -> _T: ...
  1452. @overload
  1453. def scalar_one(self) -> Any: ...
  1454. def scalar_one(self) -> Any:
  1455. """Return exactly one scalar result or raise an exception.
  1456. This is equivalent to calling :meth:`_engine.Result.scalars`
  1457. and then :meth:`_engine.ScalarResult.one`.
  1458. .. seealso::
  1459. :meth:`_engine.ScalarResult.one`
  1460. :meth:`_engine.Result.scalars`
  1461. """
  1462. ...
  1463. @overload
  1464. def scalar_one_or_none(
  1465. self: TupleResult[Tuple[_T]],
  1466. ) -> Optional[_T]: ...
  1467. @overload
  1468. def scalar_one_or_none(self) -> Optional[Any]: ...
  1469. def scalar_one_or_none(self) -> Optional[Any]:
  1470. """Return exactly one or no scalar result.
  1471. This is equivalent to calling :meth:`_engine.Result.scalars`
  1472. and then :meth:`_engine.ScalarResult.one_or_none`.
  1473. .. seealso::
  1474. :meth:`_engine.ScalarResult.one_or_none`
  1475. :meth:`_engine.Result.scalars`
  1476. """
  1477. ...
  1478. @overload
  1479. def scalar(self: TupleResult[Tuple[_T]]) -> Optional[_T]: ...
  1480. @overload
  1481. def scalar(self) -> Any: ...
  1482. def scalar(self) -> Any:
  1483. """Fetch the first column of the first row, and close the result
  1484. set.
  1485. Returns ``None`` if there are no rows to fetch.
  1486. No validation is performed to test if additional rows remain.
  1487. After calling this method, the object is fully closed,
  1488. e.g. the :meth:`_engine.CursorResult.close`
  1489. method will have been called.
  1490. :return: a Python scalar value , or ``None`` if no rows remain.
  1491. """
  1492. ...
  1493. class MappingResult(_WithKeys, FilterResult[RowMapping]):
  1494. """A wrapper for a :class:`_engine.Result` that returns dictionary values
  1495. rather than :class:`_engine.Row` values.
  1496. The :class:`_engine.MappingResult` object is acquired by calling the
  1497. :meth:`_engine.Result.mappings` method.
  1498. """
  1499. __slots__ = ()
  1500. _generate_rows = True
  1501. _post_creational_filter = operator.attrgetter("_mapping")
  1502. def __init__(self, result: Result[Any]):
  1503. self._real_result = result
  1504. self._unique_filter_state = result._unique_filter_state
  1505. self._metadata = result._metadata
  1506. if result._source_supports_scalars:
  1507. self._metadata = self._metadata._reduce([0])
  1508. def unique(self, strategy: Optional[_UniqueFilterType] = None) -> Self:
  1509. """Apply unique filtering to the objects returned by this
  1510. :class:`_engine.MappingResult`.
  1511. See :meth:`_engine.Result.unique` for usage details.
  1512. """
  1513. self._unique_filter_state = (set(), strategy)
  1514. return self
  1515. def columns(self, *col_expressions: _KeyIndexType) -> Self:
  1516. """Establish the columns that should be returned in each row."""
  1517. return self._column_slices(col_expressions)
  1518. def partitions(
  1519. self, size: Optional[int] = None
  1520. ) -> Iterator[Sequence[RowMapping]]:
  1521. """Iterate through sub-lists of elements of the size given.
  1522. Equivalent to :meth:`_engine.Result.partitions` except that
  1523. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1524. objects, are returned.
  1525. """
  1526. getter = self._manyrow_getter
  1527. while True:
  1528. partition = getter(self, size)
  1529. if partition:
  1530. yield partition
  1531. else:
  1532. break
  1533. def fetchall(self) -> Sequence[RowMapping]:
  1534. """A synonym for the :meth:`_engine.MappingResult.all` method."""
  1535. return self._allrows()
  1536. def fetchone(self) -> Optional[RowMapping]:
  1537. """Fetch one object.
  1538. Equivalent to :meth:`_engine.Result.fetchone` except that
  1539. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1540. objects, are returned.
  1541. """
  1542. row = self._onerow_getter(self)
  1543. if row is _NO_ROW:
  1544. return None
  1545. else:
  1546. return row
  1547. def fetchmany(self, size: Optional[int] = None) -> Sequence[RowMapping]:
  1548. """Fetch many objects.
  1549. Equivalent to :meth:`_engine.Result.fetchmany` except that
  1550. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1551. objects, are returned.
  1552. """
  1553. return self._manyrow_getter(self, size)
  1554. def all(self) -> Sequence[RowMapping]:
  1555. """Return all scalar values in a sequence.
  1556. Equivalent to :meth:`_engine.Result.all` except that
  1557. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1558. objects, are returned.
  1559. """
  1560. return self._allrows()
  1561. def __iter__(self) -> Iterator[RowMapping]:
  1562. return self._iter_impl()
  1563. def __next__(self) -> RowMapping:
  1564. return self._next_impl()
  1565. def first(self) -> Optional[RowMapping]:
  1566. """Fetch the first object or ``None`` if no object is present.
  1567. Equivalent to :meth:`_engine.Result.first` except that
  1568. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1569. objects, are returned.
  1570. """
  1571. return self._only_one_row(
  1572. raise_for_second_row=False, raise_for_none=False, scalar=False
  1573. )
  1574. def one_or_none(self) -> Optional[RowMapping]:
  1575. """Return at most one object or raise an exception.
  1576. Equivalent to :meth:`_engine.Result.one_or_none` except that
  1577. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1578. objects, are returned.
  1579. """
  1580. return self._only_one_row(
  1581. raise_for_second_row=True, raise_for_none=False, scalar=False
  1582. )
  1583. def one(self) -> RowMapping:
  1584. """Return exactly one object or raise an exception.
  1585. Equivalent to :meth:`_engine.Result.one` except that
  1586. :class:`_engine.RowMapping` values, rather than :class:`_engine.Row`
  1587. objects, are returned.
  1588. """
  1589. return self._only_one_row(
  1590. raise_for_second_row=True, raise_for_none=True, scalar=False
  1591. )
  1592. class FrozenResult(Generic[_TP]):
  1593. """Represents a :class:`_engine.Result` object in a "frozen" state suitable
  1594. for caching.
  1595. The :class:`_engine.FrozenResult` object is returned from the
  1596. :meth:`_engine.Result.freeze` method of any :class:`_engine.Result`
  1597. object.
  1598. A new iterable :class:`_engine.Result` object is generated from a fixed
  1599. set of data each time the :class:`_engine.FrozenResult` is invoked as
  1600. a callable::
  1601. result = connection.execute(query)
  1602. frozen = result.freeze()
  1603. unfrozen_result_one = frozen()
  1604. for row in unfrozen_result_one:
  1605. print(row)
  1606. unfrozen_result_two = frozen()
  1607. rows = unfrozen_result_two.all()
  1608. # ... etc
  1609. .. versionadded:: 1.4
  1610. .. seealso::
  1611. :ref:`do_orm_execute_re_executing` - example usage within the
  1612. ORM to implement a result-set cache.
  1613. :func:`_orm.loading.merge_frozen_result` - ORM function to merge
  1614. a frozen result back into a :class:`_orm.Session`.
  1615. """
  1616. data: Sequence[Any]
  1617. def __init__(self, result: Result[_TP]):
  1618. self.metadata = result._metadata._for_freeze()
  1619. self._source_supports_scalars = result._source_supports_scalars
  1620. self._attributes = result._attributes
  1621. if self._source_supports_scalars:
  1622. self.data = list(result._raw_row_iterator())
  1623. else:
  1624. self.data = result.fetchall()
  1625. def rewrite_rows(self) -> Sequence[Sequence[Any]]:
  1626. if self._source_supports_scalars:
  1627. return [[elem] for elem in self.data]
  1628. else:
  1629. return [list(row) for row in self.data]
  1630. def with_new_rows(
  1631. self, tuple_data: Sequence[Row[_TP]]
  1632. ) -> FrozenResult[_TP]:
  1633. fr = FrozenResult.__new__(FrozenResult)
  1634. fr.metadata = self.metadata
  1635. fr._attributes = self._attributes
  1636. fr._source_supports_scalars = self._source_supports_scalars
  1637. if self._source_supports_scalars:
  1638. fr.data = [d[0] for d in tuple_data]
  1639. else:
  1640. fr.data = tuple_data
  1641. return fr
  1642. def __call__(self) -> Result[_TP]:
  1643. result: IteratorResult[_TP] = IteratorResult(
  1644. self.metadata, iter(self.data)
  1645. )
  1646. result._attributes = self._attributes
  1647. result._source_supports_scalars = self._source_supports_scalars
  1648. return result
  1649. class IteratorResult(Result[_TP]):
  1650. """A :class:`_engine.Result` that gets data from a Python iterator of
  1651. :class:`_engine.Row` objects or similar row-like data.
  1652. .. versionadded:: 1.4
  1653. """
  1654. _hard_closed = False
  1655. _soft_closed = False
  1656. def __init__(
  1657. self,
  1658. cursor_metadata: ResultMetaData,
  1659. iterator: Iterator[_InterimSupportsScalarsRowType],
  1660. raw: Optional[Result[Any]] = None,
  1661. _source_supports_scalars: bool = False,
  1662. ):
  1663. self._metadata = cursor_metadata
  1664. self.iterator = iterator
  1665. self.raw = raw
  1666. self._source_supports_scalars = _source_supports_scalars
  1667. @property
  1668. def closed(self) -> bool:
  1669. """Return ``True`` if this :class:`_engine.IteratorResult` has
  1670. been closed
  1671. .. versionadded:: 1.4.43
  1672. """
  1673. return self._hard_closed
  1674. def _soft_close(self, hard: bool = False, **kw: Any) -> None:
  1675. if hard:
  1676. self._hard_closed = True
  1677. if self.raw is not None:
  1678. self.raw._soft_close(hard=hard, **kw)
  1679. self.iterator = iter([])
  1680. self._reset_memoizations()
  1681. self._soft_closed = True
  1682. def _raise_hard_closed(self) -> NoReturn:
  1683. raise exc.ResourceClosedError("This result object is closed.")
  1684. def _raw_row_iterator(self) -> Iterator[_RowData]:
  1685. return self.iterator
  1686. def _fetchiter_impl(self) -> Iterator[_InterimSupportsScalarsRowType]:
  1687. if self._hard_closed:
  1688. self._raise_hard_closed()
  1689. return self.iterator
  1690. def _fetchone_impl(
  1691. self, hard_close: bool = False
  1692. ) -> Optional[_InterimRowType[Row[Any]]]:
  1693. if self._hard_closed:
  1694. self._raise_hard_closed()
  1695. row = next(self.iterator, _NO_ROW)
  1696. if row is _NO_ROW:
  1697. self._soft_close(hard=hard_close)
  1698. return None
  1699. else:
  1700. return row
  1701. def _fetchall_impl(self) -> List[_InterimRowType[Row[Any]]]:
  1702. if self._hard_closed:
  1703. self._raise_hard_closed()
  1704. try:
  1705. return list(self.iterator)
  1706. finally:
  1707. self._soft_close()
  1708. def _fetchmany_impl(
  1709. self, size: Optional[int] = None
  1710. ) -> List[_InterimRowType[Row[Any]]]:
  1711. if self._hard_closed:
  1712. self._raise_hard_closed()
  1713. return list(itertools.islice(self.iterator, 0, size))
  1714. def null_result() -> IteratorResult[Any]:
  1715. return IteratorResult(SimpleResultMetaData([]), iter([]))
  1716. class ChunkedIteratorResult(IteratorResult[_TP]):
  1717. """An :class:`_engine.IteratorResult` that works from an
  1718. iterator-producing callable.
  1719. The given ``chunks`` argument is a function that is given a number of rows
  1720. to return in each chunk, or ``None`` for all rows. The function should
  1721. then return an un-consumed iterator of lists, each list of the requested
  1722. size.
  1723. The function can be called at any time again, in which case it should
  1724. continue from the same result set but adjust the chunk size as given.
  1725. .. versionadded:: 1.4
  1726. """
  1727. def __init__(
  1728. self,
  1729. cursor_metadata: ResultMetaData,
  1730. chunks: Callable[
  1731. [Optional[int]], Iterator[Sequence[_InterimRowType[_R]]]
  1732. ],
  1733. source_supports_scalars: bool = False,
  1734. raw: Optional[Result[Any]] = None,
  1735. dynamic_yield_per: bool = False,
  1736. ):
  1737. self._metadata = cursor_metadata
  1738. self.chunks = chunks
  1739. self._source_supports_scalars = source_supports_scalars
  1740. self.raw = raw
  1741. self.iterator = itertools.chain.from_iterable(self.chunks(None))
  1742. self.dynamic_yield_per = dynamic_yield_per
  1743. @_generative
  1744. def yield_per(self, num: int) -> Self:
  1745. # TODO: this throws away the iterator which may be holding
  1746. # onto a chunk. the yield_per cannot be changed once any
  1747. # rows have been fetched. either find a way to enforce this,
  1748. # or we can't use itertools.chain and will instead have to
  1749. # keep track.
  1750. self._yield_per = num
  1751. self.iterator = itertools.chain.from_iterable(self.chunks(num))
  1752. return self
  1753. def _soft_close(self, hard: bool = False, **kw: Any) -> None:
  1754. super()._soft_close(hard=hard, **kw)
  1755. self.chunks = lambda size: [] # type: ignore
  1756. def _fetchmany_impl(
  1757. self, size: Optional[int] = None
  1758. ) -> List[_InterimRowType[Row[Any]]]:
  1759. if self.dynamic_yield_per:
  1760. self.iterator = itertools.chain.from_iterable(self.chunks(size))
  1761. return super()._fetchmany_impl(size=size)
  1762. class MergedResult(IteratorResult[_TP]):
  1763. """A :class:`_engine.Result` that is merged from any number of
  1764. :class:`_engine.Result` objects.
  1765. Returned by the :meth:`_engine.Result.merge` method.
  1766. .. versionadded:: 1.4
  1767. """
  1768. closed = False
  1769. rowcount: Optional[int]
  1770. def __init__(
  1771. self, cursor_metadata: ResultMetaData, results: Sequence[Result[_TP]]
  1772. ):
  1773. self._results = results
  1774. super().__init__(
  1775. cursor_metadata,
  1776. itertools.chain.from_iterable(
  1777. r._raw_row_iterator() for r in results
  1778. ),
  1779. )
  1780. self._unique_filter_state = results[0]._unique_filter_state
  1781. self._yield_per = results[0]._yield_per
  1782. # going to try something w/ this in next rev
  1783. self._source_supports_scalars = results[0]._source_supports_scalars
  1784. self._attributes = self._attributes.merge_with(
  1785. *[r._attributes for r in results]
  1786. )
  1787. def _soft_close(self, hard: bool = False, **kw: Any) -> None:
  1788. for r in self._results:
  1789. r._soft_close(hard=hard, **kw)
  1790. if hard:
  1791. self.closed = True