///|
pub struct AuditEntry {
priv path : String
priv result : ResolvedMetadata?
priv error : Diagnostic?
}
///|
pub fn AuditEntry::path(self : AuditEntry) -> String {
self.path
}
///|
pub fn AuditEntry::result(self : AuditEntry) -> ResolvedMetadata? {
self.result
}
///|
pub fn AuditEntry::diagnostic(self : AuditEntry) -> Diagnostic? {
self.error.map(d => {
code: d.code,
path: d.path,
message: d.message,
offset: d.offset,
related: d.related.copy(),
})
}
///|
pub struct AuditReport {
priv entries : Array[AuditEntry]
}
///|
pub fn AuditReport::entries(self : AuditReport) -> Array[AuditEntry] {
self.entries.copy()
}
///|
pub fn AuditReport::error_count(self : AuditReport) -> Int32 {
self.entries.filter(e => e.error is Some(_)).length()
}
///|
/// Every requested occurrence is retained in request order, including duplicates.
/// Resolution errors are isolated; invalid manifests still fail at construction.
pub fn DatasetIndex::audit(
self : DatasetIndex,
paths : Array[String],
) -> AuditReport {
let entries = paths.map(path => {
{ path, result: Some(self.resolve(path)), error: None, } catch {
TraceError(diagnostic) => { path, result: None, error: Some(diagnostic), }
}
})
{ entries, }
}
///|
pub fn DatasetIndex::audit_all(self : DatasetIndex) -> AuditReport {
self.audit(self.data_paths())
}
///|
fn AuditReport::report_value(self : AuditReport) -> Json {
Json::object({
"error_count": Json::number(self.error_count().to_double()),
"entries": Json::array(
self.entries.map(e => {
let fields : Map[String, Json] = { "data_path": Json::string(e.path) }
match (e.result, e.error) {
(Some(result), None) => {
fields["status"] = Json::string("resolved")
fields["result"] = result.report_value()
}
(None, Some(diagnostic)) => {
fields["status"] = Json::string("error")
fields["diagnostic"] = diagnostic.to_json()
}
_ => abort("AuditEntry invariant")
}
Json::object(fields)
}),
),
})
}
///|
pub fn AuditReport::to_json(self : AuditReport) -> String {
canonical_json(self.report_value())
}