rs_json_filter_cel/
lib.rs

1use std::io;
2
3use io::BufRead;
4
5use serde_json::Value;
6
7use cel::{Context, Program};
8
9pub struct CelValue(pub cel::Value);
10
11impl CelValue {
12    pub fn to_bool(&self) -> Option<bool> {
13        match self.0 {
14            cel::Value::Bool(b) => Some(b),
15            _ => None,
16        }
17    }
18}
19
20pub struct CelProgram(pub Program);
21
22impl CelProgram {
23    pub fn execute(&self, ctx: &Context) -> Result<CelValue, io::Error> {
24        self.0.execute(ctx).map(CelValue).map_err(io::Error::other)
25    }
26
27    pub fn execute_with_value(
28        &self,
29        ctx: &Context,
30        vname: &str,
31        val: Value,
32    ) -> Result<CelValue, io::Error> {
33        let mut child: Context = ctx.new_inner_scope();
34        child.add_variable(vname, val).map_err(io::Error::other)?;
35        self.execute(&child)
36    }
37
38    pub fn filter_value(&self, ctx: &Context, vname: &str, val: &Value) -> Result<bool, io::Error> {
39        let cv: CelValue = self.execute_with_value(ctx, vname, val.clone())?;
40        let ob: Option<bool> = cv.to_bool();
41        ob.ok_or(io::Error::other("bool expected"))
42    }
43}
44
45impl CelProgram {
46    pub fn jsons2filtered<I>(
47        self,
48        jsons: I,
49        ctx: Context,
50        vname: String,
51    ) -> impl Iterator<Item = Result<Value, io::Error>>
52    where
53        I: Iterator<Item = Result<Value, io::Error>>,
54    {
55        jsons.filter(move |rv| match rv {
56            Ok(v) => {
57                let rflt = self.filter_value(&ctx, &vname, v);
58                rflt.unwrap_or(false)
59            }
60            Err(_e) => true,
61        })
62    }
63}
64
65pub fn compile(expr: &str) -> Result<CelProgram, io::Error> {
66    Program::compile(expr)
67        .map(CelProgram)
68        .map_err(io::Error::other)
69}
70
71pub fn rdr2jsons<R>(rdr: R) -> impl Iterator<Item = Result<Value, io::Error>>
72where
73    R: BufRead,
74{
75    rdr.lines()
76        .map(|rline| rline.and_then(|line| serde_json::from_str(&line).map_err(io::Error::other)))
77}
78
79pub fn stdin2jsons() -> impl Iterator<Item = Result<Value, io::Error>> {
80    rdr2jsons(io::stdin().lock())
81}