use chrono::prelude::*;
use diesel::result::Error;
use diesel::*;
use serde::Serialize;
use std::collections::HashSet;
use crate::backend::progress_report;
use crate::concerns::CortexInsertable;
use crate::helpers::TaskStatus;
use crate::models::{Corpus, Service};
use crate::schema::historical_runs;
#[derive(Identifiable, Queryable, Clone, Debug, PartialEq, Eq, QueryableByName)]
#[table_name = "historical_runs"]
pub struct HistoricalRun {
pub id: i32,
pub service_id: i32,
pub corpus_id: i32,
pub total: i32,
pub invalid: i32,
pub fatal: i32,
pub error: i32,
pub warning: i32,
pub no_problem: i32,
pub in_progress: i32,
pub start_time: NaiveDateTime,
pub end_time: Option<NaiveDateTime>,
pub owner: String,
pub description: String,
}
#[derive(Debug, Serialize, Clone)]
pub struct RunMetadata {
pub total: i32,
pub invalid: i32,
pub fatal: i32,
pub error: i32,
pub warning: i32,
pub no_problem: i32,
pub in_progress: i32,
pub start_time: String,
pub end_time: String,
pub owner: String,
pub description: String,
}
impl RunMetadata {
pub fn field_f32(&self, field: &str) -> f32 {
let field_i32 = match field {
"invalid" => self.invalid,
"total" => self.total,
"fatal" => self.fatal,
"error" => self.error,
"warning" => self.warning,
"no_problem" => self.no_problem,
"in_progress" => self.in_progress,
_ => unimplemented!(),
};
field_i32 as f32
}
}
#[derive(Debug, Serialize, Clone)]
pub struct RunMetadataStack {
pub severity: String,
pub severity_numeric: i32,
pub percent: f32,
pub total: i32,
pub start_time: String,
pub end_time: String,
pub owner: String,
pub description: String,
}
impl RunMetadataStack {
pub fn transform(runs_meta: &[RunMetadata]) -> Vec<RunMetadataStack> {
let mut start_time_guard = HashSet::new();
let mut runs_meta_vega = Vec::new();
for run in runs_meta.iter() {
if !run.start_time.is_empty() && !run.end_time.is_empty() {
if start_time_guard.contains(&run.start_time) {
continue;
} else {
start_time_guard.insert(run.start_time.clone());
}
}
let total = run.field_f32("total");
for field in ["fatal", "error", "warning", "no_problem", "in_progress"].iter() {
runs_meta_vega.push(RunMetadataStack {
severity: (*field).to_string(),
severity_numeric: TaskStatus::from_key(field).unwrap().raw(),
percent: (100.0 * run.field_f32(field)) / total,
total: run.total,
start_time: run.start_time.clone(),
end_time: run.end_time.clone(),
owner: run.owner.clone(),
description: run.description.clone(),
})
}
}
runs_meta_vega
}
}
#[derive(Insertable, Debug, Clone)]
#[table_name = "historical_runs"]
pub struct NewHistoricalRun {
pub service_id: i32,
pub corpus_id: i32,
pub description: String,
pub owner: String,
}
impl CortexInsertable for NewHistoricalRun {
fn create(&self, connection: &PgConnection) -> Result<usize, Error> {
insert_into(historical_runs::table)
.values(self)
.execute(connection)
}
}
impl HistoricalRun {
pub fn find_by(
corpus: &Corpus,
service: &Service,
connection: &PgConnection,
) -> Result<Vec<HistoricalRun>, Error>
{
use crate::schema::historical_runs::dsl::{corpus_id, service_id, start_time};
let runs: Vec<HistoricalRun> = historical_runs::table
.filter(corpus_id.eq(corpus.id))
.filter(service_id.eq(service.id))
.order(start_time.desc())
.get_results(connection)?;
Ok(runs)
}
pub fn find_current(
corpus: &Corpus,
service: &Service,
connection: &PgConnection,
) -> Result<Option<HistoricalRun>, Error>
{
use crate::schema::historical_runs::dsl::{corpus_id, end_time, service_id};
historical_runs::table
.filter(corpus_id.eq(corpus.id))
.filter(service_id.eq(service.id))
.filter(end_time.is_null())
.first(connection)
.optional()
}
pub fn mark_completed(&self, connection: &PgConnection) -> Result<(), Error> {
use diesel::dsl::now;
if self.end_time.is_none() {
let report = progress_report(connection, self.corpus_id, self.service_id);
let total = *report.get("total").unwrap_or(&0.0) as i32;
let no_problem = *report.get("no_problem").unwrap_or(&0.0) as i32;
let warning = *report.get("warning").unwrap_or(&0.0) as i32;
let error = *report.get("error").unwrap_or(&0.0) as i32;
let fatal = *report.get("fatal").unwrap_or(&0.0) as i32;
let invalid = *report.get("invalid").unwrap_or(&0.0) as i32;
let queued_count_f64: f64 =
report.get("queued").unwrap_or(&0.0) + report.get("todo").unwrap_or(&0.0);
let in_progress = queued_count_f64 as i32;
update(self)
.set((
historical_runs::end_time.eq(now),
historical_runs::total.eq(total),
historical_runs::in_progress.eq(in_progress),
historical_runs::invalid.eq(invalid),
historical_runs::no_problem.eq(no_problem),
historical_runs::warning.eq(warning),
historical_runs::error.eq(error),
historical_runs::fatal.eq(fatal),
))
.execute(connection)?;
}
Ok(())
}
}
impl From<HistoricalRun> for RunMetadata {
fn from(run: HistoricalRun) -> RunMetadata {
let HistoricalRun {
total,
warning,
error,
no_problem,
invalid,
fatal,
start_time,
end_time,
description,
in_progress,
owner,
..
} = run;
RunMetadata {
total,
invalid,
fatal,
warning,
error,
no_problem,
in_progress,
start_time: start_time.format("%Y-%m-%d").to_string(),
end_time: match end_time {
Some(etime) => etime.format("%Y-%m-%d").to_string(),
None => String::new(),
},
owner,
description,
}
}
}