af_path 0.2.3

path查询语言库
Documentation
use syn::__private::TokenStream2;
use crate::json;
use crate::json::{Field};
use std::collections::HashMap;

/// 产生所有表的struct结构
/// @param map:全局配置
pub fn structs(map: &HashMap<String, json::Table>) -> TokenStream2 {
    // 产生所有表的数据结构
    map.iter().map(|(k, v)| {
        let name: syn::Ident = syn::parse_str(&k).expect(&format!("表名不是合法变量, {}", &k));
        // 得到表的字段定义及是否有生命周期指定
        let fields = create_fields_get(&v.fields, |field_name, ty| fields(field_name, ty));
        
        // 产生获取字段内容的过程
        let fields_get = create_fields_get(&v.fields, |field_name, ty| create_field_get(field_name, ty));
        // 产生获取测试字段内容过程
        let fields_test = create_fields_get(&v.fields, |field_name, ty| create_field_test(field_name, ty));
        // 产生clone时,获取字段的过程
        let fields_clone = create_fields_get(&v.fields, |field_name, ty| create_field_clone(field_name, ty));

        // 产生构造过程
        let record = create_fields_get(&v.fields, |field_name, _| create_record(field_name));
        // 产生copy属性的过程
        let copy = create_fields_get(&v.fields, |field_name, ty| create_copy(field_name, ty));

        // 实现部分也需要根据情况指定生命周期
        let key_name: syn::Ident = syn::parse_str(&v.key).expect("主键名不合法");
        let key_type = key_type(&v);

        let table_def = quote! {
            // 产生表结构
            #[derive(Debug)]
            pub struct #name { #fields }
            // 实现表结构的构造函数
            impl Entity<#key_type> for #name {
                // 实现构造函数
                fn new(row: &MssqlRow) -> Self {
                    // 产生获取字段的过程
                    #fields_get
                    //产生构造过程
                    #name{#record}
                }

                // 实现取key值的函数
                fn key(&self) -> #key_type {
                    self.#key_name
                }

                // 把数据插入到自己到表中
                fn put(self) -> ClosureType {
                    let update: ClosureType = Box::new(move || {
                        unsafe {DATABASE.#name.data.insert(self.#key_name, self)};
                    });
                    update
                }
            
                // 克隆出自己的主体部分,不含关系内容
                fn clone(&self) -> Self {
                    // 产生获取字段的过程
                    #fields_clone
                    //产生构造过程
                    #name{#record}
                }

                // 拷贝数据内容,忽略关系部分
                fn copy(key: &i32, other: Self) -> ClosureType {
                    let entity = unsafe {DATABASE.#name.data.get_mut(&key).expect("根据主键居然没找到数据")};
                    let update: ClosureType = Box::new(move || {
                        #copy
                    });
                    update
                }

                // 实现按测试数据构造
                fn new_test(value: &HashMap<String, Value>) -> Self {
                    // 产生获取测试字段过程
                    #fields_test
                    // 产生构造过程
                    #name{#record}
                }
            }
        };
        table_def
    }).collect()
}

// 得到主键类型定义
fn key_type(table: &json::Table) -> TokenStream2 {
    let key = &table.key;
    let field = &table.fields[key.as_str()];
    let result = field_type(&field);
    result
}

// 产生一个表的字段定义
// return:(语法结构,是否有生命周期指定),一对多关系及一对一关系都需要生命周期指定
fn fields(field_name: &str, field_attr: &Field) -> TokenStream2 {
    // 每一个表的key为列名,按列名进行循环
    // 返回:(rust代码,是否需要生命周期指定)
    let name: syn::Ident = syn::parse_str(&field_name).expect(&format!("字段名不是合法变量, {}", field_name));
    let ty = field_type(field_attr);
    quote! {
        pub #name: #ty,
    }
}

// 根据字段类型定义产生rust的数据类型
// return:(语法结构,是否有生命周期指定),一对多关系及一对一关系都需要生命周期指定
fn field_type(json: &Field) -> TokenStream2 {
    // 根据类型处理
    match json {
        Field::Int => quote! { i32 },
        Field::String => quote! { String },
        Field::Double => quote! { f64 },
        Field::Datetime => quote! { i32 },
        // 一对一关系或者多对一关系,产生对应实体引用,可以为空
        Field::OneToOne(entity, _) | Field::ManyToOne(entity, _) => {
            let name: syn::Ident = syn::parse_str(&entity).expect(&format!("entity名称不合法, {:?}", entity));
            quote! { Option<&'static #name> }
        },
        // 一对多关系,产生对应实体集合
        Field::OneToMany(entity, _) => {
            let name: syn::Ident = syn::parse_str(&entity).expect(&format!("entity名称不合法, {:?}", entity));
            quote! { Vec<&'static #name> }
        },
    }   
}

// 产生构造表记录的过程
// @param handler: 产生一个字段的过程,测试数据有自己的产生过程
fn create_fields_get<F>(fields: &HashMap<String, Field>, f: F) -> TokenStream2
where F: Fn(&str, &Field) -> TokenStream2 {
    // 每一个表的key为列名,按列名进行循环
    fields.iter().map(|(field_name, field_attr)| {                            
        f(&field_name, &field_attr)
    }).collect()
}

// 产生获取字段值的过程
// @param ty: 数据类型
// @param db_ty: 数据库中的字段类型,用于把数据库中的字符串类型转换成整形
fn create_field_get(field_name: &str, ty: &Field) -> TokenStream2 {
    let name: syn::Ident = syn::parse_str(&field_name).expect("名称转换错误");
    // 根据字段类型不同,产生不同的构造过程
    match ty {
        Field::Int | Field::Datetime => quote! {
            let #name: i32 = match row.try_get(#field_name) {
                // 失败,返回0
                Err(_) => 0,
                Ok(x) => x,
            };
        },
        Field::String => quote! {
            let #name: String = match row.try_get(#field_name) {
                // 失败,返回空串
                Err(_) => String::from(""),
                Ok(x) => x,
            };
        },
        Field::Double => quote! {
            let #name: f64 = match row.try_get(#field_name) {
                // 失败,返回0
                Err(_) => 0.0,
                Ok(x) => x,
            };
        },
        // 一对一或多对一关系,给空值
        Field::OneToOne(_, _) | Field::ManyToOne(_, _) => quote! {
            let #name = None;
        },
        // 一对多关系,构造空集合
        Field::OneToMany(_, _) => quote! {
            let #name = Vec::new();
        },
    }
}

// 产生测试数据字段值的过程
// @param ty: 数据类型
fn create_field_test(field_name: &str, ty: &Field) -> TokenStream2 {
    let name: syn::Ident = syn::parse_str(&field_name).expect("名称转换错误");
    // 根据字段类型不同,产生不同的构造过程
    match ty {
        Field::Int => quote! { let #name: i32 = value.get(#field_name).expect(&format!("test字段不存在, {}", #field_name)).as_int(); },
        Field::String => quote! { let #name: String = value.get(#field_name).expect(&format!("test字段不存在, {}", #field_name)).as_string(); },
        Field::Double => quote! {
            let #name: f64 = value.get(#field_name).expect(&format!("test字段不存在, {}", #field_name)).as_double();
        },
        Field::Datetime => quote! {
            // 把字符串转换成日期
            let #name = value.get(#field_name).expect(&format!("test字段不存在, {}", #field_name)).as_datetime();
        },
        // 一对一或一对多关系,给空值
        Field::OneToOne(_, _) | Field::ManyToOne(_, _) => quote! {
            let #name = None;
        },
        // 一对多关系,构造空集合
        Field::OneToMany(_, _) => quote! {
            let #name = Vec::new();
        },
    }
}

// 产生克隆时,获取字段值的过程
fn create_field_clone(field_name: &str, ty: &Field) -> TokenStream2 {
    let name: syn::Ident = syn::parse_str(&field_name).expect("名称转换错误");
    // 根据字段类型不同,产生不同的构造过程
    match ty {
        Field::Int | Field::Double | Field::Datetime => quote! { let #name = self.#name; },
        Field::String => quote! { let #name = self.#name.to_string(); },
        // 一对一或一对多关系,给空值
        Field::OneToOne(_, _) | Field::ManyToOne(_, _) => quote! {
            let #name = None;
        },
        // 一对多关系,构造空集合
        Field::OneToMany(_, _) => quote! {
            let #name = Vec::new();
        },
    }
}

// 产生构造记录的过程
fn create_record(field_name: &str) -> TokenStream2 {
    let name: syn::Ident = syn::parse_str(&field_name).expect(&format!("变量名不合法, {}", field_name));
    let field = quote! {#name:#name,};
    field
}

// 产生记录的拷贝过程
fn create_copy(field_name: &str, ty: &Field) -> TokenStream2 {
    let name: syn::Ident = syn::parse_str(&field_name).expect(&format!("变量名不合法, {}", field_name));
    // 根据字段类型不同,产生不同的构造过程
    match ty {
        Field::Int | Field::Double | Field::Datetime => quote! { entity.#name = other.#name; },
        Field::String => quote! { entity.#name = other.#name.to_string(); },
        // 一对多等关系,不用处理
        Field::OneToOne(_, _) | Field::OneToMany(_, _) | Field::ManyToOne(_, _) => quote! {},
    }
}