///|
/// An annotation object is retained as bounded canonical JSON, without fetching URLs.
pub struct Annotation {
priv content : String
} derive(Eq, @debug.Debug)
///|
pub extend Annotation with Eq::{equal, not_equal}
///|
pub extend Annotation with @debug.Debug::{to_repr}
///|
pub fn Annotation::from_json(
text : String,
limits~ : Limits = Limits::standard(),
) -> Annotation raise SdmxError {
let value = parse_bounded_json(text, limits)
ignore(j_object(value, "annotation"))
{ content: canonical_json(value, limits), }
}
///|
pub fn Annotation::to_json(self : Annotation) -> String {
self.content
}
///|
pub fn DataMessage::annotations(self : DataMessage) -> Array[Annotation] {
self.notes.copy()
}
///|
pub fn DataMessage::annotations_for(
self : DataMessage,
key : Array[String],
) -> Array[Annotation] raise SdmxError {
if self.dataset.get(key) is None {
raise Invalid(path="annotation key", reason="observation does not exist")
}
match self.row_notes.get(framed_key(key)) {
None => []
Some(indices) => indices.map(i => self.notes[i])
}
}
///|
pub fn DataMessage::with_annotations(
self : DataMessage,
notes : Array[Annotation],
bindings : Array[(Array[String], Array[Int32])],
) -> DataMessage raise SdmxError {
let limits = self.dataset.structure.limits
if notes.length() > limits.max_codes {
raise Limit(resource="annotations", maximum=limits.max_codes)
}
let mut units = 0
for note in notes {
if units > limits.max_text - note.content.length() {
raise Limit(resource="annotation text", maximum=limits.max_text)
}
units += note.content.length()
}
if bindings.length() > self.dataset.rows.length() {
raise Invalid(
path="annotation bindings",
reason="more bindings than observations",
)
}
let mapping : Map[String, Array[Int32]] = Map([])
let mut references = 0
for (key, indices) in bindings {
if self.dataset.get(key) is None {
raise Invalid(path="annotation key", reason="observation does not exist")
}
let token = framed_key(key)
if mapping.contains(token) {
raise Invalid(path="annotation bindings", reason="duplicate key")
}
if indices.length() > 1024 {
raise Limit(resource="annotations per observation", maximum=1024)
}
references += indices.length()
if references > 1000000 {
raise Limit(resource="annotation references", maximum=1000000)
}
let seen : Map[Int32, Bool] = Map([])
for index in indices {
if index < 0 || index >= notes.length() {
raise Invalid(path="annotation index", reason="out of range")
}
if seen.contains(index) {
raise Invalid(path="annotation index", reason="duplicate reference")
}
seen[index] = true
}
mapping[token] = indices.copy()
}
{ ..self, notes: notes.copy(), row_notes: mapping, }
}
///|
pub fn DataMessage::without_annotations(self : DataMessage) -> DataMessage {
{ ..self, notes: [], row_notes: Map([]), }
}