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
#![allow(non_snake_case)]

mod attr;
mod metadata;
mod error;
mod ext;
mod syndecode;

use std::fs;
use std::path::Path;
use syn::{DeriveInput, Item};
use ignore::Walk;

use syndecode::Attributes;
pub use metadata::*;
pub use attr::*;
pub use error::*;
pub use ext::*;

#[derive(Default, Debug)]
pub struct LoadOptions {
    pub verbose: bool,
}

pub fn load_from_project(paths: &[&Path], opts: &LoadOptions) -> anyhow::Result<Vec<TableMetadata>> {
    let walk = paths.iter().map(|p| Walk::new(p)).flatten();
    let mut results = vec![];

    let walk = walk.filter_map(|e| e.ok())
        .filter(|e| e.path().extension().map(|e| e == "rs")
            .unwrap_or(false));

    for entry in walk {
        let contents = fs::read_to_string(&entry.path())?;
        if !contents.contains("Model") {
            continue;
        }
        if opts.verbose {
            eprintln!("{}: Checking for #[derive(Model)]", entry.path().display());
        }
        let ast = syn::parse_file(&contents)?;
        let structs = ast.items.into_iter().filter_map(|item| match item {
            Item::Struct(s) => Some(s),
            _ => None,
        })
            .map(|s| {
                let attrs = Attributes::filter_from(&s.attrs, "ormlite");
                (s, attrs)
            })
            .inspect(|(s, attrs)| {
                if opts.verbose {
                    eprintln!("{}: Found struct {}. Detected derives: {:?}", entry.path().display(), s.ident, attrs.derives());
                }
            })
            .filter(|(_, attrs)| attrs.has_derive("Model"))
            .collect::<Vec<_>>();
        for (item, _attrs) in structs {
            let derive: DeriveInput = item.into();
            let table = TableMetadata::try_from(&derive)
                .map_err(|e| SyndecodeError(format!(
                    "{}: Encounterd an error while scanning for #[derive(Model)] structs: {}",
                    entry.path().display(), e.to_string()))
                )?;
            results.push(table);
        }
    }
    if results.is_empty() {
        panic!("No models found in the given paths: {}", paths.iter().map(|p| p.display().to_string()).collect::<Vec<_>>().join(", "));
    }
    Ok(results)
}