xitca_postgres_codegen/
lib.rs

1//! this is an example macro for xitca-postgres
2//! it doesn't have any usability beyond as tutorial material.
3
4use quote::quote;
5use sqlparser::{dialect::PostgreSqlDialect, parser::Parser};
6use syn::{
7    parse::{Parse, ParseStream},
8    spanned::Spanned,
9    token::Comma,
10    Expr, ExprReference, Lit, LitStr,
11};
12
13#[proc_macro]
14pub fn sql(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
15    let Query { sql, exprs, types } = syn::parse_macro_input!(input as Query);
16
17    quote! {
18        ::xitca_postgres::statement::Statement::unnamed(#sql, &[#(#types),*])
19            .bind_dyn(&[#(#exprs),*])
20    }
21    .into()
22}
23
24struct Query {
25    sql: LitStr,
26    exprs: Vec<ExprReference>,
27    types: Vec<proc_macro2::TokenStream>,
28}
29
30impl Parse for Query {
31    fn parse(input: ParseStream) -> syn::Result<Self> {
32        let sql = input.parse::<LitStr>()?;
33
34        Parser::parse_sql(&PostgreSqlDialect {}, &sql.value())
35            .map_err(|e| syn::Error::new(sql.span(), e.to_string()))?;
36
37        let mut exprs = Vec::new();
38        let mut types = Vec::new();
39
40        while input.parse::<Comma>().is_ok() {
41            let expr = input.parse::<ExprReference>()?;
42            let Expr::Lit(lit) = expr.expr.as_ref() else {
43                return Err(syn::Error::new(
44                    expr.span(),
45                    "example can only handle literal expression",
46                ));
47            };
48            let ty = match lit.lit {
49                Lit::Str(_) => quote! { ::xitca_postgres::types::Type::TEXT },
50                Lit::Int(_) => quote! { ::xitca_postgres::types::Type::INT4 },
51                ref lit => {
52                    return Err(syn::Error::new(
53                        lit.span(),
54                        "example can only handle i32 and String type as parameter",
55                    ))
56                }
57            };
58            types.push(ty);
59            exprs.push(expr);
60        }
61
62        Ok(Self { sql, exprs, types })
63    }
64}