///|
fn decode_dataset(value : Json, limits : Limits) -> Dataset raise ConfigError {
let root = object_fields(value, "dataset")
reject_unknown(
root,
["format", "model", "seed", "algorithm", "reference_time", "tables"],
"dataset",
)
fn text(name : String) -> String raise ConfigError {
text_value(required(root, name, "dataset"), "dataset." + name)
}
if text("format") != "moonfixture.dataset.v1" {
raise InvalidConfig("dataset.format", "Unsupported dataset format")
}
let definitions = array_value(
required(root, "tables", "dataset"),
"dataset.tables",
)
if definitions.length() > limits.max_entities {
raise InvalidConfig("dataset.tables", "Too many tables")
}
let tables : Array[Table] = []
let mut rows_total = 0L
let mut cells_total = 0L
let mut text_total = 0L
for ti in 0.. limits.max_rows.to_int64() {
raise InvalidConfig(path, "Dataset row limit exceeded")
}
let rows : Array[Row] = []
for ri in 0.. limits.max_fields {
raise InvalidConfig(row_path, "Too many fields")
}
cells_total += object.length().to_int64()
if cells_total > limits.max_cells.to_int64() {
raise InvalidConfig(row_path, "Dataset cell limit exceeded")
}
let names : Array[String] = []
for name, _ in object {
names.push(name)
}
names.sort()
let cells : Array[Cell] = []
for name in names {
let value = scalar_value(
object.get(name).unwrap(),
row_path + "." + name,
)
if value is Text(text) {
text_total += text.length().to_int64()
}
if text_total > limits.max_text_units.to_int64() {
raise InvalidConfig(row_path, "Dataset text limit exceeded")
}
cells.push({ name, value, })
}
rows.push({ cells, })
}
tables.push({ name, rows, })
}
{
model: text("model"),
seed: unsigned_decimal(text("seed"), "dataset.seed"),
algorithm: text("algorithm"),
reference_time: text("reference_time"),
tables,
}
}
///|
/// Parsing does not imply validity against a model; call validate_dataset next.
/// Imported row fields are sorted; row/table array order is retained.
pub fn parse_dataset(
text : String,
max_units? : Int = 16777216,
limits? : Limits = Limits::default(),
) -> Result[Dataset, Issue] {
if guard_json(text, max_units, "dataset") is Err(error) {
return Err(error)
}
if max_units <= 0 || text.length() > max_units {
return Err(
issue("input_limit", "dataset", "Dataset input exceeds configured limit"),
)
}
Ok(decode_dataset(@json.parse(text), limits)) catch {
InvalidConfig(path, message) => Err(issue("invalid_dataset", path, message))
_ => Err(issue("invalid_json", "dataset", "Invalid dataset JSON"))
}
}