txtx_core/std/functions/
json.rs1use jaq_interpret::{Ctx, FilterT, ParseCtx, RcIter, Val};
2use serde_json::Value as JsonValue;
3use txtx_addon_kit::types::AuthorizationContext;
4use txtx_addon_kit::{
5 define_function, indoc,
6 types::{
7 diagnostics::Diagnostic,
8 functions::{FunctionImplementation, FunctionSpecification},
9 types::{Type, Value},
10 },
11};
12
13use crate::std::functions::{arg_checker, to_diag};
14
15lazy_static! {
16 pub static ref JSON_FUNCTIONS: Vec<FunctionSpecification> = vec documentation for more details.
22 "#},
23 example: indoc!{r#"
24 output "message" {
25 value = jq("{ \"message\": \"Hello world!\" }", ".message")
26 }
27 > message: Hello world!
28 "#},
29 inputs: [
30 decoded_json: {
31 documentation: "A JSON object.",
32 typing: vec![Type::string(), Type::arbitrary_object()]
33 },
34 query: {
35 documentation: "A JSON query. See the [jq](https://jqlang.github.io/jq/manual/) documentation.",
36 typing: vec![Type::string()]
37 }
38 ],
39 output: {
40 documentation: "The result of the `jq` query.",
41 typing: Type::array(Type::string())
42 },
43 }
44 },];
45}
46
47pub struct JsonQuery;
48impl FunctionImplementation for JsonQuery {
49 fn check_instantiability(
50 _fn_spec: &FunctionSpecification,
51 _auth_ctx: &AuthorizationContext,
52 _args: &Vec<Type>,
53 ) -> Result<Type, Diagnostic> {
54 unimplemented!()
55 }
56
57 fn run(
58 fn_spec: &FunctionSpecification,
59 _auth_ctx: &AuthorizationContext,
60 args: &Vec<Value>,
61 ) -> Result<Value, Diagnostic> {
62 arg_checker(fn_spec, args)?;
63 let input_str = args.get(0).unwrap().encode_to_string();
64 let filter = args.get(1).unwrap().as_string().unwrap();
65
66 let input: JsonValue = match serde_json::from_str(&input_str) {
68 Ok(json) => json,
69 Err(e) => serde_json::from_str(&input_str.trim_matches('"'))
71 .map_err(|_| to_diag(fn_spec, format!("failed to decode input as json: {e}")))?,
72 };
73
74 let mut defs = ParseCtx::new(Vec::new());
75
76 let (f, errs) = jaq_parse::parse(&filter, jaq_parse::main());
78 if !errs.is_empty() {
79 return Err(to_diag(fn_spec, errs.first().unwrap().to_string()));
80 }
81
82 let f = defs.compile(f.unwrap());
84 let errs = defs.errs;
85 if !errs.is_empty() {
86 return Err(to_diag(fn_spec, errs.first().unwrap().0.to_string()));
87 }
88
89 let inputs = RcIter::new(core::iter::empty());
90 let result = f
92 .run((Ctx::new([], &inputs), Val::from(input)))
93 .into_iter()
94 .map(|o| o.map(|v| Value::from_jaq_value(&v)))
96 .collect::<Result<Result<Vec<Value>, _>, _>>()
97 .map_err(|e| to_diag(fn_spec, e.to_string()))?
98 .map_err(|e| to_diag(fn_spec, e.to_string()))?;
99 if result.len() == 1 {
100 Ok(result.first().unwrap().clone())
101 } else {
102 Ok(Value::array(result))
103 }
104 }
105}