forked from transact-rs/sqlx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinput.rs
More file actions
115 lines (94 loc) · 3.36 KB
/
Copy pathinput.rs
File metadata and controls
115 lines (94 loc) · 3.36 KB
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
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::fs;
use proc_macro2::{Ident, Span};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{Expr, LitBool, LitStr, Token};
use syn::{ExprArray, Type};
/// Macro input shared by `query!()` and `query_file!()`
pub struct QueryMacroInput {
pub(super) src: String,
#[cfg_attr(not(feature = "offline"), allow(dead_code))]
pub(super) src_span: Span,
pub(super) record_type: RecordType,
pub(super) arg_exprs: Vec<Expr>,
pub(super) checked: bool,
}
enum QuerySrc {
String(String),
File(String),
}
pub enum RecordType {
Given(Type),
Generated,
}
impl Parse for QueryMacroInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut query_src: Option<(QuerySrc, Span)> = None;
let mut args: Option<Vec<Expr>> = None;
let mut record_type = RecordType::Generated;
let mut checked = true;
let mut expect_comma = false;
while !input.is_empty() {
if expect_comma {
let _ = input.parse::<syn::token::Comma>()?;
}
let key: Ident = input.parse()?;
let _ = input.parse::<syn::token::Eq>()?;
if key == "source" {
let span = input.span();
let query_str = Punctuated::<LitStr, Token![+]>::parse_separated_nonempty(input)?
.iter()
.map(LitStr::value)
.collect();
query_src = Some((QuerySrc::String(query_str), span));
} else if key == "source_file" {
let lit_str = input.parse::<LitStr>()?;
query_src = Some((QuerySrc::File(lit_str.value()), lit_str.span()));
} else if key == "args" {
let exprs = input.parse::<ExprArray>()?;
args = Some(exprs.elems.into_iter().collect())
} else if key == "record" {
record_type = RecordType::Given(input.parse()?);
} else if key == "checked" {
let lit_bool = input.parse::<LitBool>()?;
checked = lit_bool.value;
} else {
let message = format!("unexpected input key: {}", key);
return Err(syn::Error::new_spanned(key, message));
}
expect_comma = true;
}
let (src, src_span) =
query_src.ok_or_else(|| input.error("expected `source` or `source_file` key"))?;
let arg_exprs = args.unwrap_or_default();
Ok(QueryMacroInput {
src: src.resolve(src_span)?,
src_span,
record_type,
arg_exprs,
checked,
})
}
}
impl QuerySrc {
/// If the query source is a file, read it to a string. Otherwise return the query string.
fn resolve(self, source_span: Span) -> syn::Result<String> {
match self {
QuerySrc::String(string) => Ok(string),
QuerySrc::File(file) => read_file_src(&file, source_span),
}
}
}
fn read_file_src(source: &str, source_span: Span) -> syn::Result<String> {
let file_path = crate::common::resolve_path(source, source_span)?;
fs::read_to_string(&file_path).map_err(|e| {
syn::Error::new(
source_span,
format!(
"failed to read query file at {}: {}",
file_path.display(),
e
),
)
})
}