@@ -615,36 +615,40 @@ pub struct QueryPager {
615615impl QueryPager {
616616 /// Returns the next item (`ColumnIterator`) from the stream.
617617 ///
618- /// This can be used with `type_check() for manual deserialization - see example below.
618+ /// Because pages may have different result metadata, each one needs to be type-checked before deserialization.
619+ /// The bool returned in second element of the tuple indicates whether the page was fresh or not.
620+ /// This allows user to then perform the type check for fresh pages.
619621 ///
620622 /// This is not a part of the `Stream` interface because the returned iterator
621623 /// borrows from self.
622624 ///
623625 /// This is cancel-safe.
624- async fn next ( & mut self ) -> Option < Result < ColumnIterator < ' _ , ' _ > , NextRowError > > {
626+ async fn next ( & mut self ) -> Option < Result < ( ColumnIterator < ' _ , ' _ > , bool ) , NextRowError > > {
625627 let res = std:: future:: poll_fn ( |cx| Pin :: new ( & mut * self ) . poll_fill_page ( cx) ) . await ;
626- match res {
627- Some ( Ok ( ( ) ) ) => { }
628+ let fresh_page = match res {
629+ Some ( Ok ( f ) ) => f ,
628630 Some ( Err ( err) ) => return Some ( Err ( err) ) ,
629631 None => return None ,
630- }
632+ } ;
631633
632634 // We are guaranteed here to have a non-empty page, so unwrap
633635 Some (
634636 self . current_page
635637 . next ( )
636638 . unwrap ( )
637- . map_err ( NextRowError :: RowDeserializationError ) ,
639+ . map_err ( NextRowError :: RowDeserializationError )
640+ . map ( |x| ( x, fresh_page) ) ,
638641 )
639642 }
640643
641644 /// Tries to acquire a non-empty page, if current page is exhausted.
645+ /// Boolean value in `Some(Ok(r))` is true if a new page was fetched.
642646 fn poll_fill_page (
643647 mut self : Pin < & mut Self > ,
644648 cx : & mut Context < ' _ > ,
645- ) -> Poll < Option < Result < ( ) , NextRowError > > > {
649+ ) -> Poll < Option < Result < bool , NextRowError > > > {
646650 if !self . is_current_page_exhausted ( ) {
647- return Poll :: Ready ( Some ( Ok ( ( ) ) ) ) ;
651+ return Poll :: Ready ( Some ( Ok ( false ) ) ) ;
648652 }
649653 ready_some_ok ! ( self . as_mut( ) . poll_next_page( cx) ) ;
650654 if self . is_current_page_exhausted ( ) {
@@ -653,7 +657,7 @@ impl QueryPager {
653657 cx. waker ( ) . wake_by_ref ( ) ;
654658 Poll :: Pending
655659 } else {
656- Poll :: Ready ( Some ( Ok ( ( ) ) ) )
660+ Poll :: Ready ( Some ( Ok ( true ) ) )
657661 }
658662 }
659663
@@ -691,6 +695,12 @@ impl QueryPager {
691695 /// This is automatically called upon transforming [QueryPager] into [TypedRowStream].
692696 // Can be used with `next()` for manual deserialization.
693697 #[ inline]
698+ #[ deprecated(
699+ since = "1.4.0" ,
700+ note = "Type check should be performed for each page, which is not possible with public API.
701+ Also, the only thing user can do (rows_stream) will take care of type check anyway.
702+ If you are using this API, you are probably doing something wrong."
703+ ) ]
694704 pub fn type_check < ' frame , ' metadata , RowT : DeserializeRow < ' frame , ' metadata > > (
695705 & self ,
696706 ) -> Result < ( ) , TypeCheckError > {
@@ -1040,6 +1050,7 @@ impl QueryPager {
10401050/// To use [Stream] API (only accessible for owned types), use [QueryPager::rows_stream].
10411051pub struct TypedRowStream < RowT > {
10421052 raw_row_lending_stream : QueryPager ,
1053+ current_page_typechecked : bool ,
10431054 _phantom : std:: marker:: PhantomData < RowT > ,
10441055}
10451056
@@ -1061,10 +1072,12 @@ where
10611072 RowT : for < ' frame , ' metadata > DeserializeRow < ' frame , ' metadata > ,
10621073{
10631074 fn new ( raw_stream : QueryPager ) -> Result < Self , TypeCheckError > {
1075+ #[ allow( deprecated) ] // In TypedRowStream we take care to type check each page.
10641076 raw_stream. type_check :: < RowT > ( ) ?;
10651077
10661078 Ok ( Self {
10671079 raw_row_lending_stream : raw_stream,
1080+ current_page_typechecked : true ,
10681081 _phantom : Default :: default ( ) ,
10691082 } )
10701083 }
@@ -1101,8 +1114,18 @@ where
11011114
11021115 fn poll_next ( mut self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
11031116 let next_fut = async {
1104- self . raw_row_lending_stream . next ( ) . await . map ( |res| {
1105- res. and_then ( |column_iterator| {
1117+ let real_self: & mut Self = & mut self ; // Self is Unpin, and this lets us perform partial borrows.
1118+ real_self. raw_row_lending_stream . next ( ) . await . map ( |res| {
1119+ res. and_then ( |( column_iterator, fresh_page) | {
1120+ if fresh_page {
1121+ real_self. current_page_typechecked = false ;
1122+ }
1123+ if !real_self. current_page_typechecked {
1124+ column_iterator. type_check :: < RowT > ( ) . map_err ( |e| {
1125+ NextRowError :: NextPageError ( NextPageError :: TypeCheckError ( e) )
1126+ } ) ?;
1127+ real_self. current_page_typechecked = true ;
1128+ }
11061129 <RowT as DeserializeRow >:: deserialize ( column_iterator)
11071130 . map_err ( NextRowError :: RowDeserializationError )
11081131 } )
@@ -1130,6 +1153,10 @@ pub enum NextPageError {
11301153 /// Failed to deserialize result metadata associated with next page response.
11311154 #[ error( "Failed to deserialize result metadata associated with next page response: {0}" ) ]
11321155 ResultMetadataParseError ( #[ from] ResultMetadataAndRowsCountParseError ) ,
1156+
1157+ /// Failed to type check a received page.
1158+ #[ error( "Failed to type check a received page: {0}" ) ]
1159+ TypeCheckError ( #[ from] TypeCheckError ) ,
11331160}
11341161
11351162/// An error returned by async iterator API.
0 commit comments