@@ -25,8 +25,9 @@ use futures::{
25
25
} ;
26
26
use futures_util:: io;
27
27
use reqwest:: Method ;
28
- use serde:: Serialize ;
29
28
use serde:: de:: DeserializeOwned ;
29
+ use serde:: { Deserialize , Serialize } ;
30
+ use std:: pin:: Pin ;
30
31
use tokio:: io:: { AsyncBufReadExt , BufReader } ;
31
32
use tokio_stream:: wrappers:: LinesStream ;
32
33
use tokio_util:: io:: StreamReader ;
@@ -61,19 +62,54 @@ pub trait OneShotRequest: ClientRequest {
61
62
Ok ( ( ) )
62
63
}
63
64
}
65
+ #[ derive( Deserialize , Debug ) ]
66
+ #[ serde( tag = "type" , content = "payload" , rename_all = "camelCase" ) ]
67
+ enum StreamLineItem < T > {
68
+ Error {
69
+ error : String ,
70
+ } ,
71
+ Heartbeat ,
72
+ #[ serde( untagged) ]
73
+ Ok {
74
+ #[ serde( rename = "type" ) ]
75
+ ty : String ,
76
+ payload : T ,
77
+ } ,
78
+ }
79
+
80
+ impl < T > StreamLineItem < T > {
81
+ pub fn into_result_option ( self , expected_type : & str ) -> Result < Option < T > , ClientError > {
82
+ match self {
83
+ StreamLineItem :: Error { error } => Err ( ClientError :: DBError ( error) ) ,
84
+ StreamLineItem :: Heartbeat => Ok ( None ) ,
85
+ StreamLineItem :: Ok { ty, payload } => {
86
+ if ty == expected_type {
87
+ Ok ( Some ( payload) )
88
+ } else {
89
+ Err ( ClientError :: InvalidResponseType ( ty) )
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
64
95
65
96
/// Represents a request to the database that expects a stream of responses
66
97
pub trait StreamingRequest : ClientRequest {
67
98
type ItemType : DeserializeOwned ;
99
+ const ITEM_TYPE_NAME : & ' static str ;
68
100
69
101
fn build_stream (
70
102
response : reqwest:: Response ,
71
- ) -> impl Stream < Item = Result < Self :: ItemType , ClientError > > {
72
- Self :: lines_stream ( response) . map ( |line| {
73
- let line = line?;
74
- let item = serde_json:: from_str ( line. as_str ( ) ) ?;
75
- Ok ( item)
76
- } )
103
+ ) -> Pin < Box < impl Stream < Item = Result < Self :: ItemType , ClientError > > > > {
104
+ Box :: pin (
105
+ Self :: lines_stream ( response)
106
+ . map ( |line| {
107
+ let line = line?;
108
+ let item: StreamLineItem < Self :: ItemType > = serde_json:: from_str ( line. as_str ( ) ) ?;
109
+ item. into_result_option ( Self :: ITEM_TYPE_NAME )
110
+ } )
111
+ . filter_map ( |o| async { o. transpose ( ) } ) ,
112
+ )
77
113
}
78
114
79
115
fn lines_stream (
0 commit comments