matdb 0.1.0

An experimental embedded SQL-like DBMS
Documentation
use std::fmt::Debug;

use anyhow::{anyhow, Result};

use crate::{
    ast::{Column, Expr},
    eval::Context,
    kv::{Range, RangeEnd, RangeIterKV},
    Db,
};

#[derive(Debug)]
pub struct RangeScan {
    table: String,
    alias: String,
    tx_id: u64,

    index: Option<String>,

    range: Range<Expr>,

    iter: Option<RangeIterKV>,
}

impl RangeScan {
    pub fn new(
        table: String,
        alias: String,
        tx_id: u64,
        index: Option<String>,
        range: Range<Expr>,
    ) -> Self {
        Self {
            range,
            iter: None,
            table,
            alias,
            index,
            tx_id,
        }
    }

    pub fn execute<'a>(&'a mut self, db: &'a mut Db, mut ctx: Context) -> Result<Option<Context>> {
        self.iter = Some(
            self.iter
                .take()
                .map(|x| -> Result<_> { Ok(x) })
                .unwrap_or_else(|| {
                    Ok(RangeIterKV::new(
                        Range {
                            backwards: false,
                            prefix: self
                                .range
                                .prefix
                                .iter()
                                .map(|e| ctx.eval(e))
                                .collect::<Result<Vec<_>, _>>()?,
                            start: self
                                .range
                                .start
                                .as_ref()
                                .map(|s| -> Result<_> {
                                    Ok(RangeEnd {
                                        inclusive: s.inclusive,
                                        value: ctx.eval(&s.value)?,
                                    })
                                })
                                .transpose()?,
                            end: self
                                .range
                                .end
                                .as_ref()
                                .map(|e| -> Result<_> {
                                    Ok(RangeEnd {
                                        inclusive: e.inclusive,
                                        value: ctx.eval(&e.value)?,
                                    })
                                })
                                .transpose()?,
                        },
                        self.tx_id,
                        self.index.clone().unwrap_or(self.table.clone()),
                    ))
                })?,
        );

        let schema = db.get_table_schema(self.tx_id, &self.table)?;

        Ok(self
            .iter
            .as_mut()
            .unwrap()
            .next(db)?
            .map(|(k, v)| -> Result<_> {
                Ok(if self.index.is_some() {
                    RangeIterKV::new(
                        Range {
                            backwards: false,
                            prefix: v[v.len() - schema.primary_key.len()..].to_vec(),
                            start: None,
                            end: None,
                        },
                        self.tx_id,
                        self.table.clone(),
                    )
                    .next(db)?
                    .ok_or(anyhow!("missing table entry for index"))?
                } else {
                    (k, v)
                })
            })
            .transpose()?
            .map(|(_, v)| {
                for (col, v) in schema.columns.into_iter().zip(v.into_iter()) {
                    ctx.set(Column(self.alias.clone(), col.name), v);
                }

                ctx
            })
            .or_else(|| {
                self.iter = None;
                None
            }))
    }
}