#![allow(unused_variables)] use criterion::{criterion_group, criterion_main, Criterion}; use tina::{ indexmap::IndexMap, serde_json::{Number, Value}, tina::{ core::service::dict::IDictService, data::AppResult, excel::{IExcelRow, IExcelSheet}, file::FileData, server::{ application::{AppConfig, Application, FromApplication}, session::Session, }, util::excel::ExcelUtil, }, }; #[macro_use] extern crate tina; #[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Debug)] #[serde(crate = "tina::serde")] struct RowData { name: Option, age: Option, status: Option, up: Option, } impl RowData { fn new(name: impl Into, age: i32, status: impl Into, up: bool) -> Self { Self { name: Some(name.into()), age: Some(age), status: Some(status.into()), up: Some(up), } } } #[async_trait] impl IExcelSheet for RowData { /// 获取 Sheet 名称 async fn get_sheet_name(&self, session: &Session) -> AppResult { Ok("测试".to_string()) } } #[async_trait] impl IExcelRow for RowData { /// 获取 Sheet列 与 属性的 映射 async fn get_field_column_mapping(&self, session: &Session) -> AppResult> { Ok(vec![("name", "姓名"), ("age", "年龄"), ("status", "状态"), ("up", "标志")] .into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) .collect()) } /// 获取 Sheet列 的 字典映射 async fn get_field_dict(&self, session: &Session) -> AppResult> { Ok(vec![("status", "status_dict")].into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()) } /// 获取 Sheet列 的 枚举映射 async fn get_field_enum_mapping(&self, session: &Session) -> AppResult>> { Ok(vec![("up", vec![("true", "是"), ("false", "否")])] .into_iter() .map(|(k, v)| { (k.to_string(), v.into_iter().map(|(k1, v1)| (k1.to_string(), v1.to_string())).collect::>()) }) .collect()) } /// 获取 Sheet 数据 async fn get_field_datas(&self, session: &Session) -> AppResult> { Ok(vec![ ("name", self.name.as_ref().map(|v| Value::String(v.to_string())).unwrap_or(Value::Null)), ("age", self.age.map(|v| Value::Number(Number::from(v))).unwrap_or(Value::Null)), ("status", self.status.as_ref().map(|v| Value::String(v.to_string())).unwrap_or(Value::Null)), ("up", self.up.map(Value::Bool).unwrap_or(Value::Null)), ] .into_iter() .map(|(k, v)| (k.to_string(), v)) .collect()) } } struct TestDictService; #[async_trait] impl IDictService for TestDictService { /// 根据字典类型查询字典数据 async fn get_dict_data_mapping_by_keys( &self, session: &Session, dict_type: &str, dict_keys: &[&str], ) -> AppResult> { self.get_dict_data_mapping_by_types(session, vec![dict_type].as_slice()) .await .map(|v| v.into_iter().next().map(|v1| v1.1).unwrap_or_default()) } /// 根据字典类型查询字典数据 async fn get_dict_data_mapping_by_types( &self, session: &Session, dict_types: &[&str], ) -> AppResult>> { Ok(dict_types .iter() .map(|&dict_type| match dict_type { "status_dict" => ( dict_type.to_string(), vec![("0", "正常"), ("1", "禁用")] .into_iter() .map(|(k, v)| (k.to_string(), v.to_string())) .collect::>(), ), _ => (dict_type.to_string(), IndexMap::default()), }) .collect()) } } fn bench_small_data_export_import(c: &mut Criterion) { let rt = tina::tokio::runtime::Builder::new_current_thread().enable_all().build().expect("build runtime failed"); let mut config = AppConfig::default(); config.set_dict_service(TestDictService); let application = Application::from(config); let session = Session::from_application(application, false).expect("build session failed"); c.bench_function("bench_small_data_export_import", |b| { b.iter(|| { rt.block_on(async { { let data = vec![ RowData::new("张三", 20, "0", true), RowData::new("李四", 12, "1", false), RowData::new("王五", 18, "2", true), ]; let mut data1 = data.clone(); data1.reverse(); let file = ExcelUtil::write_excel(&session, "", false, move || { let d = data1.pop(); async move { Ok(d) as AppResult> } }) .await?; let data2 = ExcelUtil::import::(&session, FileData::from_local_file(file.store_path.as_str(), true)?).await?; assert_ne!(data, data2); } Ok(()) as AppResult<()> }) .expect("execute failed"); }) }); } fn bench_large_data_export_import(c: &mut Criterion) { let rt = tina::tokio::runtime::Builder::new_current_thread().enable_all().build().expect("build runtime failed"); let mut config = AppConfig::default(); config.set_dict_service(TestDictService); let application = Application::from(config); let session = Session::from_application(application, false).expect("build session failed"); c.bench_function("bench_large_data_export_import", |b| { b.iter(|| { rt.block_on(async { { let data = vec![RowData::new("张三", 20, "0", true); 10000]; let mut data1 = data.clone(); data1.reverse(); let file = ExcelUtil::write_excel(&session, "", false, move || { let d = data1.pop(); async move { Ok(d) as AppResult> } }) .await?; let data2 = ExcelUtil::import::(&session, FileData::from_local_file(file.store_path.as_str(), true)?).await?; assert_eq!(data, data2); } Ok(()) as AppResult<()> }) .expect("execute failed"); }) }); } criterion_group!(name = benches; config = Criterion::default().sample_size(10); targets = bench_small_data_export_import, bench_large_data_export_import); criterion_main!(benches);