kosame_dsl 0.3.0

Macro-based Rust ORM focused on developer ergonomics
Documentation
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use syn::{
    Ident, Token,
    parse::{Parse, ParseStream},
    spanned::Spanned,
};

use crate::{
    clause::peek_clause,
    keyword,
    parse_option::ParseOption,
    part::ColumnList,
    pretty::{PrettyPrint, Printer},
    quote_option::QuoteOption,
};

pub struct TableAlias {
    pub as_token: Option<Token![as]>,
    pub name: Ident,
    pub columns: Option<ColumnList>,
}

impl ParseOption for TableAlias {
    fn peek(_input: ParseStream) -> bool {
        // TableAlias has custom parsing logic, so peek is not meaningful here.
        // The actual logic is in parse_option override.
        true
    }

    fn parse_option(input: ParseStream) -> syn::Result<Option<Self>> {
        if input.is_empty() || peek_clause(input) {
            return Ok(None);
        }
        macro_rules! check {
            ($kw:expr) => {
                if input.peek($kw) {
                    return Ok(None);
                }
            };
        }
        check!(keyword::inner);
        check!(keyword::left);
        check!(keyword::right);
        check!(keyword::full);
        check!(keyword::on);

        check!(keyword::natural);
        check!(keyword::cross);

        Ok(Some(input.parse()?))
    }
}

impl Parse for TableAlias {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Self {
            as_token: input.peek(Token![as]).then(|| input.parse()).transpose()?,
            name: input.parse()?,
            columns: {
                let columns = input
                    .peek(syn::token::Paren)
                    .then(|| input.parse::<ColumnList>())
                    .transpose()?;
                if let Some(columns) = columns {
                    return Err(syn::Error::new(
                        columns.paren_token.span.span(),
                        "column aliases are currently unsupported",
                    ));
                }

                columns
            },
        })
    }
}

impl ToTokens for TableAlias {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let name = &self.name.to_string();
        let columns = QuoteOption::from(&self.columns);
        quote! {
            ::kosame::repr::part::TableAlias::new(#name, #columns)
        }
        .to_tokens(tokens);
    }
}

impl PrettyPrint for TableAlias {
    fn pretty_print(&self, printer: &mut Printer<'_>) {
        " ".pretty_print(printer);
        self.as_token.pretty_print(printer);
        " ".pretty_print(printer);
        self.name.pretty_print(printer);
        self.columns.pretty_print(printer);
    }
}