Skip to main content

jpx_core/extensions/
jsonpatch.rs

1//! JSON Patch (RFC 6902) functions.
2
3use std::collections::HashSet;
4
5use serde_json::Value;
6
7use crate::functions::{Function, custom_error};
8use crate::interpreter::SearchResult;
9use crate::registry::register_if_enabled;
10use crate::{Context, Runtime, arg, defn};
11
12// =============================================================================
13// json_patch(obj, patch) -> object (RFC 6902)
14// Apply a JSON Patch (RFC 6902) to an object.
15// =============================================================================
16
17defn!(JsonPatchFn, vec![arg!(any), arg!(array)], None);
18
19impl Function for JsonPatchFn {
20    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
21        self.signature.validate(args, ctx)?;
22
23        // json-patch works with serde_json::Value directly -- no conversion needed
24        let mut result = args[0].clone();
25
26        let patch: json_patch::Patch = serde_json::from_value(args[1].clone())
27            .map_err(|e| custom_error(ctx, &format!("Invalid JSON Patch format: {}", e)))?;
28
29        json_patch::patch(&mut result, &patch)
30            .map_err(|e| custom_error(ctx, &format!("Failed to apply patch: {}", e)))?;
31
32        Ok(result)
33    }
34}
35
36// =============================================================================
37// json_merge_patch(obj, patch) -> object (RFC 7396)
38// Apply a JSON Merge Patch (RFC 7396) to an object.
39// =============================================================================
40
41defn!(JsonMergePatchFn, vec![arg!(any), arg!(any)], None);
42
43impl Function for JsonMergePatchFn {
44    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
45        self.signature.validate(args, ctx)?;
46
47        let mut result = args[0].clone();
48        json_patch::merge(&mut result, &args[1]);
49
50        Ok(result)
51    }
52}
53
54// =============================================================================
55// json_diff(a, b) -> array (RFC 6902 JSON Patch)
56// Generate a JSON Patch (RFC 6902) that transforms the first object into the second.
57// =============================================================================
58
59defn!(JsonDiffFn, vec![arg!(any), arg!(any)], None);
60
61impl Function for JsonDiffFn {
62    fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
63        self.signature.validate(args, ctx)?;
64
65        let patch = json_patch::diff(&args[0], &args[1]);
66
67        let patch_json = serde_json::to_value(&patch)
68            .map_err(|e| custom_error(ctx, &format!("Failed to serialize patch: {}", e)))?;
69
70        Ok(patch_json)
71    }
72}
73
74/// Register JSON patch functions filtered by the enabled set.
75pub fn register_filtered(runtime: &mut Runtime, enabled: &HashSet<&str>) {
76    register_if_enabled(runtime, "json_patch", enabled, Box::new(JsonPatchFn::new()));
77    register_if_enabled(
78        runtime,
79        "json_merge_patch",
80        enabled,
81        Box::new(JsonMergePatchFn::new()),
82    );
83    register_if_enabled(runtime, "json_diff", enabled, Box::new(JsonDiffFn::new()));
84}