extern crate serde_json;
use std::rc::Rc;
use crate::json::{Table, Field};
use std::collections::HashMap;
use syn::__private::TokenStream2;
use iso8601;
#[derive(Debug)]
pub enum Expression {
Query(QueryType, Option<syn::Ident>, Vec<Expression>, Box<Select>),
Binary(String, Box<Expression>, Box<Expression>),
Cond(Box<Expression>, Box<Expression>, Box<Expression>),
Lit(syn::Lit),
Ident(syn::Ident),
Var(String, String),
Range(syn::ExprRange),
Expr(Box<Expression>),
Call(syn::Ident, Vec<Expression>),
Func(syn::Ident, Box<Expression>),
ParamValue(String),
Program(Vec<Expression>),
Params(Vec<Expression>),
OperOne(String, Box<Expression>),
Attr(syn::Ident, Box<Expression>),
}
impl Expression {
pub fn to_oper_one(self) -> (String, Expression) {
match self {
Expression::OperOne(oper, exp) => (oper, *exp),
_ => panic!("只有临时操作才能转")
}
}
pub fn to_attr(self) -> (syn::Ident, Box<Expression>) {
match self {
Expression::Attr(ident, exp) => (ident, exp),
_ => panic!("只有属性才能转")
}
}
}
#[derive(Debug, Clone)]
pub enum QueryType {
Database,
Var,
Sub,
}
#[derive(Debug)]
pub enum Select {
Selects(bool, Vec<(syn::Ident, Expression)>),
Agg(syn::Ident, Option<Expression>),
Field(syn::Ident)
}
impl Select {
fn is_total(&self) -> bool {
match &self {
Select::Selects(is_total, _exps) => *is_total,
_ => false
}
}
fn is_selects(&self) -> bool {
match &self {
Select::Selects(_, exps) => !exps.is_empty(),
_ => false
}
}
fn selects(&self) -> Result<&Vec<(syn::Ident, Expression)>, String> {
match &self {
Select::Selects(_, exps) => Ok(&exps),
_ => Err(format!("必须是一般选择内容, {:?}", &self))
}
}
}
#[derive(Debug)]
pub enum Type<'a> {
Double,
Int,
Bool,
String,
Datetime,
Unknown,
Json(&'a Table),
None,
}
impl<'a> Type<'a> {
fn has_borrow(&self) -> TokenStream2 {
if let Type::String = self {
quote! {&}
} else {
quote! {}
}
}
fn default(&self) -> TokenStream2 {
match self {
Type::Double => quote! {0.0},
Type::Int => quote! {0},
Type::Bool => quote! {false},
Type::String => quote! {""},
Type::Datetime => quote! {0},
_ => panic!("无法得到默认值:{:?}", self),
}
}
}
pub fn to_exp<'a>(exp: &Expression,
del: &mut HashMap<String, Rc<Type<'a>>>,
json: Option<&Table>, config: &'a HashMap<String, Table>
) -> (TokenStream2, Rc<Type<'a>>, Vec<TokenStream2>) {
match exp {
Expression::Program(exps) => {
let mut nulls = Vec::new();
let gen: TokenStream2 = exps.iter().map(|v| {
let (one_exp, _, mut null) = to_exp(v, del, json, config);
nulls.append(&mut null);
one_exp
}).collect();
(gen, Rc::new(Type::Unknown), nulls)
},
Expression::Func(name, exp) => {
let (one_exp, ty, nulls) = to_exp(exp, del, json, config);
let gen = quote! {
let #name = #one_exp;
};
del.insert(name.to_string(), Rc::clone(&ty));
(gen, Rc::new(Type::None), nulls)
},
Expression::Query(q_type, name, cond, selects) => {
to_query(q_type, name, cond, selects.as_ref(), del, json, config)
},
Expression::Lit(lit) => {
let gen = match lit {
syn::Lit::Str(lit_str) => {
let str = lit_str.value();
if is_datetime(&str) {
quote! { LocalDateTime::from_str(#str).expect("日志格式错误") }
} else {
quote! { #lit }
}
},
_ => quote! { #lit }
};
let ty = match lit {
syn::Lit::Str(_) => Type::String,
syn::Lit::Int(_) => Type::Int,
syn::Lit::Float(_) => Type::Double,
syn::Lit::Bool(_) => Type::Bool,
_ => panic!("不识别的常量, {:?}", lit)
};
(gen, Rc::new(ty), Vec::new())
},
Expression::Ident(ident) => {
(quote! { #ident }, Rc::new(Type::Unknown), Vec::new())
},
Expression::Binary(op, left, right) => {
let (left, ty, mut l_nulls) = to_exp(&left, del, json, config);
let (right, _, mut r_nulls) = to_exp(&right, del, json, config);
let op = to_oper(&op);
let mut nulls = Vec::new();
nulls.append(&mut l_nulls);
nulls.append(&mut r_nulls);
(quote! { #left #op #right }, ty, nulls)
},
Expression::Cond(if_cond, if_exp, else_exp) => {
let (if_cond, ty, mut cond_null) = to_exp(&if_cond, del, json, config);
let (if_exp, _, mut if_null) = to_exp(&if_exp, del, json, config);
let (else_exp, _, mut else_null) = to_exp(&else_exp, del, json, config);
let gen = quote! {
if #if_cond { #if_exp } else { #else_exp }
};
let mut nulls = Vec::new();
nulls.append(&mut cond_null);
nulls.append(&mut if_null);
nulls.append(&mut else_null);
(gen, ty, nulls)
},
Expression::Expr(exp) => {
let (result, ty, nulls) = to_exp(&exp, del, json, config);
(quote! { (#result) }, ty, nulls)
},
Expression::Call(ident, params) => {
let mut nulls = Vec::new();
let (rel_params, _) = params.iter().fold( (quote!{}, 0), |(acc, i), v| {
let (value, _, mut null) = to_exp(&v, del, json, config);
nulls.append(&mut null);
if i == 0 {
(quote! { #value }, i + 1)
} else {
(quote! { #acc, #value }, i + 1)
}
});
(quote! { #ident(#rel_params) }, Rc::new(Type::Unknown), nulls)
},
Expression::ParamValue(name_str) => {
let name: syn::Ident = syn::parse_str(name_str).expect("变量名不合法");
let p_name: syn::Ident = syn::parse_str(&format!("p_{}", name_str)).expect("变量名不合法");
if name_str.starts_with("s_") {
(quote! { #name }, Rc::new(Type::Unknown), Vec::new())
} else {
(quote! { #p_name }, Rc::new(Type::Unknown), Vec::new())
}
},
Expression::Var(name_str, ty) => {
let s_name: syn::Ident = syn::parse_str(&format!("s_{}", name_str)).expect("变量名不合法");
let p_name: syn::Ident = syn::parse_str(&format!("p_{}", name_str)).expect("变量名不合法");
let s_value = quote! {
params[#name_str].as_str().expect(&format!("参数不存在, {}, {:?}", #name_str, params))
};
let value = get_value(&s_name, ty);
let gen = quote! {
let #s_name = #s_value;
let #p_name = #value;
};
(gen, Rc::new(Type::None), Vec::new())
},
Expression::Params(exps) => {
let mut nulls = Vec::new();
let gen = exps.iter().fold(quote!{}, |acc, x| {
let (one_gen, _, mut null) = to_exp(x, del, json, config);
nulls.append(&mut null);
quote! { #acc #one_gen }
});
(gen, Rc::new(Type::None), nulls)
},
Expression::Range(_) => {
let err = format!("quey查询中的表达式不可能出现这个语法结构, {:?}", exp);
panic!("{}", err)
},
Expression::OperOne(_, _) | Expression::Attr(_, _) => panic!("None不能在表达式中出现"),
}
}
fn to_query<'a>(q_type: &QueryType, name: &Option<syn::Ident>, cond: &Vec<Expression>, selects: &Select,
del: &mut HashMap<String, Rc<Type<'a>>>,
table_op: Option<&Table>, config: &'a HashMap<String, Table>
) -> (TokenStream2, Rc<Type<'a>>, Vec<TokenStream2>) {
let (name_gen, name_iter) = to_name(q_type, name);
if selects.is_total() {
let ty = get_type(table_op, &name.as_ref().expect("聚集查询有空值").to_string(), config, del, q_type);
let filter_exp = if let Type::Json(ref json) = *ty {
to_conds(&cond, del, json, config)
} else {
quote!{}
};
let select_exp = if let Type::Json(ref json) = *ty {
to_agg_selects(&selects.selects().expect("必须是一般选择内容"), del, json, config)
} else {
panic!("取聚集值必须有表")
};
let has_iter = if let QueryType::Var = q_type {
quote! {}
} else if name_iter {
quote! {.iter()}
} else {
quote! {}
};
let gen = quote! {
let x = #name_gen#has_iter#filter_exp;
#select_exp
select(vec![result])
};
(gen, Rc::new(Type::Unknown), Vec::new())
}
else if let Some(name) = name {
let ty = get_type(table_op, &name.to_string(), config, del, q_type);
let filter_exp = if let Type::Json(ref json) = *ty {
to_conds(&cond, del, json, config)
} else {
quote!{}
};
let (select_exp, has_agg, proc_null, select_type) = if let Type::Json(ref json) = *ty {
to_select(q_type, &selects, del, json, config)
} else {
(quote!{}, false, false, Rc::new(Type::Unknown))
};
let has_iter = if let QueryType::Var = q_type {
quote! {}
}
else if (!cond.is_empty() || has_agg) && name_iter {
quote! { .iter() }
} else {
quote! {}
};
let mut nulls = Vec::new();
let mut gen = if proc_null {
nulls.push(quote! { x.#name });
let default_gen = select_type.default();
let has_borrow = select_type.has_borrow();
quote! {
(match &#name_gen {
Some(x) => #has_borrow x#has_iter#filter_exp#select_exp,
None => #default_gen,
})
}
} else {
quote! { #name_gen#has_iter#filter_exp#select_exp }
};
if selects.is_selects() {
gen = quote! { select(#gen.collect()) };
}
(gen, ty, nulls)
}
else {
let table = table_op.expect("聚集函数必须有上层table");
let (select_exp, _has_agg, _proc_null, _) = to_select(q_type, &selects, del, &table, config);
(quote! { x#select_exp }, Rc::new(Type::Unknown), Vec::new())
}
}
fn to_name(q_type: &QueryType, name: &Option<syn::Ident>) -> (TokenStream2, bool) {
match q_type {
QueryType::Database => (quote! {DATABASE.#name.data.values()}, false),
QueryType::Var => (quote! {#name}, true),
QueryType::Sub => (quote! {x.#name}, true),
}
}
fn to_conds<'a>(exps: &Vec<Expression>,
del: &mut HashMap<String, Rc<Type<'a>>>,
json: &Table, config: &'a HashMap<String, Table>
) -> TokenStream2 {
exps.iter().map(|exp| {
match exp {
Expression::Range(range) => {
let (start_gen, start_num) = match &range.from {
Some(start) => (quote! { .skip(#start) }, quote! { #start }),
None => (quote! {}, quote! { 0 })
};
let end_gen = match &range.to {
Some(end) => quote! { .take(#end - #start_num) },
None => quote! {}
};
quote! { #start_gen#end_gen }
},
_ => {
let (exp_gen, _, _nulls) = to_exp(&exp, del, Some(json), config);
quote! { .filter(|x| {#exp_gen}) }
}
}
}).collect::<TokenStream2>()
}
fn to_select<'a>(q_type: &QueryType, select: &Select,
del: &mut HashMap<String, Rc<Type<'a>>>,
json: &Table, config: &'a HashMap<String, Table>
) -> (TokenStream2, bool, bool, Rc<Type<'a>>) {
match select {
Select::Agg(agg, exp) => {
(to_agg_select(&exp, &agg, del, json, config), true, false, Rc::new(Type::None))
},
Select::Selects(_is_total, exps) => {
if exps.is_empty() {
(quote! {}, false, false, Rc::new(Type::None))
} else {
let select = to_selects(&exps, del, json, config);
(quote! { .map(|x| {#select}) }, true, false, Rc::new(Type::None))
}
},
Select::Field(field_name) => {
let ty = get_type(Some(json), &field_name.to_string(), config, del, q_type);
(quote! { .#field_name }, false, true, ty)
}
}
}
fn to_agg_selects<'a>(exps: &Vec<(syn::Ident, Expression)>,
del: &mut HashMap<String, Rc::<Type<'a>>>,
json: &Table, config: &'a HashMap<String, Table>
) -> TokenStream2 {
let gen: TokenStream2 = exps.iter().map(|(name, exp)| {
let name_str = format!("\"{}\"", name.to_string());
let (one_exp, _, _nulls) = to_exp(&exp, del, Some(json), config);
let init = quote! {
format!("{:?}", #one_exp)
};
quote! {
result.push((#name_str, #init));
}
}).collect();
quote! {
let mut result: Vec<(&str, String)> = Vec::new();
#gen
}
}
fn to_selects<'a>(exps: &Vec<(syn::Ident, Expression)>,
del: &mut HashMap<String, Rc::<Type<'a>>>,
json: &Table, config: &'a HashMap<String, Table>
) -> TokenStream2 {
let gen = exps.iter().map(|(name, exp)| {
let name_str = format!("\"{}\"", name.to_string());
let (one_exp, _, nulls) = to_exp(&exp, del, Some(json), config);
let init = quote! { format!("{:?}", #one_exp) };
let one_exp = to_nulls(&nulls, init);
quote! {
result.push((#name_str, #one_exp));
}
}).collect::<TokenStream2>();
quote! {
let mut result: Vec<(&str, String)> = Vec::new();
#gen
result
}
}
fn to_nulls(nulls: &Vec<TokenStream2>, init: TokenStream2) -> TokenStream2 {
nulls.iter().fold(init, |acc, x| {
quote! {
match #x {
None => "null".to_string(),
Some(_) => #acc
}
}
})
}
fn to_agg_select<'a>(exp: &Option<Expression>, agg: &syn::Ident,
del: &mut HashMap<String, Rc<Type<'a>>>,
json: &Table, config: &'a HashMap<String, Table>
) -> TokenStream2 {
let (select, ty) = match exp {
Some(e) => {
let (first, ty, _nulls) = to_exp(&e, del, Some(json), config);
(quote! { .map(|x| #first) }, ty)
},
None => (quote! {}, Rc::new(Type::None))
};
let type_gen = match *ty {
Type::Double => {
match agg{
_ if agg.to_string() == "max" => quote! {max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default },
_ if agg.to_string() == "min" => quote! {min_by(|a, b| a.partial_cmp(b).unwrap()).unwrap_or_default },
_ => quote! { #agg::<f64> },
}
}
Type::Int => {
match agg {
_ if agg.to_string() == "max" => quote! { #agg().unwrap_or_default },
_ if agg.to_string() == "min" => quote! { #agg().unwrap_or_default },
_ => quote! { #agg::<i32> },
}
},
Type::None => quote! {#agg},
_ => panic!("表达式类型错误:{:?}", ty),
};
let result = quote! { #select.#type_gen() };
result
}
fn to_oper(str: &str) -> TokenStream2 {
match str {
"+" => quote!{ + },
"-" => quote!{ - },
"*" => quote!{ * },
"/" => quote!{ / },
"%" => quote!{ % },
">" => quote!{ > },
">=" => quote!{ >= },
"<" => quote!{ < },
"<=" => quote!{ <= },
"==" => quote!{ == },
"!=" => quote!{ != },
"&&" => quote!{ && },
"||" => quote!{ || },
"!" => quote!{ ! },
_ => panic!("暂时不能转, {}", str)
}
}
fn get_value(s_name: &syn::Ident, ty: &str) -> TokenStream2 {
if ty == "string" {
quote! { #s_name.to_string() }
} else if ty == "int" {
quote! { i32::from_str_radix(&#s_name, 10).expect("必须是整数") }
} else if ty == "datetime" {
quote! { datetime(&#s_name) }
} else if ty == "double" {
quote! { f64::from_str(&#s_name) }
} else {
panic!("类型不正确,{}", ty)
}
}
fn get_type<'a>(table_op: Option<&Table>, name: &str, config: &'a HashMap<String, Table>,
del: &HashMap<String, Rc<Type<'a>>>, q_type: &QueryType
) -> Rc<Type<'a>> {
match q_type {
QueryType::Database => Rc::new(Type::Json(&config.get(name).expect(&format!("没有找到全局表的定义, {}", name)))),
QueryType::Sub => {
let ty = &table_op.expect("找不到表").fields.get(name).expect(&format!("没有找到字段, {}", name));
match ty {
Field::Int => Rc::new(Type::Int),
Field::String => Rc::new(Type::String),
Field::Double => Rc::new(Type::Double),
Field::Datetime => Rc::new(Type::Datetime),
Field::OneToOne(entity, _) | Field::OneToMany(entity, _) | Field::ManyToOne(entity, _) => {
let table_str = entity.to_string();
Rc::new(Type::Json(&config.get(&table_str).expect(&format!("没有找到表的定义, {}", table_str))))
}
}
},
QueryType::Var => Rc::clone(del.get(name).expect(&format!("为定义的变量, {}", name))),
}
}
fn is_datetime(str: &str) -> bool {
match iso8601::datetime(str) {
Ok(_) => true,
Err(_) => false,
}
}