use serde_json::Number;
use super::{Input, Refused, Span, Stage, first};
pub(super) fn read(input: &mut Input<'_>) -> Result<Stage, Refused> {
input.advance(10);
input.require("(", "`percentile` takes a field and number in brackets")?;
input.require(
".",
"`percentile` takes a top-level field with a leading dot",
)?;
let length = input
.rest
.find(|character| !first(character))
.unwrap_or(input.rest.len());
if length == 0 {
return Err(input.parse("`percentile` needs a field name after its dot"));
}
let field = input.rest.split_at(length).0.to_owned();
input.advance(length);
input.require(";", "`percentile` separates its field and number with `;`")?;
input.trim();
let Some((literal, _)) = input.rest.split_once(')') else {
return Err(input.parse("`percentile` needs a number and a closing `)`"));
};
let number = literal.trim_end();
let span = Span {
start: input.position(),
end: input.position() + number.len(),
};
let percentile: Number = serde_json::from_str(number).map_err(|error| {
Refused::Parse(format!("`percentile` takes a JSON number: {error}"), span)
})?;
haematite_query::stage::percentile::Percentile::compile(field.clone(), percentile.clone())
.map_err(|error| Refused::Percentile(error.refusal.message, span))?;
input.advance(literal.len() + 1);
Ok(Stage::Percentile { field, percentile })
}
#[cfg(test)]
#[path = "percentile_parse_tests.rs"]
mod tests;