///|
pub fn quality_gate(
config : Value,
input : Int32,
rejected : Int32,
) -> Value raise {
if input < 0 || rejected < 0 || rejected > input {
raise InputError("invalid quality gate row counts")
}
let fraction = if input == 0 {
0.0
} else {
rejected.to_double() / input.to_double()
}
let violations : Array[String] = []
if config != Null {
for key, _ in obj(config) {
if !["max_rejected", "max_rejection_fraction"].contains(key) {
raise InputError("unknown quality gate option: " + key)
}
}
if get(config, "max_rejected") != Null {
let limit = num(get(config, "max_rejected"))
if limit < 0.0 || limit.floor() != limit {
raise InputError("max_rejected must be a nonnegative integer")
}
if rejected.to_double() > limit {
violations.push("max_rejected")
}
}
if get(config, "max_rejection_fraction") != Null {
let limit = num(get(config, "max_rejection_fraction"))
if limit < 0.0 || limit > 1.0 {
raise InputError("max_rejection_fraction must be between zero and one")
}
if fraction > limit {
violations.push("max_rejection_fraction")
}
}
}
record([
("passed", Bool(violations.is_empty())),
("rejected", Number(rejected.to_double())),
("rejection_fraction", Number(fraction)),
("violations", strings(violations)),
])
}
///|
fn audit_rows(
input : Int32,
rejected : Int32,
accepted : Int32,
filtered : Int32,
deduplicated : Int32,
join_discarded : Int32,
before_group : Int32,
returned : Int32,
) -> Value raise {
let conserved = input ==
rejected + filtered + deduplicated + join_discarded + before_group &&
input == accepted + rejected
if !conserved {
raise InputError("internal row reconciliation failed")
}
record([
("input", Number(input.to_double())),
("rejected", Number(rejected.to_double())),
("accepted", Number(accepted.to_double())),
("filtered", Number(filtered.to_double())),
("deduplicated", Number(deduplicated.to_double())),
("join_discarded", Number(join_discarded.to_double())),
("before_group", Number(before_group.to_double())),
("returned", Number(returned.to_double())),
("conserved", Bool(conserved)),
])
}