kosame_dsl 0.3.0

Macro-based Rust ORM focused on developer ergonomics
Documentation
use crate::{
    inferred_type::InferredType,
    pretty::{PrettyPrint, Printer},
    scopes::ScopeId,
};

use super::Visit;
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};
use syn::{
    Ident, Token,
    parse::{Parse, ParseStream},
};

pub struct ColumnRef {
    pub correlation: Option<Correlation>,
    pub name: Ident,
}

impl ColumnRef {
    #[must_use]
    pub fn infer_name(&self) -> Option<&Ident> {
        Some(&self.name)
    }

    #[must_use]
    pub fn infer_type(&self, scope_id: ScopeId) -> Option<InferredType<'_>> {
        Some(InferredType::Scope {
            scope_id,
            table: self
                .correlation
                .as_ref()
                .map(|correlation| &correlation.name),
            column: &self.name,
        })
    }

    #[must_use]
    pub fn span(&self) -> Span {
        if let Some(correlation) = &self.correlation {
            correlation
                .name
                .span()
                .join(self.name.span())
                .unwrap_or(self.name.span())
        } else {
            self.name.span()
        }
    }
}

pub fn visit_column_ref<'a>(_visit: &mut (impl Visit<'a> + ?Sized), _column_ref: &'a ColumnRef) {}

impl Parse for ColumnRef {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let ident1 = input.parse::<Ident>()?;
        if input.peek(Token![.]) {
            let correlation = Correlation {
                name: ident1,
                period_token: input.parse()?,
            };
            Ok(Self {
                correlation: Some(correlation),
                name: input.parse()?,
            })
        } else {
            Ok(Self {
                correlation: None,
                name: ident1,
            })
        }
    }
}

impl PrettyPrint for ColumnRef {
    fn pretty_print(&self, printer: &mut Printer) {
        self.correlation.pretty_print(printer);
        self.name.pretty_print(printer);
    }
}

impl ToTokens for ColumnRef {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let name = &self.name;
        let scope_id = ScopeId::of_scope();
        match &self.correlation {
            Some(correlation) => {
                let correlation = &correlation.name;
                quote! {
                    ::kosame::repr::expr::ColumnRef::new(
                        Some(scopes::#scope_id::tables::#correlation::TABLE_NAME),
                        scopes::#scope_id::tables::#correlation::columns::#name::COLUMN_NAME
                    )
                }
                .to_tokens(tokens);
            }
            None => quote! {
                ::kosame::repr::expr::ColumnRef::new(
                    ::core::option::Option::None,
                    scopes::#scope_id::columns::#name::COLUMN_NAME
                )
            }
            .to_tokens(tokens),
        }
    }
}

pub struct Correlation {
    pub name: Ident,
    pub period_token: Token![.],
}

impl PrettyPrint for Correlation {
    fn pretty_print(&self, printer: &mut Printer) {
        self.name.pretty_print(printer);
        self.period_token.pretty_print(printer);
    }
}