///|
fn validate_value(
component : Component,
value : String,
limits : Limits,
) -> Unit raise SdmxError {
check_field(value, limits, component.id)
if value.is_empty() {
raise Invalid(
path=component.id,
reason="empty text is omission in this profile",
)
}
try {
match component.representation {
Text => ()
Decimal => ignore(DecimalValue::parse(value))
Integer => {
let chars = value.to_array()
let start = if chars[0] == '-' || chars[0] == '+' { 1 } else { 0 }
if start == chars.length() {
raise Invalid(path=component.id, reason="integer has no digits")
}
for i = start; i < chars.length(); i = i + 1 {
if chars[i] < '0' || chars[i] > '9' {
raise Invalid(path=component.id, reason="invalid integer")
}
}
ignore(DecimalValue::parse(value))
}
Period => ignore(PeriodValue::parse(value))
Coded(codes) =>
if !codes.contains(value) {
raise Invalid(path=component.id, reason="not in code list: \{value}")
}
}
} catch {
error => raise Invalid(path=component.id, reason=error.message())
}
}
///|
pub struct Observation {
priv key : Array[String]
priv measures : Array[String?]
priv attributes : Array[String?]
} derive(Eq, @debug.Debug)
///|
pub extend Observation with Eq::{equal, not_equal}
///|
pub extend Observation with @debug.Debug::{to_repr}
///|
pub fn Observation::new(
structure : Structure,
key : Array[String],
measures : Array[String?],
attributes : Array[String?],
) -> Observation raise SdmxError {
if key.length() != structure.dimensions.length() ||
measures.length() != structure.measures.length() ||
attributes.length() != structure.attributes.length() {
raise Invalid(
path="observation",
reason="component count differs from structure",
)
}
for i, component in structure.dimensions {
validate_value(component, key[i], structure.limits)
}
for i, component in structure.measures {
match measures[i] {
Some(value) => validate_value(component, value, structure.limits)
None =>
if component.required {
raise Invalid(path=component.id, reason="required measure omitted")
}
}
}
for i, component in structure.attributes {
match attributes[i] {
Some(value) => validate_value(component, value, structure.limits)
None =>
if component.required {
raise Invalid(path=component.id, reason="required attribute omitted")
}
}
}
{ key: key.copy(), measures: measures.copy(), attributes: attributes.copy(), }
}
///|
fn detached_observation(row : Observation) -> Observation {
{
key: row.key.copy(),
measures: row.measures.copy(),
attributes: row.attributes.copy(),
}
}
///|
pub fn Observation::key(self : Observation) -> Array[String] {
self.key.copy()
}
///|
pub fn Observation::measures(self : Observation) -> Array[String?] {
self.measures.copy()
}
///|
pub fn Observation::attributes(self : Observation) -> Array[String?] {
self.attributes.copy()
}
///|
pub fn Observation::key_token(self : Observation) -> String {
framed_key(self.key)
}
///|
pub fn Observation::value(
self : Observation,
structure : Structure,
id : String,
) -> String? raise SdmxError {
if structure.dimension_index(id) is Some(i) {
return Some(self.key[i])
}
for i, component in structure.measures {
if component.id == id {
return self.measures[i]
}
}
for i, component in structure.attributes {
if component.id == id {
return self.attributes[i]
}
}
raise Invalid(path="component", reason="unknown component: \{id}")
}