Files
advotracker/frontend/examples/csv-test/main.rs
Ralf Zerres c3e939c6bb frontend: examples: introduce csv-test
* cli to test data import and export
  - import from a csv file
  - export to a csv file

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2020-07-12 14:14:47 +02:00

243 lines
7.9 KiB
Rust

/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::{Local, DateTime};
use locales::t;
use serde::Deserialize;
use std::env;
use std::{error::Error, process};
use tracing::{debug, trace, Level};
//use crate::db::data::CsvImportRecord;
// include modules
mod parse_args;
/// respect environment variables set in .env files
/// located in the current call directory
/// this is primarily used in testing scenarios (eg. debugging)
#[derive(Debug, Deserialize)]
struct Environment {
test_lang: String,
log: String,
}
#[derive(Debug, Deserialize)]
pub struct CsvImportRecord {
// dion => Allianz Dion: 1-9
// policy_code => Policy Typ: "AS"
// policy_number => Versicherungsscheinnummer: "1515735810"
pub dion: String,
pub policy_code: String,
pub policy_number: String,
}
#[derive(Default, Debug, Deserialize)]
pub struct RecordList {
records: Vec<CsvImportRecord>
}
/// export as csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
fn export(p: &mut String, lang: &String) -> Result<(), Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
//use std::ffi::OsStr;
let mut res = t!("csv_import.started", lang);
let mut state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
// Note: slash syntax also works on Windows!
let path = Path::new(p);
// only create files with a '.txt' extensions
//let extension = path.extension();
// match extension {
// //Some(String) => println!("file extension ok!"),
// //_ => extension = OsStr::new("txt")
// _ => println!("got file extension {:?}", extension)
// };
// open the file
let file = File::open(path)?;
trace!(target: "csv-export", extension = ?path.extension(), file = ?file);
state = t!("state.finished", lang);
res = t!("csv_import.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
Ok(())
}
/// import from csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
fn import(p: &mut String, lang: &String) -> Result<u32, Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
use std::ffi::OsStr;
let mut res = t!("csv_import.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test", process = ?res, state = ?state, date_start = ?dt_start.to_string());
// Note: slash syntax also workd on Windows!
let path = Path::new(p);
// must be a readable file
trace!(target: "csv-test", path = ?path);
assert_eq!(path.is_file(), true);
// only accept files with '.txt' extensions
let extension = path.extension();
assert_eq!(extension, Some(OsStr::new("txt")));
// open the file
let file = File::open(path)?;
trace!(target: "csv-test", extension = ?extension, file = ?file);
// Build the CSV reader and iterate over each record.
let mut csv_reader = csv::ReaderBuilder::new()
.has_headers(false)
.delimiter(b' ')
.comment(Some(b'#'))
//.has_headers(true)
//.from_reader(io::stdin());
//.from_path(path);
.from_reader(file);
{
// We nest this call in its own scope because of lifetimes.
let headers = csv_reader.headers()?;
trace!(target: "csv-test", header = ?headers);
}
//for result in csv_reader.records() {
let mut count = 0;
for result in csv_reader.deserialize() {
// The iterator yields Result<StringRecord, Error>, so we check the
// error here.
//let record = result?;
let _record: CsvImportRecord = result?;
//println!("{:?}", record);
count +=1;
}
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
println!("Duration: {:#?}", duration);
//let seconds = duration.secs;
//println!("Seconds: {:#?}", seconds);
trace!(target: "csv-test", record_count = ?count, duration = ?duration);
state = t!("state.finished", lang);
res = t!("csv_import.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state, date_stop = ?dt_end.to_string());
//Ok(count, duration.seconds())
Ok(count)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
use dotenv::dotenv;
use parse_args::parse_args;
//use std::process;
//use std::sync::Arc;
use tracing_subscriber::fmt;
use viperus::Viperus;
//static DEFAULT_FILTER: &str = concat!(module_path!(), "=", "trace");
// initialize the tracing subsystem
// a drop in replacement for classical logging
// reference: https://tokio.rs/blog/2019-08-tracing/
let span = tracing::span!(Level::TRACE, "csv-test");
let _enter = span.enter();
let subscriber = fmt::Subscriber::builder()
.with_env_filter("trace")
//.with_max_level(tracing::Level::DEBUG)
.finish();
// initialize logger
//env_logger::init();
//info!("Commencing the import Test-Run!");
tracing::subscriber::with_default(subscriber, || {
// get system environment
let mut lang = env::var("LANG").unwrap_or("en".to_string());
let mut res = t!("parse.environment", lang);
let mut state = t!("state.started", lang);
trace!(target: "csv-test", message = ?res, state = ?state);
//debug!(message = ?res, state = ?state);
trace!(target: "csv-test", environment = "system", lang = ?lang);
// testing environment: read from .env file
dotenv().ok();
match envy::from_env::<Environment>() {
Ok(environment) => {
if environment.test_lang != lang { lang = environment.test_lang; }
},
Err(e) => { debug!(target: "csv-test", "{}", e); }
}
// how to handle unumplemented lang resources??
res = t!("parse.environment", lang);
trace!(target: "csv-test", environment = "envy", lang = ?lang);
state = t!("state.finished", lang);
trace!(target: "csv-test", message = ?res, state = ?state);
// initialize viperus structure
let mut v = Viperus::new();
// parse commandline arguments
res = t!("parse.arguments", lang);
state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
let _ = parse_args(&mut v);
state = t!("state.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
//trace!(target: "Viperus", "Config results: {:?}", v);
// main tasks
res = t!("main.started", lang);
state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
// importing policy code elements from csv-file
let mut csv_import_path = v.get::<String>("import_file").unwrap();
match import(&mut csv_import_path, &lang) {
Ok(count) => {
println!("Imported {:?} records", count);
}
Err(err) => {
println!("error running Csv-Test: {}", err);
process::exit(1);
}
}
// export policy code elements to csv-file
let mut csv_export_path = v.get::<String>("export_file").unwrap();
match export(&mut csv_export_path, &lang) {
Ok(count) => {
println!("Exported {:?} records", count);
}
Err(err) => {
println!("error running CSV-Export: {}", err);
process::exit(1);
}
}
state = t!("state.finished", lang);
res = t!("main.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
});
Ok(())
}