toql_sql_expr_macro/
lib.rs

1//! The `sql_expr!` macro compiles an SQL expression into program code.
2//!
3//! ### Example
4//! ```rust, ignore
5//! use toql_sql_expr_macro::sql_expr;
6//!
7//! let e = sql_expr!("SELECT ..id FROM User .. WHERE ..age <= <age>");
8//! ```
9
10#![recursion_limit = "512"]
11
12extern crate proc_macro;
13
14extern crate syn;
15
16#[macro_use]
17extern crate quote;
18
19use syn::parse_macro_input;
20
21use proc_macro::TokenStream;
22
23mod sql_expr_macro;
24
25#[proc_macro]
26pub fn sql_expr(input: TokenStream) -> TokenStream {
27    let _ = env_logger::try_init(); // Avoid multiple init
28                                    // eprintln!("{:?}", input);
29
30    let ast = parse_macro_input!(input as sql_expr_macro::SqlExprMacro);
31
32    let gen = sql_expr_macro::parse(&ast.query, &mut ast.arguments.iter());
33
34    match gen {
35        Ok(o) => {
36            tracing::debug!(
37                "Source code for `{}`:\n{}",
38                ast.query.value(),
39                o.to_string()
40            );
41            TokenStream::from(o)
42        }
43        Err(e) => {
44            tracing::debug!(
45                "Source code for `{}`:\n{}",
46                ast.query.value(),
47                e.to_string()
48            );
49            TokenStream::from(e)
50        }
51    }
52}
53
54#[test]
55fn literal_and_alias() {
56    use sql_expr_macro::SqlExprMacro;
57    let input = "\"SELECT ..id FROM Table .. JOIN OtherTable ...\"";
58
59    let m = syn::parse_str(input);
60    assert_eq!(m.is_ok(), true);
61
62    let SqlExprMacro { query, arguments } = m.unwrap();
63    let f = sql_expr_macro::parse(&query, &mut arguments.iter());
64    assert_eq!(f.is_ok(), true);
65
66    assert_eq!(f.unwrap().to_string(), "{ let mut t = toql :: sql_expr :: SqlExpr :: new ( ) ; \
67        t . extend ( toql :: sql_expr :: SqlExpr :: from ( vec ! [ \
68            toql :: sql_expr :: SqlExprToken :: Literal ( String :: from ( \"SELECT \" ) ) , \
69            toql :: sql_expr :: SqlExprToken :: SelfAlias , \
70            toql :: sql_expr :: SqlExprToken :: Literal ( String :: from ( \".id FROM Table \" ) ) , \
71            toql :: sql_expr :: SqlExprToken :: SelfAlias , \
72            toql :: sql_expr :: SqlExprToken :: Literal ( String :: from ( \" JOIN OtherTable \" ) ) , \
73            toql :: sql_expr :: SqlExprToken :: OtherAlias ] ) ) ; t }");
74}
75#[test]
76fn placeholders_and_aux_params() {
77    use sql_expr_macro::SqlExprMacro;
78    let input = "\"SELECT ?, <aux_parm>\"";
79
80    let m = syn::parse_str(input);
81    assert_eq!(m.is_ok(), true);
82
83    let SqlExprMacro { query, arguments } = m.unwrap();
84    let f = sql_expr_macro::parse(&query, &mut arguments.iter());
85    assert_eq!(f.is_ok(), true);
86
87    assert_eq!(f.unwrap().to_string(), "{ let mut t = toql :: sql_expr :: SqlExpr :: new ( ) ; \
88    t . extend ( toql :: sql_expr :: SqlExpr :: from ( vec ! [ \
89        toql :: sql_expr :: SqlExprToken :: Literal ( String :: from ( \"SELECT \" ) ) , \
90        toql :: sql_expr :: SqlExprToken :: UnresolvedArg , \
91        toql :: sql_expr :: SqlExprToken :: Literal ( String :: from ( \", \" ) ) , \
92        toql :: sql_expr :: SqlExprToken :: AuxParam ( String :: from ( \"aux_parm\" ) ) ] ) ) ; t }");
93}
94#[test]
95fn quotes() {
96    use sql_expr_macro::SqlExprMacro;
97    let input = "\"SELECT '''?', '<aux_parm>'\"";
98
99    let m = syn::parse_str(input);
100    assert_eq!(m.is_ok(), true);
101
102    let SqlExprMacro { query, arguments } = m.unwrap();
103    let f = sql_expr_macro::parse(&query, &mut arguments.iter());
104    assert_eq!(f.is_ok(), true);
105
106    assert_eq!(f.unwrap().to_string(), "{ let mut t = toql :: sql_expr :: SqlExpr :: new ( ) ; \
107    t . extend ( toql :: sql_expr :: SqlExpr :: from ( vec ! [ \
108        toql :: sql_expr :: SqlExprToken :: Literal ( String :: from ( \"SELECT \'\'\'?\', \'<aux_parm>\'\" ) ) ] ) ) ; t }");
109}