///|
pub(all) struct DimensionCoverage {
id : String
observed_values : Int32
declared_codes : Int32?
unseen_codes : Array[String]
} derive(@debug.Debug)
///|
pub extend DimensionCoverage with @debug.Debug::{to_repr}
///|
pub(all) struct ValueCoverage {
id : String
reported : Int32
omitted : Int32
distinct_values : Int32
} derive(@debug.Debug)
///|
pub extend ValueCoverage with @debug.Debug::{to_repr}
///|
pub struct DatasetCoverage {
priv observations : Int32
priv dimensions : Array[DimensionCoverage]
priv measures : Array[ValueCoverage]
priv attributes : Array[ValueCoverage]
priv frequencies : Array[(String, Int32)]
priv limits : Limits
} derive(@debug.Debug)
///|
pub extend DatasetCoverage with @debug.Debug::{to_repr}
///|
fn value_coverage(data : Dataset, measure : Bool) -> Array[ValueCoverage] {
let components = if measure {
data.structure.measures
} else {
data.structure.attributes
}
components.mapi((i, component) => {
let seen : Map[String, Bool] = Map([])
let mut reported = 0
for row in data.rows {
let value = if measure { row.measures[i] } else { row.attributes[i] }
if value is Some(text) {
reported += 1
seen[text] = true
}
}
{
id: component.id,
reported,
omitted: data.rows.length() - reported,
distinct_values: seen.length(),
}
})
}
///|
/// Coverage describes reported cells and vocabularies; it does not aggregate
/// values across units, frequencies, quality statuses or unit multipliers.
pub fn Dataset::coverage(self : Dataset) -> DatasetCoverage raise SdmxError {
let dimensions = self.structure.dimensions.mapi((i, component) => {
let seen : Map[String, Bool] = Map([])
for row in self.rows {
seen[row.key[i]] = true
}
let (declared_codes, unseen_codes) = match component.representation {
Coded(codes) => {
let unseen : Array[String] = []
for (code, _) in codes.entries() {
if !seen.contains(code) {
unseen.push(code)
}
}
(Some(codes.labels.length()), unseen)
}
_ => (None, [])
}
{
id: component.id,
observed_values: seen.length(),
declared_codes,
unseen_codes,
}
})
let counts : Map[String, Int32] = Map([])
if self.structure.time_index() is Some(position) {
for row in self.rows {
let frequency = PeriodValue::parse(row.key[position]).frequency()
counts[frequency] = counts.get(frequency).unwrap_or(0) + 1
}
}
let names : Array[String] = counts.keys().collect()
names.sort_by((a, b) => a.lexical_compare(b))
{
observations: self.rows.length(),
dimensions,
measures: value_coverage(self, true),
attributes: value_coverage(self, false),
frequencies: names.map(name => (name, counts[name])),
limits: self.structure.limits,
}
}
///|
pub fn DatasetCoverage::observation_count(self : DatasetCoverage) -> Int32 {
self.observations
}
///|
pub fn DatasetCoverage::dimensions(
self : DatasetCoverage,
) -> Array[DimensionCoverage] {
self.dimensions.map(c => { ..c, unseen_codes: c.unseen_codes.copy(), })
}
///|
pub fn DatasetCoverage::measures(
self : DatasetCoverage,
) -> Array[ValueCoverage] {
self.measures.copy()
}
///|
pub fn DatasetCoverage::attributes(
self : DatasetCoverage,
) -> Array[ValueCoverage] {
self.attributes.copy()
}
///|
pub fn DatasetCoverage::period_frequencies(
self : DatasetCoverage,
) -> Array[(String, Int32)] {
self.frequencies.copy()
}
///|
fn coverage_values_json(components : Array[ValueCoverage]) -> Array[Json] {
components.map(c => {
"id": c.id,
"reported": c.reported,
"omitted": c.omitted,
"distinctValues": c.distinct_values,
})
}
///|
pub fn DatasetCoverage::to_json(
self : DatasetCoverage,
) -> String raise SdmxError {
let dimensions : Array[Json] = self.dimensions.map(c => {
let count = match c.declared_codes {
None => Json::null()
Some(n) => Json::number(n.to_double())
}
{
"id": c.id,
"observedValues": c.observed_values,
"declaredCodes": count,
"unseenCodes": c.unseen_codes.map(Json::string),
}
})
let frequencies : Array[Json] = self.frequencies.map(pair => {
"frequency": pair.0,
"observations": pair.1,
})
canonical_json(
{
"profile": "moonsdmx.coverage/1",
"observations": self.observations,
"dimensions": dimensions,
"measures": coverage_values_json(self.measures),
"attributes": coverage_values_json(self.attributes),
"periodFrequencies": frequencies,
},
self.limits,
)
}