@@ -666,14 +666,38 @@ impl<S: Storage> Database<S> {
666666 }
667667}
668668
669- /// Common interface for result iterators returned by database execution APIs.
670- ///
671- /// A result iterator streams [`Tuple`] values and exposes the output schema of
672- /// the current statement.
673- pub trait ResultIter : Iterator < Item = Result < Tuple , DatabaseError > > {
669+ /// Borrowing interface for result iterators returned by database execution APIs.
670+ pub trait BorrowResultIter {
674671 /// Returns the output schema for the current result set.
675672 fn schema ( & self ) -> & SchemaRef ;
676673
674+ /// Returns the next row as a borrowed tuple.
675+ fn next_borrowed_tuple ( & mut self ) -> Result < Option < & Tuple > , DatabaseError > ;
676+
677+ /// Creates a mapped iterator that transforms borrowed tuples into owned output values.
678+ fn map_result < F , O > ( self , mapper : F ) -> MappedResultIter < Self , F , O >
679+ where
680+ Self : Sized ,
681+ F : for < ' a > FnMut ( & ' a SchemaRef , & ' a Tuple ) -> Result < O , DatabaseError > ,
682+ {
683+ let schema = self . schema ( ) . clone ( ) ;
684+ MappedResultIter {
685+ inner : self ,
686+ mapper,
687+ schema,
688+ _marker : PhantomData ,
689+ }
690+ }
691+
692+ /// Finishes consuming the iterator and flushes any remaining work.
693+ fn done ( self ) -> Result < ( ) , DatabaseError > ;
694+ }
695+
696+ /// Common interface for owned-tuple result iterators.
697+ ///
698+ /// This remains for compatibility with existing callers that expect
699+ /// `Iterator<Item = Result<Tuple, DatabaseError>>`.
700+ pub trait ResultIter : BorrowResultIter + Iterator < Item = Result < Tuple , DatabaseError > > {
677701 #[ cfg( feature = "orm" ) ]
678702 /// Converts this iterator into a typed ORM iterator.
679703 ///
@@ -687,9 +711,46 @@ pub trait ResultIter: Iterator<Item = Result<Tuple, DatabaseError>> {
687711 {
688712 OrmIter :: new ( self )
689713 }
714+ }
690715
691- /// Finishes consuming the iterator and flushes any remaining work.
692- fn done ( self ) -> Result < ( ) , DatabaseError > ;
716+ impl < I > ResultIter for I where I : BorrowResultIter + Iterator < Item = Result < Tuple , DatabaseError > > { }
717+
718+ /// Typed adapter over a borrowing result iterator.
719+ pub struct MappedResultIter < I , F , O > {
720+ inner : I ,
721+ mapper : F ,
722+ schema : SchemaRef ,
723+ _marker : PhantomData < O > ,
724+ }
725+
726+ impl < I , F , O > MappedResultIter < I , F , O >
727+ where
728+ I : BorrowResultIter ,
729+ F : for < ' a > FnMut ( & ' a SchemaRef , & ' a Tuple ) -> Result < O , DatabaseError > ,
730+ {
731+ pub fn schema ( & self ) -> & SchemaRef {
732+ & self . schema
733+ }
734+
735+ pub fn done ( self ) -> Result < ( ) , DatabaseError > {
736+ self . inner . done ( )
737+ }
738+ }
739+
740+ impl < I , F , O > Iterator for MappedResultIter < I , F , O >
741+ where
742+ I : BorrowResultIter ,
743+ F : for < ' a > FnMut ( & ' a SchemaRef , & ' a Tuple ) -> Result < O , DatabaseError > ,
744+ {
745+ type Item = Result < O , DatabaseError > ;
746+
747+ fn next ( & mut self ) -> Option < Self :: Item > {
748+ match self . inner . next_borrowed_tuple ( ) {
749+ Ok ( Some ( tuple) ) => Some ( ( self . mapper ) ( & self . schema , tuple) ) ,
750+ Ok ( None ) => None ,
751+ Err ( err) => Some ( Err ( err) ) ,
752+ }
753+ }
693754}
694755
695756#[ cfg( feature = "orm" ) ]
@@ -760,6 +821,33 @@ impl<S: Storage> Drop for DatabaseIter<'_, S> {
760821 }
761822}
762823
824+ impl < S : Storage > DatabaseIter < ' _ , S > {
825+ #[ inline]
826+ pub fn schema ( & self ) -> & SchemaRef {
827+ unsafe { ( * self . inner ) . schema ( ) }
828+ }
829+
830+ #[ inline]
831+ pub fn next_borrowed_tuple ( & mut self ) -> Result < Option < & Tuple > , DatabaseError > {
832+ let result = unsafe { ( * self . inner ) . next_borrowed_tuple ( ) } ;
833+ if result. as_ref ( ) . is_ok_and ( Option :: is_none) {
834+ self . _guard = None ;
835+ }
836+ result
837+ }
838+
839+ #[ inline]
840+ pub fn done ( mut self ) -> Result < ( ) , DatabaseError > {
841+ unsafe {
842+ Box :: from_raw ( mem:: replace ( & mut self . inner , std:: ptr:: null_mut ( ) ) ) . done ( ) ?;
843+ }
844+ unsafe {
845+ Box :: from_raw ( mem:: replace ( & mut self . transaction , std:: ptr:: null_mut ( ) ) ) . commit ( ) ?;
846+ }
847+ Ok ( ( ) )
848+ }
849+ }
850+
763851impl < S : Storage > Iterator for DatabaseIter < ' _ , S > {
764852 type Item = Result < Tuple , DatabaseError > ;
765853
@@ -772,19 +860,17 @@ impl<S: Storage> Iterator for DatabaseIter<'_, S> {
772860 }
773861}
774862
775- impl < S : Storage > ResultIter for DatabaseIter < ' _ , S > {
863+ impl < S : Storage > BorrowResultIter for DatabaseIter < ' _ , S > {
776864 fn schema ( & self ) -> & SchemaRef {
777- unsafe { ( * self . inner ) . schema ( ) }
865+ DatabaseIter :: schema ( self )
778866 }
779867
780- fn done ( mut self ) -> Result < ( ) , DatabaseError > {
781- unsafe {
782- Box :: from_raw ( mem:: replace ( & mut self . inner , std:: ptr:: null_mut ( ) ) ) . done ( ) ?;
783- }
784- unsafe {
785- Box :: from_raw ( mem:: replace ( & mut self . transaction , std:: ptr:: null_mut ( ) ) ) . commit ( ) ?;
786- }
787- Ok ( ( ) )
868+ fn next_borrowed_tuple ( & mut self ) -> Result < Option < & Tuple > , DatabaseError > {
869+ DatabaseIter :: next_borrowed_tuple ( self )
870+ }
871+
872+ fn done ( self ) -> Result < ( ) , DatabaseError > {
873+ DatabaseIter :: done ( self )
788874 }
789875}
790876
@@ -851,34 +937,55 @@ impl<'a, T: Transaction + 'a> TransactionIter<'a, T> {
851937 fn new ( schema : SchemaRef , executor : Executor < ' a , T > ) -> Self {
852938 Self { executor, schema }
853939 }
940+
941+ #[ inline]
942+ pub fn schema ( & self ) -> & SchemaRef {
943+ & self . schema
944+ }
945+
946+ #[ inline]
947+ pub fn next_borrowed_tuple ( & mut self ) -> Result < Option < & Tuple > , DatabaseError > {
948+ self . executor . next_tuple ( )
949+ }
950+
951+ #[ inline]
952+ pub fn done ( mut self ) -> Result < ( ) , DatabaseError > {
953+ while self . next_borrowed_tuple ( ) ?. is_some ( ) { }
954+ Ok ( ( ) )
955+ }
854956}
855957
856958impl < T : Transaction > Iterator for TransactionIter < ' _ , T > {
857959 type Item = Result < Tuple , DatabaseError > ;
858960
859961 fn next ( & mut self ) -> Option < Self :: Item > {
860- self . executor . next ( )
962+ match self . executor . next_tuple ( ) {
963+ Ok ( Some ( tuple) ) => Some ( Ok ( tuple. clone ( ) ) ) ,
964+ Ok ( None ) => None ,
965+ Err ( err) => Some ( Err ( err) ) ,
966+ }
861967 }
862968}
863969
864- impl < T : Transaction > ResultIter for TransactionIter < ' _ , T > {
970+ impl < T : Transaction > BorrowResultIter for TransactionIter < ' _ , T > {
865971 fn schema ( & self ) -> & SchemaRef {
866- & self . schema
972+ TransactionIter :: schema ( self )
867973 }
868974
869- fn done ( mut self ) -> Result < ( ) , DatabaseError > {
870- for result in self . by_ref ( ) {
871- let _ = result?;
872- }
873- Ok ( ( ) )
975+ fn next_borrowed_tuple ( & mut self ) -> Result < Option < & Tuple > , DatabaseError > {
976+ TransactionIter :: next_borrowed_tuple ( self )
977+ }
978+
979+ fn done ( self ) -> Result < ( ) , DatabaseError > {
980+ TransactionIter :: done ( self )
874981 }
875982}
876983
877984#[ cfg( all( test, not( target_arch = "wasm32" ) ) ) ]
878985pub ( crate ) mod test {
879986 use crate :: binder:: { Binder , BinderContext } ;
880987 use crate :: catalog:: { ColumnCatalog , ColumnDesc , ColumnRef } ;
881- use crate :: db:: { DataBaseBuilder , DatabaseError , ResultIter } ;
988+ use crate :: db:: { DataBaseBuilder , DatabaseError } ;
882989 use crate :: expression:: ScalarExpression ;
883990 use crate :: planner:: operator:: join:: JoinCondition ;
884991 use crate :: planner:: operator:: Operator ;
0 commit comments