kosame_dsl 0.3.0

Macro-based Rust ORM focused on developer ergonomics
Documentation
use std::{fmt::Display, ops::Deref};

use syn::{
    Token,
    parse::{Parse, ParseStream},
};

use crate::{
    expr::ExprRoot,
    keyword,
    pretty::{PrettyPrint, Printer},
};

pub struct ColumnConstraints(pub Vec<ColumnConstraint>);

impl ColumnConstraints {
    pub fn not_null(&self) -> Option<&NotNull> {
        self.0.iter().find_map(|c| match c {
            ColumnConstraint::NotNull(inner) => Some(inner),
            _ => None,
        })
    }

    pub fn primary_key(&self) -> Option<&PrimaryKey> {
        self.0.iter().find_map(|c| match c {
            ColumnConstraint::PrimaryKey(inner) => Some(inner),
            _ => None,
        })
    }

    pub fn default(&self) -> Option<&Default> {
        self.0.iter().find_map(|c| match c {
            ColumnConstraint::Default(inner) => Some(inner),
            _ => None,
        })
    }
}

impl Parse for ColumnConstraints {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let mut constraints = vec![];
        while !input.is_empty() && !input.peek(Token![,]) {
            constraints.push(input.parse()?);
        }
        Ok(Self(constraints))
    }
}

impl PrettyPrint for ColumnConstraints {
    fn pretty_print(&self, printer: &mut Printer<'_>) {
        for constraint in &self.0 {
            printer.scan_break();
            " ".pretty_print(printer);
            constraint.pretty_print(printer);
        }
    }
}

impl Deref for ColumnConstraints {
    type Target = Vec<ColumnConstraint>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[allow(unused)]
pub enum ColumnConstraint {
    NotNull(NotNull),
    PrimaryKey(PrimaryKey),
    Default(Default),
}

impl Parse for ColumnConstraint {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(keyword::not) {
            Ok(Self::NotNull(input.parse()?))
        } else if lookahead.peek(keyword::primary) {
            Ok(Self::PrimaryKey(input.parse()?))
        } else if lookahead.peek(keyword::default) {
            Ok(Self::Default(input.parse()?))
        } else {
            keyword::group_column_constraint::error(input);
        }
    }
}

impl PrettyPrint for ColumnConstraint {
    fn pretty_print(&self, printer: &mut Printer<'_>) {
        match self {
            Self::NotNull(inner) => {
                inner.not_kw.pretty_print(printer);
                " ".pretty_print(printer);
                inner.null_kw.pretty_print(printer);
            }
            Self::PrimaryKey(inner) => {
                inner.primary_kw.pretty_print(printer);
                " ".pretty_print(printer);
                inner.key_kw.pretty_print(printer);
            }
            Self::Default(inner) => {
                inner.default_kw.pretty_print(printer);
                " ".pretty_print(printer);
                inner.expr.pretty_print(printer);
            }
        }
    }
}

impl Display for ColumnConstraint {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NotNull(_) => f.write_str("not null")?,
            Self::PrimaryKey(_) => f.write_str("primary key")?,
            Self::Default(_) => f.write_str("default ...")?,
        }
        Ok(())
    }
}

pub struct NotNull {
    pub not_kw: keyword::not,
    pub null_kw: keyword::null,
}

impl Parse for NotNull {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            not_kw: input.call(keyword::not::parse_autocomplete)?,
            null_kw: input.call(keyword::null::parse_autocomplete)?,
        })
    }
}

pub struct PrimaryKey {
    pub primary_kw: keyword::primary,
    pub key_kw: keyword::key,
}

impl Parse for PrimaryKey {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            primary_kw: input.call(keyword::primary::parse_autocomplete)?,
            key_kw: input.call(keyword::key::parse_autocomplete)?,
        })
    }
}

pub struct Default {
    pub default_kw: keyword::default,
    pub expr: ExprRoot,
}

impl Parse for Default {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            default_kw: input.call(keyword::default::parse_autocomplete)?,
            expr: input.parse()?,
        })
    }
}