1use std::marker::PhantomData;
21use std::ops::BitOr;
22
23use serde::de::DeserializeOwned;
24use serde_json::Value;
25
26use crate::parser;
27use crate::vm::VM;
28use crate::Error;
29
30#[derive(Debug, Clone)]
39pub struct Expr<T> {
40 src: String,
41 _marker: PhantomData<fn() -> T>,
42}
43
44impl<T> Expr<T> {
45 pub fn new<S: Into<String>>(src: S) -> Result<Self, Error> {
48 let src = src.into();
49 parser::parse(&src)?;
50 Ok(Self { src, _marker: PhantomData })
51 }
52
53 pub fn as_str(&self) -> &str { &self.src }
56
57 pub fn into_string(self) -> String { self.src }
60
61 pub fn cast<U>(self) -> Expr<U> {
64 Expr { src: self.src, _marker: PhantomData }
65 }
66}
67
68impl<T: DeserializeOwned> Expr<T> {
69 pub fn eval(&self, doc: &Value) -> Result<T, Error> {
74 let raw = VM::new().run_str(&self.src, doc)?;
75 serde_json::from_value(raw).map_err(|e| Error::Eval(crate::EvalError(e.to_string())))
76 }
77
78 pub fn eval_with(&self, vm: &mut VM, doc: &Value) -> Result<T, Error> {
81 let raw = vm.run_str(&self.src, doc)?;
82 serde_json::from_value(raw).map_err(|e| Error::Eval(crate::EvalError(e.to_string())))
83 }
84}
85
86impl Expr<Value> {
87 pub fn eval_raw(&self, doc: &Value) -> Result<Value, Error> {
89 Ok(VM::new().run_str(&self.src, doc)?)
90 }
91}
92
93impl<T, U> BitOr<Expr<U>> for Expr<T> {
96 type Output = Expr<U>;
97 fn bitor(self, rhs: Expr<U>) -> Expr<U> {
98 Expr {
99 src: format!("({}) | ({})", self.src, rhs.src),
100 _marker: PhantomData,
101 }
102 }
103}
104
105impl<T> AsRef<str> for Expr<T> {
106 fn as_ref(&self) -> &str { &self.src }
107}
108
109impl<T> std::fmt::Display for Expr<T> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 f.write_str(&self.src)
112 }
113}
114
115#[cfg(test)]
118mod tests {
119 use super::*;
120 use serde_json::json;
121
122 #[test]
123 fn parse_ok() {
124 let e: Expr<i64> = Expr::new("$.x.len()").unwrap();
125 assert_eq!(e.as_str(), "$.x.len()");
126 }
127
128 #[test]
129 fn parse_err() {
130 let e: Result<Expr<i64>, _> = Expr::new("$$$ not valid");
131 assert!(e.is_err());
132 }
133
134 #[test]
135 fn eval_typed() {
136 let e: Expr<i64> = Expr::new("$.xs.len()").unwrap();
137 let n = e.eval(&json!({"xs": [1, 2, 3]})).unwrap();
138 assert_eq!(n, 3);
139 }
140
141 #[test]
142 fn eval_vec() {
143 let e: Expr<Vec<String>> = Expr::new("$.users.map(name)").unwrap();
144 let names = e.eval(&json!({
145 "users": [{"name":"a"}, {"name":"b"}]
146 })).unwrap();
147 assert_eq!(names, vec!["a", "b"]);
148 }
149
150 #[test]
151 fn pipe_compose() {
152 let a: Expr<Value> = Expr::new("$.books").unwrap();
153 let b: Expr<Vec<Value>> = Expr::new("@.filter(price > 10)").unwrap();
154 let piped = a | b;
155 assert_eq!(piped.as_str(), "($.books) | (@.filter(price > 10))");
156 }
157
158 #[test]
159 fn cast_keeps_src() {
160 let e: Expr<i64> = Expr::new("$.n").unwrap();
161 let s = e.clone().cast::<String>();
162 assert_eq!(s.as_str(), e.as_str());
163 }
164}