1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#![doc = include_str!("../README.md")]

mod db;
mod join;

use proc_macro as pc;
use proc_macro2::Span;
use std::fmt;
use syn::Ident;

/// Printing errors at the current span
fn s_err(span: proc_macro2::Span, msg: impl fmt::Display) -> syn::Error {
    syn::Error::new(span, msg)
}

/// Capitalizing ident
///
/// # Example
///
/// `user_name` => `UserName`
fn capitalize_ident(ident: &Ident) -> Ident {
    let capitalized: String = ident
        .to_string()
        .split('_')
        .map(|part| {
            let mut c = part.chars();
            match c.next() {
                None => String::new(),
                Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
            }
        })
        .collect();

    Ident::new(&capitalized, Span::call_site())
}

/// Pre-Extending ident
///
/// # Example
///
/// `pre_extend_ident(ident, "extend_")` => `extend_ident`
fn pre_extend_ident(ident: &Ident, pre_extend: &str) -> Ident {
    Ident::new(
        &(pre_extend.to_string() + &ident.to_string()),
        Span::call_site(),
    )
}

/// Creates the Database struct with the fitting logic
///
/// ## Functions
/// - `insert_#table`
/// - `get_#table`
/// - `edit_#table`
/// - `delete_#table`
/// - `search_#table`
///
/// ## Example
/// ```
/// use light_magic::db;
///
/// db! {
///     // `users` is the table name
///     // `{...}` is the table data
///     // the first field, like here `name`, is the `primary_key`
///     user => { id: usize, name: String, kind: String },
///     // using [...] after the table name you can add your own derives
///     // like here `PartialEq`
///     criminal: [PartialEq] => { user_name: String, entry: String }
/// }
/// ```
#[proc_macro]
pub fn db(input: pc::TokenStream) -> pc::TokenStream {
    match db::db_inner(input.into()) {
        Ok(result) => result.into(),
        Err(e) => e.into_compile_error().into(),
    }
}

/// Joins Data in the Database together
///
/// ## Example
/// ```
/// use light_magic::{db, join};
///
/// db! {
///     user => { id: usize, name: String, kind: String },
///     criminal => { user_name: String, entry: String }
/// }
///
/// let db = Database::new();
/// /// Firstly specify the to db which should be used, then the key,
/// /// and lastly the joined items with the field which should be joined
/// let joined = join!(db, "Nils", user => name, criminal => user_name);
/// ```
#[proc_macro]
pub fn join(input: pc::TokenStream) -> pc::TokenStream {
    match join::join_inner(input.into()) {
        Ok(result) => result.into(),
        Err(e) => e.into_compile_error().into(),
    }
}