use entity::Entity;
use entity::EntityInner;
use entity::EntityInnerPointer;
use value::FieldValue;
use meta::EntityMeta;
use meta::OrmMeta;
use mysql::prelude::GenericConnection;
use mysql::Error;
use mysql::Value;
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
pub struct Insert {
withs: Vec<(String, Insert)>,
}
impl Insert {
pub fn new() -> Self {
Insert { withs: Vec::new() }
}
pub fn with(&mut self, field: &str) -> &mut Insert {
let insert = Insert::new();
self.withs.push((field.to_string(), insert));
&mut self.withs.last_mut().unwrap().1
}
pub fn execute<C, E>(&self, conn: &mut C, entity: &E) -> Result<u64, Error>
where C: GenericConnection,
E: Entity
{
self.execute_inner(conn, entity.inner())
}
pub fn execute_inner<C>(&self, conn: &mut C, rc: EntityInnerPointer) -> Result<u64, Error>
where C: GenericConnection
{
if !rc.borrow().meta.is_id_auto() && !rc.borrow().is_value_null("id") {
panic!("Id Not Auto And Has No Value");
}
let r1 = try!(self.execute_pointer(conn, rc.clone()));
let r2 = try!(self.execute_self(conn, rc.clone()));
let r3 = try!(self.execute_one_one(conn, rc.clone()));
let r4 = try!(self.execute_one_many(conn, rc.clone()));
Ok(r1 + r2 + r3 + r4)
}
pub fn execute_pointer<C>(&self, conn: &mut C, rc: EntityInnerPointer) -> Result<u64, Error>
where C: GenericConnection
{
self.withs
.iter()
.filter_map(|&(ref field, ref ins)| {
if !rc.borrow().meta.field_map.get(field).unwrap().is_refer_pointer() {
return None;
}
rc.borrow()
.field_map
.get(field)
.map_or(None, |v| v.as_entity().map(|b_rc| (field, ins, b_rc)))
})
.fold(Ok(0), |acc, (field, ins, b_rc)| {
if acc.is_err() {
return acc;
}
let res = ins.execute_inner(conn, b_rc.clone());
if res.is_err() {
return res;
}
let (left, right) = rc.borrow().meta.field_map.get(field).unwrap().get_refer_lr();
let b_id = b_rc.borrow().field_map.get(&right).map(|v| v.clone());
if b_id.is_some() {
rc.borrow_mut().field_map.insert(left, b_id.unwrap());
}
let acc = acc.unwrap() + res.unwrap();
Ok(acc)
})
}
pub fn execute_one_one<C>(&self, conn: &mut C, rc: EntityInnerPointer) -> Result<u64, Error>
where C: GenericConnection
{
self.withs
.iter()
.filter_map(|&(ref field, ref ins)| {
if !rc.borrow().meta.field_map.get(field).unwrap().is_refer_one_one() {
return None;
}
rc.borrow()
.field_map
.get(field)
.map_or(None, |v| v.as_entity().map(|b_rc| (field, ins, b_rc)))
})
.fold(Ok(0), |acc, (field, ins, b_rc)| {
if acc.is_err() {
return acc;
}
let (left, right) = rc.borrow().meta.field_map.get(field).unwrap().get_refer_lr();
let a_id = rc.borrow().field_map.get(&left).map(|v| v.clone());
if a_id.is_some() {
b_rc.borrow_mut().field_map.insert(right, a_id.unwrap());
}
let res = ins.execute_inner(conn, b_rc.clone());
if res.is_err() {
return res;
}
let acc = acc.unwrap() + res.unwrap();
Ok(acc)
})
}
pub fn execute_one_many<C>(&self, conn: &mut C, rc: EntityInnerPointer) -> Result<u64, Error>
where C: GenericConnection
{
self.withs
.iter()
.filter_map(|&(ref field, ref ins)| {
if !rc.borrow().meta.field_map.get(field).unwrap().is_refer_one_many() {
return None;
}
rc.borrow()
.field_map
.get(field)
.map(|v| (field, ins, v.as_vec()))
})
.fold(Ok(0), |acc, (field, ins, vec)| {
if acc.is_err() {
return acc;
}
let (left, right) = rc.borrow().meta.field_map.get(field).unwrap().get_refer_lr();
let a_id = rc.borrow().field_map.get(&left).map(|v| v.clone());
if a_id.is_some() {
for b_rc in vec.iter() {
b_rc.borrow_mut()
.field_map
.insert(right.to_string(), a_id.clone().unwrap());
}
}
let res = vec.iter().fold(Ok(0), |acc, b_rc| {
if acc.is_err() {
return acc;
}
let res = ins.execute_inner(conn, b_rc.clone());
if res.is_err() {
return res;
}
Ok(acc.unwrap() + res.unwrap())
});
if res.is_err() {
return res;
}
Ok(acc.unwrap() + res.unwrap())
})
}
pub fn execute_self<C>(&self, conn: &mut C, rc: EntityInnerPointer) -> Result<u64, Error>
where C: GenericConnection
{
let table = rc.borrow().meta.table_name.clone();
let valid_fields = rc.borrow()
.meta
.field_vec
.iter()
.filter(|&field| {
let field_meta = rc.borrow().meta.field_map.get(field).unwrap();
if rc.borrow().meta.is_id_auto() && field_meta.is_type_id() {
return false;
}
rc.borrow().field_map.get(field).is_some() && !field_meta.is_type_refer()
})
.collect::<Vec<_>>();
let params = valid_fields.iter()
.map(|&field| {
(field.to_string(), rc.borrow().field_map.get(field).expect(&expect!()).as_value())
})
.collect::<Vec<_>>();
let fields = valid_fields.iter()
.map(|field| format!("`{}` = :{}", field, field))
.collect::<Vec<_>>()
.join(", ");
let sql = format!("INSERT INTO `{}` SET {}", table, fields);
log!("{}", sql);
log!("{:?}", params);
conn.prep_exec(sql, params).map(|res| {
if rc.borrow().meta.is_id_auto() {
rc.borrow_mut()
.field_map
.insert("id".to_string(),
FieldValue::from(Value::from(res.last_insert_id())));
}
res.affected_rows()
})
}
}