use syn::__private::TokenStream2;
use crate::json;
use crate::json::{Table, Field};
use std::collections::HashMap;
enum AssocialType {
OneToOne,
OneToMany,
ManyToOne,
}
pub fn tables(map: &HashMap<String, json::Table>) -> TokenStream2 {
let (gen, tables_gen, load_gen, _i) = map.iter().fold( (quote!{}, quote!{}, quote!{}, 0), |(acc_gen, acc_tables, acc_load, acc), (k, v)| {
let name: syn::Ident = syn::parse_str(&k).expect(&format!("数据库表名不是合法变量:{:?}", &k));
let key_type = get_key_type(&v);
let table_def = quote! {
pub #name: Table<#key_type, entity::#name>,
};
let gen = quote! {
#acc_gen #table_def
};
let table_gen = quote! {
#name:Table{data:BTreeMap::new()}
};
let tables_gen = match acc {
0 => quote! { #table_gen },
_ => quote! { #acc_tables, #table_gen },
};
let load_gen = quote! { #acc_load self.#name.load_data(db_time, #k, &json[#k], conn, &f).await?; };
(gen, tables_gen, load_gen, acc + 1)
});
let load_next_gen: TokenStream2 = map.iter().map(|(k, _v)| {
load_next(&k)
}).collect();
let clear_gen = clear_gen(map);
let create_relation_gen = create_relation(map, |k, slave_table, slave_key, field_key, _slave_id| {
create_one(k, slave_table, slave_key, field_key, AssocialType::OneToOne)
}, |k, slave_table, slave_key, field_key, _slave_id| {
create_one(k, slave_table, slave_key, field_key, AssocialType::OneToMany)
}, |k, slave_table, slave_key, field_key, _slave_id| {
create_one(k, slave_table, slave_key, field_key, AssocialType::ManyToOne)
});
let remove_relation_gen = create_relation(map, |k, slave_table, slave_key, field_key, slave_id| {
remove_one(k, slave_table, slave_key, field_key, slave_id, AssocialType::OneToOne)
}, |k, slave_table, slave_key, field_key, slave_id| {
remove_one(k, slave_table, slave_key, field_key, slave_id, AssocialType::OneToMany)
}, |k, slave_table, slave_key, field_key, slave_id| {
remove_one(k, slave_table, slave_key, field_key, slave_id, AssocialType::ManyToOne)
});
let create_next_gen = create_relation(map, |k, slave_table, slave_key, field_key, _slave_id| {
create_next(k, slave_table, slave_key, field_key, AssocialType::OneToOne)
}, |k, slave_table, slave_key, field_key, _slave_id| {
create_next(k, slave_table, slave_key, field_key, AssocialType::OneToMany)
}, |k, slave_table, slave_key, field_key, _slave_id| {
create_next(k, slave_table, slave_key, field_key, AssocialType::ManyToOne)
});
quote! {
pub struct DataBase { #gen }
pub static mut DATABASE: DataBase = DataBase{ #tables_gen };
impl DataBase {
pub async fn load<F>(&self, db_time: &Update, json: &HashMap<String, json::Table>, conn: &mut MssqlConnection, f: F) -> Result<(), sqlx::Error>
where F: Fn(ClosureType) {
#load_gen
Ok(())
}
pub async fn load_next<F>(db_time: &Update, json: &HashMap<String, json::Table>, conn: &mut MssqlConnection, f: F) -> Result<(), sqlx::Error>
where F: Fn(ClosureType) {
unsafe {
#load_next_gen
#remove_relation_gen
#create_next_gen
}
Ok(())
}
pub fn clear(&mut self) {
#clear_gen
}
pub fn create_relation<F>(f: F) where F: Fn(ClosureType) {
#create_relation_gen
}
}
}
}
fn clear_gen(map: &HashMap<String, json::Table>) -> TokenStream2 {
map.iter().fold(quote!{}, |acc, (table_name, _table)| {
let name: syn::Ident = syn::parse_str(&table_name).expect(&format!("数据库表名不是合法变量:{:?}", &table_name));
let gen = quote! {
self.#name.clear();
};
quote! { #acc #gen }
})
}
fn get_key_type(json: &Table) -> TokenStream2 {
let name = &json.key;
let key_type = &json.fields[&name.to_string()];
match key_type {
Field::Int => quote! { i32 },
Field::String => quote! { String },
_ => panic!("这种类型不能做主键,{:?}", key_type)
}
}
fn create_relation<FOne, FMany, FToOne>(map: &HashMap<String, json::Table>, f_one: FOne, f_many: FMany, f_to_one: FToOne) -> TokenStream2 where
FOne: Fn(&str, &str, &str, &str, &str) -> TokenStream2,
FMany: Fn(&str, &str, &str, &str, &str) -> TokenStream2,
FToOne: Fn(&str, &str, &str, &str, &str) -> TokenStream2 {
let result: TokenStream2 = map.iter().map(|(k, v)| {
let fields = &v.fields;
let result_in: TokenStream2 = fields.iter().map(|(field_key, field_attr)| {
match field_attr {
Field::OneToMany(slave_table, slave_key) => {
let slave_id = &map.get(slave_table).expect("从表不存在").key;
f_many(&k, &slave_table, &slave_key, &field_key, slave_id)
},
Field::OneToOne(slave_table, slave_key) => {
let slave_id = &map.get(slave_table).expect("从表不存在").key;
f_one(&k, &slave_table, &slave_key, &field_key, slave_id)
},
Field::ManyToOne(slave_table, slave_key) => {
let slave_id = &map.get(slave_table).expect("从表不存在").key;
f_to_one(&slave_table, &k, &slave_key, &field_key, slave_id)
}
Field::Int | Field::Double | Field::String | Field::Datetime => quote!{},
}
}).collect();
result_in
}).collect();
result
}
fn create_one(main_table: &str, slave_table: &str, slave_key_str: &str, main_field_str: &str, ty: AssocialType) -> TokenStream2 {
let main_name: syn::Ident = syn::parse_str(&main_table).expect(&format!("表名不是合法变量,{:?}", main_table));
let slave_name: syn::Ident = syn::parse_str(&slave_table).expect(&format!("表名不是合法变量,{:?}", slave_table));
let slave_key: syn::Ident = syn::parse_str(&slave_key_str).expect(&format!("外键不是合法变量,{:?}", slave_key_str));
let main_field: syn::Ident = syn::parse_str(&main_field_str).expect(&format!("主表字段不是合法变量,{:?}", main_field_str));
let create_statement = match ty {
AssocialType::OneToOne => quote! { v.#main_field = Some(&slave_v) },
AssocialType::OneToMany => quote! { v.#main_field.push(&slave_v) },
AssocialType::ManyToOne => quote! { slave_v.#main_field = Some(&v) },
};
let iter_gen = if let AssocialType::ManyToOne = ty {
quote! { iter_mut }
} else {
quote! { iter }
};
let get_gen = if let AssocialType::ManyToOne = ty {
quote! { get }
} else {
quote! { get_mut }
};
quote! {
for (_, slave_v) in unsafe{DATABASE.#slave_name.data.#iter_gen()} {
let t_main = unsafe{&mut DATABASE.#main_name.data};
if let Some(v) = t_main.#get_gen(&slave_v.#slave_key) {
let update: ClosureType = Box::new(move || {#create_statement;});
f(update);
}
}
}
}
fn create_next(main_table: &str, slave_table: &str, slave_key_str: &str, main_field_str: &str, ty: AssocialType) -> TokenStream2 {
let main_name: syn::Ident = syn::parse_str(&main_table).expect(&format!("表名不是合法变量,{:?}", main_table));
let slave_name: syn::Ident = syn::parse_str(&slave_table).expect(&format!("表名不是合法变量,{:?}", slave_table));
let slave_key: syn::Ident = syn::parse_str(&slave_key_str).expect(&format!("外键不是合法变量,{:?}", slave_key_str));
let main_field: syn::Ident = syn::parse_str(&main_field_str).expect(&format!("主表字段不是合法变量,{:?}", main_field_str));
let slave_keys: syn::Ident = syn::parse_str(&format!("{}_keys", slave_table)).expect(&format!("主表字段不是合法变量,{:?}", slave_table));
let create_statement = match ty {
AssocialType::OneToOne => quote! { v.#main_field = Some(&slave_v) },
AssocialType::OneToMany => quote! { v.#main_field.push(&slave_v) },
AssocialType::ManyToOne => quote! {
},
};
quote! {
for slave_id in &#slave_keys {
let slave_v = unsafe{DATABASE.#slave_name.data.get(&slave_id).unwrap()};
let t_main = unsafe{&mut DATABASE.#main_name.data};
if let Some(v) = t_main.get_mut(&slave_v.#slave_key) {
let update: ClosureType = Box::new(move || {#create_statement;});
f(update);
}
}
}
}
fn remove_one(main_table: &str, slave_table: &str, slave_key_str: &str, main_field_str: &str, slave_id_str: &str, ty: AssocialType) -> TokenStream2 {
let main_name: syn::Ident = syn::parse_str(&main_table).expect(&format!("表名不是合法变量,{:?}", main_table));
let slave_key: syn::Ident = syn::parse_str(&slave_key_str).expect(&format!("外键不是合法变量,{:?}", slave_key_str));
let slave_id: syn::Ident = syn::parse_str(&slave_id_str).expect(&format!("外键不是合法变量,{:?}", slave_id_str));
let main_field: syn::Ident = syn::parse_str(&main_field_str).expect(&format!("主表字段不是合法变量,{:?}", main_field_str));
let slave_entity: syn::Ident = syn::parse_str(&format!("{}_entity", slave_table)).expect(&format!("主表字段不是合法变量,{:?}", slave_table));
let create_statement = match ty {
AssocialType::OneToOne => quote! {
let update: ClosureType = Box::new(move || {v.#main_field = None;});
f(update);
},
AssocialType::OneToMany => quote! {
if let Some(pos) = v.#main_field.iter().position(|x| x.#slave_id == slave_v.#slave_id) {
let update: ClosureType = Box::new(move || {v.#main_field.remove(pos);});
f(update);
}
},
AssocialType::ManyToOne => quote! {
let update: ClosureType = Box::new(move || {
});
f(update);
}
};
quote! {
for slave_v in &#slave_entity {
let t_main = unsafe{&mut DATABASE.#main_name.data};
if let Some(v) = t_main.get_mut(&slave_v.#slave_key) {
#create_statement
}
}
}
}
fn load_next(k: &str) -> TokenStream2 {
let name: syn::Ident = syn::parse_str(k).expect(&format!("数据库表名不是合法变量:{:?}", k));
let key_name: syn::Ident = syn::parse_str(&format!("{}_keys", k)).expect(&format!("数据库表名不是合法变量:{:?}", k));
let entity_name: syn::Ident = syn::parse_str(&format!("{}_entity", k)).expect(&format!("数据库表名不是合法变量:{:?}", k));
quote! {
let mut #key_name = Vec::new();
let mut #entity_name = Vec::new();
DATABASE.#name.load_next(db_time, #k, &json[#k], conn, |x, key, entity_op| {
f(x);
#key_name.push(key);
if let Some(entity) = entity_op {
#entity_name.push(entity);
}
}).await?;
}
}