An :class:`_engine.IteratorResult` that works from an iterator-producing callable. The given ``chunks`` argument is a function that is given a number of rows to return in each chunk, or ``None`` for all rows. The function should then return an un-consumed iterator of lists, each li
| 1911 | |
| 1912 | |
| 1913 | class ChunkedIteratorResult(IteratorResult[Unpack[_Ts]]): |
| 1914 | """An :class:`_engine.IteratorResult` that works from an |
| 1915 | iterator-producing callable. |
| 1916 | |
| 1917 | The given ``chunks`` argument is a function that is given a number of rows |
| 1918 | to return in each chunk, or ``None`` for all rows. The function should |
| 1919 | then return an un-consumed iterator of lists, each list of the requested |
| 1920 | size. |
| 1921 | |
| 1922 | The function can be called at any time again, in which case it should |
| 1923 | continue from the same result set but adjust the chunk size as given. |
| 1924 | |
| 1925 | .. versionadded:: 1.4 |
| 1926 | |
| 1927 | """ |
| 1928 | |
| 1929 | def __init__( |
| 1930 | self, |
| 1931 | cursor_metadata: ResultMetaData, |
| 1932 | chunks: Callable[ |
| 1933 | [Optional[int]], Iterator[Sequence[_InterimRowType[_R]]] |
| 1934 | ], |
| 1935 | source_supports_scalars: bool = False, |
| 1936 | raw: Optional[Result[Any]] = None, |
| 1937 | dynamic_yield_per: bool = False, |
| 1938 | context: Optional[Any] = None, |
| 1939 | ): |
| 1940 | self._metadata = cursor_metadata |
| 1941 | self.chunks = chunks |
| 1942 | self._source_supports_scalars = source_supports_scalars |
| 1943 | self.raw = raw |
| 1944 | self.iterator = itertools.chain.from_iterable(self.chunks(None)) |
| 1945 | self.dynamic_yield_per = dynamic_yield_per |
| 1946 | self.context = context |
| 1947 | |
| 1948 | @_generative |
| 1949 | def yield_per(self, num: int) -> Self: |
| 1950 | # TODO: this throws away the iterator which may be holding |
| 1951 | # onto a chunk. the yield_per cannot be changed once any |
| 1952 | # rows have been fetched. either find a way to enforce this, |
| 1953 | # or we can't use itertools.chain and will instead have to |
| 1954 | # keep track. |
| 1955 | |
| 1956 | self._yield_per = num |
| 1957 | self.iterator = itertools.chain.from_iterable(self.chunks(num)) |
| 1958 | return self |
| 1959 | |
| 1960 | def _soft_close(self, hard: bool = False, **kw: Any) -> None: |
| 1961 | super()._soft_close(hard=hard, **kw) |
| 1962 | self.chunks = lambda size: [] # type: ignore |
| 1963 | |
| 1964 | def _fetchmany_impl( |
| 1965 | self, size: Optional[int] = None |
| 1966 | ) -> List[_InterimRowType[Row[Unpack[TupleAny]]]]: |
| 1967 | if self.dynamic_yield_per: |
| 1968 | self.iterator = itertools.chain.from_iterable(self.chunks(size)) |
| 1969 | return super()._fetchmany_impl(size=size) |
| 1970 |