1use std::sync::Arc;
4
5use arrow_array::RecordBatch;
6use arrow_schema::{Schema, SchemaRef};
7use futures::{StreamExt as _, TryStreamExt as _, stream};
8
9use crate::scandal::error::ScandalError;
10use crate::scandal::{Scandal, TableBinding};
11use crate::{BatchStream, Error, FunctionInfo, NamedExpression, Scan};
12
13#[derive(Clone)]
18pub struct Functions {
19 scandal: Arc<dyn Scandal>,
20 catalog: Arc<Vec<FunctionInfo>>,
21}
22
23impl Functions {
24 pub async fn new(scandal: Arc<dyn Scandal>) -> Result<Self, Error> {
26 let catalog = Arc::new(scandal.list_functions().await?);
27 Ok(Self { scandal, catalog })
28 }
29
30 pub fn list(&self) -> &[FunctionInfo] {
32 &self.catalog
33 }
34
35 pub async fn bind(
39 &self,
40 outputs: &[NamedExpression],
41 input: &Schema,
42 ) -> Result<SchemaRef, Error> {
43 Ok(self.scandal.bind_projection(input, outputs).await?)
44 }
45
46 pub async fn project_stream(
51 &self,
52 outputs: &[NamedExpression],
53 input: BatchStream,
54 ) -> Result<BatchStream, Error> {
55 self.evaluate_stream(outputs, input, &[]).await
56 }
57
58 pub async fn project_stream_with_scans(
64 &self,
65 outputs: &[NamedExpression],
66 input: BatchStream,
67 scans: &[Scan],
68 ) -> Result<BatchStream, Error> {
69 let mut tables = Vec::with_capacity(scans.len());
70 for scan in scans {
71 tables.extend(scan.table_binding().await?);
72 }
73 self.evaluate_stream(outputs, input, &tables).await
74 }
75
76 pub async fn evaluate(
79 &self,
80 outputs: &[NamedExpression],
81 batch: RecordBatch,
82 ) -> Result<Vec<RecordBatch>, Error> {
83 let input = BatchStream::from_stream(batch.schema(), stream::iter([Ok(batch)]));
84 self.project_stream(outputs, input)
85 .await?
86 .try_collect()
87 .await
88 }
89
90 async fn evaluate_stream(
91 &self,
92 outputs: &[NamedExpression],
93 input: BatchStream,
94 tables: &[TableBinding],
95 ) -> Result<BatchStream, Error> {
96 let schema = input.schema();
97 let input = input
98 .map_err(|error| ScandalError::InvalidArgument {
99 message: error.to_string(),
100 })
101 .boxed();
102 let evaluation = self
103 .scandal
104 .evaluate(outputs, schema, input, tables)
105 .await?;
106 Ok(BatchStream::from_stream(
107 evaluation.schema,
108 evaluation.batches.map_err(Error::from),
109 ))
110 }
111}