///|
pub struct QualityMetric {
key : String
value : Double
unit : String
target : Double
lower_is_better : Bool
} derive(Debug, ToJson)
///|
pub struct MetricCatalog {
metrics : Array[QualityMetric]
version : String
} derive(Debug, ToJson)
///|
pub fn quality_metric(
key~ : String,
value~ : Double,
unit~ : String,
target~ : Double,
lower_is_better~ : Bool,
) -> QualityMetric {
{ key, value, unit, target, lower_is_better }
}
///|
pub fn metric_catalog(version~ : String) -> MetricCatalog {
{ metrics: [], version }
}
///|
pub fn MetricCatalog::add(self : MetricCatalog, metric : QualityMetric) -> Unit {
self.metrics.push(metric)
}
///|
pub fn metric_gap(metric : QualityMetric) -> Double {
if metric.lower_is_better {
(metric.value - metric.target).max(0.0)
} else {
(metric.target - metric.value).max(0.0)
}
}
///|
pub fn metric_meets_target(metric : QualityMetric) -> Bool {
metric_gap(metric) <= 0.0
}
///|
pub fn catalog_score(catalog : MetricCatalog) -> Double {
if catalog.metrics.length() == 0 {
100.0
} else {
let mut passed = 0
for metric in catalog.metrics {
if metric_meets_target(metric) {
passed += 1
}
}
passed.to_double() / catalog.metrics.length().to_double() * 100.0
}
}
///|
pub fn catalog_failed(catalog : MetricCatalog) -> Array[QualityMetric] {
let result : Array[QualityMetric] = []
for metric in catalog.metrics {
if !metric_meets_target(metric) {
result.push(metric)
}
}
result
}
///|
pub fn catalog_keys(catalog : MetricCatalog) -> Array[String] {
let result : Array[String] = []
for metric in catalog.metrics {
result.push(metric.key)
}
result
}
///|
pub fn catalog_units(catalog : MetricCatalog) -> Array[String] {
let result : Array[String] = []
for metric in catalog.metrics {
if !result.contains(metric.unit) {
result.push(metric.unit)
}
}
result
}
///|
pub fn catalog_metric(catalog : MetricCatalog, key : String) -> QualityMetric? {
for metric in catalog.metrics {
if metric.key == key {
return Some(metric)
}
}
None
}
///|
pub fn normalized_metric(metric : QualityMetric) -> Double {
if metric.target == 0.0 {
0.0
} else if metric.lower_is_better {
metric.target / metric.value.max(0.000001)
} else {
metric.value / metric.target
}
}
///|
pub fn catalog_average_normalized(catalog : MetricCatalog) -> Double {
if catalog.metrics.length() == 0 {
0.0
} else {
let mut total = 0.0
for metric in catalog.metrics {
total += normalized_metric(metric)
}
total / catalog.metrics.length().to_double()
}
}