///|
/// Compiled jq query wrapper so the AST stays internal.
pub struct Query {
expr : @ast.Expr
}
///|
/// Compile a jq query string into a reusable Query.
pub fn parse(query : String) -> Query raise {
Query::{ expr: @parser.parse(query) }
}
///|
/// Evaluate a compiled query against an input JSON value and stream results.
pub fn eval(query : Query, input : Json) -> Iterator[Json] raise {
query.eval(input)
}
///|
/// Evaluate a compiled query and collect all results eagerly.
pub fn eval_all(query : Query, input : Json) -> Array[Json] raise {
query.eval_all(input)
}
///|
/// Parse + evaluate a jq query against a JSON string input, collecting results.
pub fn run(query : String, input : String) -> Array[Json] raise {
let compiled = parse(query)
let json = @json.parse(input[:])
compiled.eval_all(json)
}
///|
/// Evaluate a compiled query against an already parsed Json input.
pub fn run_json(query : Query, input : Json) -> Array[Json] raise {
query.eval_all(input)
}
///|
/// Methods on Query for direct control.
pub fn Query::eval(self : Query, input : Json) -> Iterator[Json] raise {
@ast.eval(self.expr, input)
}
///|
pub fn Query::eval_all(self : Query, input : Json) -> Array[Json] raise {
self.eval(input).collect()
}
///|
/// Apply the query to newline-delimited JSON logs, skipping invalid lines.
pub fn Query::eval_logs(self : Query, logs : String) -> Iterator[Json] raise {
let aggregated : Array[Json] = []
for raw_line in logs.split("\n") {
let line = match raw_line.strip_suffix("\r"[:]) {
Some(rest) => rest
None => raw_line
}
if line.length() == 0 {
continue
}
let json_value = @json.parse(line) catch { _ => continue }
for value in @ast.eval(self.expr, json_value) {
aggregated.push(value)
}
}
aggregated.iterator()
}