///|
fn validate_columns(columns : Value) -> Unit raise {
if columns == Null {
return
}
let targets : Map[String, Bool] = Map([])
for column in arr(columns) {
fields_only(column, [
"source", "target", "type", "default", "required", "trim", "lower", "empty_as_null",
"min", "max", "enum", "scale",
])
ignore(obj(column))
let source = str(get(column, "source"))
let target = optional_str(get(column, "target"), source)
if source == "" || target == "" || targets.contains(target) {
raise InputError("empty source/target or duplicate target column")
}
targets[target] = true
let kind = optional_str(get(column, "type"), "any")
if !["any", "string", "number", "integer", "boolean"].contains(kind) {
raise InputError("unknown column type: " + kind)
}
for flag in ["required", "trim", "lower", "empty_as_null"] {
match get(column, flag) {
Null | Bool(_) => ()
_ => raise InputError("column flag must be boolean: " + flag)
}
}
for key in ["min", "max", "scale"] {
if get(column, key) != Null {
ignore(num(get(column, key)))
}
}
if get(column, "min") != Null &&
get(column, "max") != Null &&
num(get(column, "min")) > num(get(column, "max")) {
raise InputError("column minimum exceeds maximum")
}
if get(column, "enum") != Null {
ignore(arr(get(column, "enum")))
}
}
}
///|
fn validate_group_keys(keys : Array[String]) -> Unit raise InputError {
let seen : Map[String, Bool] = Map([])
for key in keys {
if key == "" || ["count", "sum", "mean"].contains(key) || seen.contains(key) {
raise InputError("duplicate, empty or aggregate-reserved group key")
}
seen[key] = true
}
}