matdb 0.1.0

An experimental embedded SQL-like DBMS
Documentation
use std::{fmt::Display, iter::once};

use crate::{
    ast::{Column, Expr},
    value::Type,
};

#[derive(Debug, Clone)]
pub struct TableSchema {
    pub readonly: bool,
    pub name: String,
    pub columns: Vec<ColumnSchema>,
    pub checks: Vec<Expr>,
    pub indexes: Vec<Index>,
    pub primary_key: Vec<Expr>,
    pub foreign_keys: Vec<ForeignKey>,
    pub referenced_by: Vec<String>,
}

impl Display for TableSchema {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!(
            "CREATE{} TABLE {} ({});",
            if self.readonly { " READONLY" } else { "" },
            self.name,
            self.columns
                .iter()
                .map(|c| format!(
                    "{} {}{}",
                    c.name,
                    c.ty,
                    if !c.nullable { " NOT NULL" } else { "" }
                ))
                .chain(self.checks.iter().map(|c| format!("CHECK({c})")))
                .chain(self.indexes.iter().map(|index| format!(
                        "{}KEY({})",
                        if index.unique { "UNIQUE " } else { "" },
                        index
                            .exprs
                            .iter()
                            .map(|e| e.to_string())
                            .collect::<Vec<_>>()
                            .join(",")
                    )))
                .chain(once(format!(
                    "PRIMARY KEY({})",
                    self.primary_key
                        .iter()
                        .map(|e| e.to_string())
                        .collect::<Vec<_>>()
                        .join(",")
                )))
                .chain(self.foreign_keys.iter().map(|fk| fk.to_string()))
                .chain(once(format!(
                    "REFERENCED BY({})",
                    self.referenced_by.clone().join(",")
                )))
                .collect::<Vec<String>>()
                .join(",")
        ))
    }
}

#[derive(Debug, Clone)]
pub struct Index {
    pub exprs: Vec<Expr>,
    pub unique: bool,
}

impl Index {
    pub fn name(&self, table: &str) -> String {
        format!(
            "{table}.{}",
            self.exprs
                .iter()
                .map(|e| format!("{e}"))
                .collect::<Vec<_>>()
                .join(",")
        )
    }
}

#[derive(Debug, Clone)]
pub struct ForeignKey {
    pub lhs_exprs: Vec<Expr>,
    pub rhs_table: String,
    pub rhs_exprs: Vec<Expr>,
}

impl Display for ForeignKey {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!(
            "FOREIGN KEY({}) REFERENCES {}({})",
            self.lhs_exprs
                .iter()
                .map(|e| e.to_string())
                .collect::<Vec<_>>()
                .join(","),
            self.rhs_table,
            self.rhs_exprs
                .iter()
                .map(|e| e.to_string())
                .collect::<Vec<_>>()
                .join(",")
        ))
    }
}

#[derive(Debug, Clone)]
pub struct ColumnSchema {
    pub name: String,
    pub ty: Type,
    pub nullable: bool,
}

pub const MATDB_TABLES: &str = "matdb_tables";

pub fn matdb_tables_schema() -> TableSchema {
    TableSchema {
        readonly: true,
        name: MATDB_TABLES.to_string(),
        columns: vec![
            ColumnSchema {
                name: "name".to_string(),
                ty: Type::String,
                nullable: false,
            },
            ColumnSchema {
                name: "tree_id".to_string(),
                ty: Type::Int,
                nullable: false,
            },
        ],
        checks: vec![],
        indexes: vec![],
        primary_key: vec![Expr::Column(Column(
            MATDB_TABLES.to_string(),
            "name".to_string(),
        ))],
        foreign_keys: vec![],
        referenced_by: vec![],
    }
}

pub const MATDB_SCHEMAS: &str = "matdb_schemas";

pub fn matdb_schemas_schema() -> TableSchema {
    TableSchema {
        readonly: true,
        name: MATDB_SCHEMAS.to_string(),
        columns: vec![
            ColumnSchema {
                name: "name".to_string(),
                ty: Type::String,
                nullable: false,
            },
            ColumnSchema {
                name: "schema".to_string(),
                ty: Type::String,
                nullable: false,
            },
        ],
        checks: vec![],
        indexes: vec![],
        primary_key: vec![Expr::Column(Column(
            MATDB_SCHEMAS.to_string(),
            "name".to_string(),
        ))],
        foreign_keys: vec![],
        referenced_by: vec![],
    }
}

pub const MATDB_REVS: &str = "matdb_revs";

pub fn matdb_revs_schema() -> TableSchema {
    TableSchema {
        readonly: true,
        name: MATDB_REVS.to_string(),
        columns: vec![
            ColumnSchema {
                name: "tx_id".to_string(),
                ty: Type::Int,
                nullable: false,
            },
            ColumnSchema {
                name: "page_number".to_string(),
                ty: Type::Int,
                nullable: false,
            },
        ],
        checks: vec![],
        indexes: vec![],
        primary_key: vec![Expr::Column(Column(
            MATDB_REVS.to_string(),
            "tx_id".to_string(),
        ))],
        foreign_keys: vec![],
        referenced_by: vec![],
    }
}