codekingpro/portable-devtools
115k
1# engine/_py_row.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
7from __future__ import annotations
8
9import operator
10import typing
11from typing import Any
12from typing import Callable
13from typing import Dict
14from typing import Iterator
15from typing import List
16from typing import Mapping
17from typing import Optional
18from typing import Tuple
19from typing import Type
20
21if typing.TYPE_CHECKING:
22 from .result import _KeyType
23 from .result import _ProcessorsType
24 from .result import _RawRowType
25 from .result import _TupleGetterType
26 from .result import ResultMetaData
27
28MD_INDEX = 0 # integer index in cursor.description
29
30
31class BaseRow:
32 __slots__ = ("_parent", "_data", "_key_to_index")
33
34 _parent: ResultMetaData
35 _key_to_index: Mapping[_KeyType, int]
36 _data: _RawRowType
37
38 def __init__(
39 self,
40 parent: ResultMetaData,
41 processors: Optional[_ProcessorsType],
42 key_to_index: Mapping[_KeyType, int],
43 data: _RawRowType,
44 ):
45 """Row objects are constructed by CursorResult objects."""
46 object.__setattr__(self, "_parent", parent)
47
48 object.__setattr__(self, "_key_to_index", key_to_index)
49
50 if processors:
51 object.__setattr__(
52 self,
53 "_data",
54 tuple(
55 [
56 proc(value) if proc else value
57 for proc, value in zip(processors, data)
58 ]
59 ),
60 )
61 else:
62 object.__setattr__(self, "_data", tuple(data))
63
64 def __reduce__(self) -> Tuple[Callable[..., BaseRow], Tuple[Any, ...]]:
65 return (
66 rowproxy_reconstructor,
67 (self.__class__, self.__getstate__()),
68 )
69
70 def __getstate__(self) -> Dict[str, Any]:
71 return {"_parent": self._parent, "_data": self._data}
72
73 def __setstate__(self, state: Dict[str, Any]) -> None:
74 parent = state["_parent"]
75 object.__setattr__(self, "_parent", parent)
76 object.__setattr__(self, "_data", state["_data"])
77 object.__setattr__(self, "_key_to_index", parent._key_to_index)
78
79 def _values_impl(self) -> List[Any]:
80 return list(self)
81
82 def __iter__(self) -> Iterator[Any]:
83 return iter(self._data)
84
85 def __len__(self) -> int:
86 return len(self._data)
87
88 def __hash__(self) -> int:
89 return hash(self._data)
90
91 def __getitem__(self, key: Any) -> Any:
92 return self._data[key]
93
94 def _get_by_key_impl_mapping(self, key: str) -> Any:
95 try:
96 return self._data[self._key_to_index[key]]
97 except KeyError:
98 pass
99 self._parent._key_not_found(key, False)
100
101 def __getattr__(self, name: str) -> Any:
102 try:
103 return self._data[self._key_to_index[name]]
104 except KeyError:
105 pass
106 self._parent._key_not_found(name, True)
107
108 def _to_tuple_instance(self) -> Tuple[Any, ...]:
109 return self._data
110
111
112# This reconstructor is necessary so that pickles with the Cy extension or
113# without use the same Binary format.
114def rowproxy_reconstructor(
115 cls: Type[BaseRow], state: Dict[str, Any]
116) -> BaseRow:
117 obj = cls.__new__(cls)
118 obj.__setstate__(state)
119 return obj
120
121
122def tuplegetter(*indexes: int) -> _TupleGetterType:
123 if len(indexes) != 1:
124 for i in range(1, len(indexes)):
125 if indexes[i - 1] != indexes[i] - 1:
126 return operator.itemgetter(*indexes)
127 # slice form is faster but returns a list if input is list
128 return operator.itemgetter(slice(indexes[0], indexes[-1] + 1))
129 