1use std::pin::Pin;
16use std::sync::Arc;
17use std::task::{Context, Poll};
18
19use arc_swap::ArcSwapOption;
20use datatypes::schema::SchemaRef;
21use futures::{Stream, StreamExt, TryStreamExt};
22use snafu::ensure;
23
24use crate::adapter::RecordBatchMetrics;
25use crate::error::{EmptyStreamSnafu, Result, SchemaNotMatchSnafu};
26use crate::{
27 OrderOption, RecordBatch, RecordBatchStream, RecordBatches, SendableRecordBatchStream,
28};
29
30pub async fn collect(stream: SendableRecordBatchStream) -> Result<Vec<RecordBatch>> {
32 stream.try_collect::<Vec<_>>().await
33}
34
35pub async fn collect_batches(stream: SendableRecordBatchStream) -> Result<RecordBatches> {
37 let schema = stream.schema();
38 let batches = stream.try_collect::<Vec<_>>().await?;
39 RecordBatches::try_new(schema, batches)
40}
41
42pub struct ChainedRecordBatchStream {
44 inputs: Vec<SendableRecordBatchStream>,
45 curr_index: usize,
46 schema: SchemaRef,
47 metrics: Arc<ArcSwapOption<RecordBatchMetrics>>,
48}
49
50impl ChainedRecordBatchStream {
51 pub fn new(inputs: Vec<SendableRecordBatchStream>) -> Result<Self> {
52 ensure!(!inputs.is_empty(), EmptyStreamSnafu);
54
55 let first_schema = inputs[0].schema();
57 for input in inputs.iter().skip(1) {
58 let schema = input.schema();
59 ensure!(
60 first_schema == schema,
61 SchemaNotMatchSnafu {
62 left: first_schema,
63 right: schema
64 }
65 );
66 }
67
68 Ok(Self {
69 inputs,
70 curr_index: 0,
71 schema: first_schema,
72 metrics: Default::default(),
73 })
74 }
75
76 fn sequence_poll(
77 mut self: Pin<&mut Self>,
78 ctx: &mut Context<'_>,
79 ) -> Poll<Option<Result<RecordBatch>>> {
80 if self.curr_index >= self.inputs.len() {
81 return Poll::Ready(None);
82 }
83
84 let curr_index = self.curr_index;
85 match self.inputs[curr_index].poll_next_unpin(ctx) {
86 Poll::Ready(Some(Ok(batch))) => Poll::Ready(Some(Ok(batch))),
87 Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(e))),
88 Poll::Ready(None) => {
89 self.curr_index += 1;
90 if self.curr_index < self.inputs.len() {
91 self.sequence_poll(ctx)
92 } else {
93 Poll::Ready(None)
94 }
95 }
96 Poll::Pending => Poll::Pending,
97 }
98 }
99}
100
101pub struct LimitedRecordBatchStream {
103 input: Option<SendableRecordBatchStream>,
104 remaining: usize,
105 schema: SchemaRef,
106 output_ordering: Option<Vec<OrderOption>>,
107}
108
109impl LimitedRecordBatchStream {
110 pub fn new(input: SendableRecordBatchStream, limit: usize) -> Self {
111 let schema = input.schema();
112 let output_ordering = input.output_ordering().map(|o| o.to_vec());
113 Self {
114 input: Some(input),
115 remaining: limit,
116 schema,
117 output_ordering,
118 }
119 }
120}
121
122impl RecordBatchStream for LimitedRecordBatchStream {
123 fn name(&self) -> &str {
124 "LimitedRecordBatchStream"
125 }
126
127 fn schema(&self) -> SchemaRef {
128 self.schema.clone()
129 }
130
131 fn output_ordering(&self) -> Option<&[OrderOption]> {
132 self.output_ordering.as_deref()
133 }
134
135 fn metrics(&self) -> Option<RecordBatchMetrics> {
136 self.input.as_ref().and_then(|input| input.metrics())
137 }
138}
139
140impl Stream for LimitedRecordBatchStream {
141 type Item = Result<RecordBatch>;
142
143 fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
144 if self.remaining == 0 {
145 self.input.take();
146 return Poll::Ready(None);
147 }
148
149 let Some(input) = self.input.as_mut() else {
150 return Poll::Ready(None);
151 };
152
153 match input.poll_next_unpin(ctx) {
154 Poll::Ready(Some(Ok(batch))) => {
155 let num_rows = batch.num_rows();
156 if num_rows > self.remaining {
157 let remaining = self.remaining;
158 self.remaining = 0;
159 self.input.take();
160 Poll::Ready(Some(batch.slice(0, remaining)))
161 } else {
162 self.remaining -= num_rows;
163 if self.remaining == 0 {
164 self.input.take();
165 }
166 Poll::Ready(Some(Ok(batch)))
167 }
168 }
169 Poll::Ready(None) => {
170 self.input.take();
171 Poll::Ready(None)
172 }
173 other => other,
174 }
175 }
176}
177
178impl RecordBatchStream for ChainedRecordBatchStream {
179 fn name(&self) -> &str {
180 "ChainedRecordBatchStream"
181 }
182
183 fn schema(&self) -> SchemaRef {
184 self.schema.clone()
185 }
186
187 fn output_ordering(&self) -> Option<&[OrderOption]> {
188 None
189 }
190
191 fn metrics(&self) -> Option<RecordBatchMetrics> {
192 self.metrics.load().as_ref().map(|m| m.as_ref().clone())
193 }
194}
195
196impl Stream for ChainedRecordBatchStream {
197 type Item = Result<RecordBatch>;
198
199 fn poll_next(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
200 self.sequence_poll(ctx)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use std::pin::Pin;
207 use std::sync::Arc;
208
209 use datatypes::prelude::*;
210 use datatypes::schema::{ColumnSchema, Schema, SchemaRef};
211 use datatypes::vectors::UInt32Vector;
212 use futures::Stream;
213 use futures::task::{Context, Poll};
214
215 use super::*;
216 use crate::adapter::RecordBatchMetrics;
217 use crate::{OrderOption, RecordBatchStream};
218
219 struct MockRecordBatchStream {
220 batch: Option<RecordBatch>,
221 schema: SchemaRef,
222 }
223
224 impl RecordBatchStream for MockRecordBatchStream {
225 fn schema(&self) -> SchemaRef {
226 self.schema.clone()
227 }
228
229 fn output_ordering(&self) -> Option<&[OrderOption]> {
230 None
231 }
232
233 fn metrics(&self) -> Option<RecordBatchMetrics> {
234 None
235 }
236 }
237
238 impl Stream for MockRecordBatchStream {
239 type Item = Result<RecordBatch>;
240
241 fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
242 let batch = self.batch.take();
243
244 if let Some(batch) = batch {
245 Poll::Ready(Some(Ok(batch)))
246 } else {
247 Poll::Ready(None)
248 }
249 }
250 }
251
252 #[tokio::test]
253 async fn test_limited_chained_stream() {
254 let column_schemas = vec![ColumnSchema::new(
255 "number",
256 ConcreteDataType::uint32_datatype(),
257 false,
258 )];
259
260 let schema = Arc::new(Schema::try_new(column_schemas).unwrap());
261 let first = RecordBatch::new(
262 schema.clone(),
263 [Arc::new(UInt32Vector::from_vec(vec![0, 1, 2])) as _],
264 )
265 .unwrap();
266 let second = RecordBatch::new(
267 schema.clone(),
268 [Arc::new(UInt32Vector::from_vec(vec![3, 4, 5])) as _],
269 )
270 .unwrap();
271 let chained = ChainedRecordBatchStream::new(vec![
272 Box::pin(MockRecordBatchStream {
273 schema: schema.clone(),
274 batch: Some(first),
275 }),
276 Box::pin(MockRecordBatchStream {
277 schema: schema.clone(),
278 batch: Some(second),
279 }),
280 ])
281 .unwrap();
282
283 let batches = collect(Box::pin(LimitedRecordBatchStream::new(
284 Box::pin(chained),
285 4,
286 )))
287 .await
288 .unwrap();
289
290 assert_eq!(2, batches.len());
291 assert_eq!(3, batches[0].num_rows());
292 assert_eq!(1, batches[1].num_rows());
293 }
294
295 #[tokio::test]
296 async fn test_limited_stream_with_zero_limit() {
297 let column_schemas = vec![ColumnSchema::new(
298 "number",
299 ConcreteDataType::uint32_datatype(),
300 false,
301 )];
302
303 let schema = Arc::new(Schema::try_new(column_schemas).unwrap());
304 let batch = RecordBatch::new(
305 schema.clone(),
306 [Arc::new(UInt32Vector::from_vec(vec![0])) as _],
307 )
308 .unwrap();
309 let stream = MockRecordBatchStream {
310 schema,
311 batch: Some(batch),
312 };
313
314 let batches = collect(Box::pin(LimitedRecordBatchStream::new(Box::pin(stream), 0)))
315 .await
316 .unwrap();
317
318 assert!(batches.is_empty());
319 }
320
321 #[tokio::test]
322 async fn test_collect() {
323 let column_schemas = vec![ColumnSchema::new(
324 "number",
325 ConcreteDataType::uint32_datatype(),
326 false,
327 )];
328
329 let schema = Arc::new(Schema::try_new(column_schemas).unwrap());
330
331 let stream = MockRecordBatchStream {
332 schema: schema.clone(),
333 batch: None,
334 };
335
336 let batches = collect(Box::pin(stream)).await.unwrap();
337 assert_eq!(0, batches.len());
338
339 let numbers: Vec<u32> = (0..10).collect();
340 let columns = [Arc::new(UInt32Vector::from_vec(numbers)) as _];
341 let batch = RecordBatch::new(schema.clone(), columns).unwrap();
342
343 let stream = MockRecordBatchStream {
344 schema: schema.clone(),
345 batch: Some(batch.clone()),
346 };
347 let batches = collect(Box::pin(stream)).await.unwrap();
348 assert_eq!(1, batches.len());
349 assert_eq!(batch, batches[0]);
350
351 let stream = MockRecordBatchStream {
352 schema: schema.clone(),
353 batch: Some(batch.clone()),
354 };
355 let batches = collect_batches(Box::pin(stream)).await.unwrap();
356 let expect_batches = RecordBatches::try_new(schema.clone(), vec![batch]).unwrap();
357 assert_eq!(expect_batches, batches);
358 }
359}