orm 0.2.0

A ORM framework written in Rust, unfinished yet
use rustc_serialize;

use meta::*;

static TPL: &'static str = r#"
use orm;
use orm::Entity;
use std;

static mut ORM_META: Option<&'static orm::meta::OrmMeta> = None;
static ONCE: std::sync::Once = std::sync::ONCE_INIT;

pub fn orm_meta() -> &'static orm::meta::OrmMeta {
    let json = r#${JSON}#;
    ONCE.call_once(|| unsafe { ORM_META = Some(orm::init::init_meta(json)) });
    unsafe { ORM_META.unwrap() }
}

${ENTITIES}
"#;

static TPL_STRUCT: &'static str = r#"
#[derive(Debug, Clone)]
pub struct ${ENTITY_NAME} {
    inner: orm::EntityInnerPointer,
}
"#;

static TPL_IMPL: &'static str = r#"
impl ${ENTITY_NAME} {${IMPL_FIELDS}
}
"#;

static TPL_IMPL_VALUE: &'static str = r#"
    #[allow(dead_code)]
    pub fn get_${FIELD}(&self) -> ${TYPE} {
        self.inner_get_value::<${TYPE}>("${FIELD}")
    }
    #[allow(dead_code)]
    pub fn set_${FIELD}(&mut self, value: ${SET_TYPE}) {
        self.inner_set_value("${FIELD}", value);
    }
    #[allow(dead_code)]
    pub fn set_${FIELD}_null(&self) {
        self.inner_set_value_null("${FIELD}")
    }
    #[allow(dead_code)]
    pub fn is_${FIELD}_null(&self) -> bool {
        self.inner_is_value_null("${FIELD}")
    }"#;

static TPL_IMPL_ENTITY: &'static str = r#"
    #[allow(dead_code)]
    pub fn get_${FIELD}(&self) -> Box<${TYPE}> {
        Box::new(self.inner_get_entity("${FIELD}"))
    }
    #[allow(dead_code)]
    pub fn set_${FIELD}(&mut self, value: ${SET_TYPE}) {
        self.inner_set_entity("${FIELD}", value);
    }
    #[allow(dead_code)]
    pub fn set_${FIELD}_null(&self) {
        self.inner_set_entity_null("${FIELD}")
    }
    #[allow(dead_code)]
    pub fn is_${FIELD}_null(&self) -> bool {
        self.inner_is_entity_null("${FIELD}")
    }"#;

static TPL_IMPL_VEC: &'static str = r#"
    #[allow(dead_code)]
    pub fn get_${FIELD}(&self) -> Box<Vec<${TYPE}>> {
        Box::new(self.inner_get_vec("${FIELD}"))
    }
    #[allow(dead_code)]
    pub fn set_${FIELD}(&mut self, value: Vec<${TYPE}>) {
        self.inner_set_vec("${FIELD}", value);
    }
    #[allow(dead_code)]
    pub fn is_${FIELD}_null(&self) -> bool {
        self.inner_is_vec_null("${FIELD}")
    }"#;

static TPL_TRAIT: &'static str = r#"
impl orm::Entity for ${ENTITY_NAME} {
    fn orm_meta() -> &'static orm::meta::OrmMeta {
        orm_meta()
    }
    fn meta() -> &'static orm::meta::EntityMeta {
        orm_meta().entity_map.get("${ENTITY_NAME}").unwrap()
    }
    fn default() -> Self {
        ${ENTITY_NAME} {
            inner: std::rc::Rc::new(std::cell::RefCell::new(orm::EntityInner::default(Self::meta(), Self::orm_meta())))
        }
    }
    fn new() -> Self {
        ${ENTITY_NAME} {
            inner: std::rc::Rc::new(std::cell::RefCell::new(orm::EntityInner::new(Self::meta(), Self::orm_meta())))
        }
    }
    fn from_inner(inner: orm::EntityInnerPointer) -> ${ENTITY_NAME} {
        ${ENTITY_NAME} {
            inner: inner,
        }
    }
    fn inner(&self) -> orm::EntityInnerPointer {
        self.inner.clone()
    }
}
"#;

pub fn format_meta(meta: &OrmMeta) -> String {
    let json = format!("\"{}\"", rustc_serialize::json::encode(&meta).unwrap());
    let entities = meta.get_entities()
        .into_iter()
        .map(format_entity)
        .collect::<Vec<_>>()
        .join("");
    let tpl = TPL.to_string();
    tpl.replace("${JSON}", &json).replace("${ENTITIES}", &entities)
}
fn format_entity(meta: &EntityMeta) -> String {
    let entity = format_entity_define(meta);
    let implt = format_entity_impl(meta);
    let treit = format_entity_trait(meta);
    format!("{}{}{}", entity, implt, treit)
}
fn format_entity_define(meta: &EntityMeta) -> String {
    TPL_STRUCT.to_string()
        .replace("${ENTITY_NAME}", &meta.entity_name)
}
fn format_entity_impl(meta: &EntityMeta) -> String {
    let fields = meta.field_vec
        .iter()
        .map(|field| {
            let field_meta = meta.field_map.get(field).expect(&expect!());
            format_entity_field(field_meta)
        })
        .collect::<Vec<_>>()
        .join("\n");
    TPL_IMPL.to_string()
        .replace("${ENTITY_NAME}", &meta.entity_name)
        .replace("${IMPL_FIELDS}", &fields)
}
fn format_entity_field(meta: &FieldMeta) -> String {
    let tpl = match meta {
        &FieldMeta::Id { .. } |
        &FieldMeta::String { .. } |
        &FieldMeta::Integer { .. } => TPL_IMPL_VALUE,
        &FieldMeta::Refer { .. } |
        &FieldMeta::Pointer { .. } |
        &FieldMeta::OneToOne { .. } => TPL_IMPL_ENTITY,
        &FieldMeta::OneToMany { .. } => TPL_IMPL_VEC,
    };
    tpl.to_string()
        .replace("${FIELD}", &meta.get_field_name())
        .replace("${TYPE}", &meta.get_type_name())
        .replace("${SET_TYPE}", &meta.get_type_name_set())
}
fn format_entity_trait(meta: &EntityMeta) -> String {
    TPL_TRAIT.to_string()
        .replace("${ENTITY_NAME}", &meta.entity_name)
}