Skip to main content

gluesql_core/executor/
fetch.rs

1use {
2    super::{context::RowContext, filter::check_expr},
3    crate::{
4        data::{Key, Row, SCHEMALESS_DOC_COLUMN},
5        plan::ExprPlan,
6        result::Result,
7        store::GStore,
8    },
9    serde::Serialize,
10    std::{borrow::Cow, fmt::Debug, rc::Rc},
11    thiserror::Error as ThisError,
12};
13
14pub type KeyedRows<'a> = Box<dyn Iterator<Item = Result<(Key, Row)>> + 'a>;
15
16#[derive(ThisError, Serialize, Debug, PartialEq, Eq)]
17pub enum FetchError {
18    #[error("table not found: {0}")]
19    TableNotFound(String),
20}
21
22pub fn fetch<'a, T: GStore>(
23    storage: &'a T,
24    table_name: &'a str,
25    columns: Rc<[String]>,
26    where_clause: Option<&'a ExprPlan>,
27) -> Result<KeyedRows<'a>> {
28    let rows = storage.scan_data(table_name)?.filter_map(move |row| {
29        let (key, values) = match row {
30            Ok(row) => row,
31            Err(error) => return Some(Err(error)),
32        };
33        let row = Row {
34            columns: Rc::clone(&columns),
35            values,
36        };
37
38        match where_clause {
39            Some(expr) => {
40                let context = RowContext::new(table_name, Cow::Borrowed(&row), None);
41                let context = Rc::new(context);
42                match check_expr(storage, Some(&context), None, expr) {
43                    Ok(true) => Some(Ok((key, row))),
44                    Ok(false) => None,
45                    Err(error) => Some(Err(error)),
46                }
47            }
48            None => Some(Ok((key, row))),
49        }
50    });
51
52    Ok(Box::new(rows))
53}
54
55pub fn fetch_columns<T: GStore>(storage: &T, table_name: &str) -> Result<Vec<String>> {
56    let columns = storage
57        .fetch_schema(table_name)?
58        .ok_or_else(|| FetchError::TableNotFound(table_name.to_owned()))?
59        .column_defs
60        .map_or_else(
61            || vec![SCHEMALESS_DOC_COLUMN.to_owned()],
62            |column_defs| {
63                column_defs
64                    .into_iter()
65                    .map(|column_def| column_def.name)
66                    .collect()
67            },
68        );
69
70    Ok(columns)
71}