///|
struct DimensionPredicate {
position : Int32
codes : Map[String, Bool]
}
///|
pub struct Selection {
priv signature : String
priv predicates : Array[DimensionPredicate]
}
///|
pub fn Selection::new(
structure : Structure,
terms : Array[(String, Array[String])],
) -> Selection raise SdmxError {
let predicates : Array[DimensionPredicate] = []
let seen : Map[String, Bool] = Map([])
for (id, values) in terms {
let position = match structure.positions.get(id) {
Some(i) => i
None => raise Invalid(path="selection", reason="not a dimension: \{id}")
}
if seen.contains(id) {
raise Invalid(path="selection", reason="duplicate dimension: \{id}")
}
seen[id] = true
if values.length() > structure.limits.max_codes {
raise Limit(
resource="selection values",
maximum=structure.limits.max_codes,
)
}
let codes : Map[String, Bool] = Map([])
for value in values {
validate_value(structure.dimensions[position], value, structure.limits)
if codes.contains(value) {
raise Invalid(path=id, reason="duplicate selected code")
}
codes[value] = true
}
predicates.push({ position, codes, })
}
{ signature: structure.to_profile_json(), predicates, }
}
///|
pub fn Dataset::select(
self : Dataset,
selection : Selection,
) -> Dataset raise SdmxError {
if self.structure.to_profile_json() != selection.signature {
raise Invalid(
path="selection",
reason="selection was compiled for a different structure",
)
}
let rows : Array[Observation] = []
for row in self.rows {
let mut selected = true
for predicate in selection.predicates {
if !predicate.codes.contains(row.key[predicate.position]) {
selected = false
break
}
}
if selected {
rows.push(row)
}
}
Dataset::new(self.structure, rows)
}
///|
pub fn Dataset::dimension_values(
self : Dataset,
id : String,
) -> Array[String] raise SdmxError {
let index = match self.structure.dimension_index(id) {
Some(i) => i
None => raise Invalid(path=id, reason="not a dimension")
}
let seen : Map[String, Bool] = Map([])
for row in self.rows {
seen[row.key[index]] = true
}
let values : Array[String] = seen.keys().collect()
values.sort_by((a, b) => a.lexical_compare(b))
values
}