feoxdb/core/store/json_patch.rs
1use crate::error::{FeoxError, Result};
2
3use super::FeoxStore;
4
5impl FeoxStore {
6 /// Apply a JSON patch to a value.
7 ///
8 /// Uses RFC 6902 JSON Patch format to modify specific fields in a JSON document.
9 /// Both the existing value and the patch must be valid JSON.
10 ///
11 /// # Arguments
12 ///
13 /// * `key` - The key containing the JSON document to patch
14 /// * `patch` - JSON Patch operations in RFC 6902 format
15 /// * `timestamp` - Optional timestamp for conflict resolution
16 ///
17 /// # Returns
18 ///
19 /// Returns `Ok(())` if the update was applied.
20 ///
21 /// # Errors
22 ///
23 /// * `KeyNotFound` - Key does not exist
24 /// * `OlderTimestamp` - Timestamp is not newer than existing record
25 /// * `JsonPatchError` - Invalid JSON document or patch format
26 ///
27 /// # Example
28 ///
29 /// ```no_run
30 /// # use feoxdb::FeoxStore;
31 /// # fn main() -> feoxdb::Result<()> {
32 /// # let store = FeoxStore::new(None)?;
33 /// // Insert initial JSON value
34 /// let initial = br#"{"name":"Alice","age":30}"#;
35 /// store.insert(b"user:1", initial)?;
36 ///
37 /// // Apply JSON patch to update age
38 /// let patch = br#"[{"op":"replace","path":"/age","value":31}]"#;
39 /// store.json_patch(b"user:1", patch)?;
40 ///
41 /// // Value now has age updated to 31
42 /// let updated = store.get(b"user:1")?;
43 /// assert_eq!(updated.len(), initial.len()); // Same length, just age changed
44 /// # Ok(())
45 /// # }
46 /// ```
47 pub fn json_patch(&self, key: &[u8], patch: &[u8]) -> Result<()> {
48 self.json_patch_with_timestamp(key, patch, None)
49 }
50
51 /// Apply JSON patch with explicit timestamp.
52 ///
53 /// This is the advanced version that allows manual timestamp control.
54 /// Most users should use `json_patch()` instead.
55 ///
56 /// # Arguments
57 ///
58 /// * `key` - The key whose value to patch
59 /// * `patch` - JSON Patch array (RFC 6902)
60 /// * `timestamp` - Optional timestamp. If `None`, uses current time.
61 ///
62 /// # Errors
63 ///
64 /// * `OlderTimestamp` - Timestamp is not newer than existing record
65 pub fn json_patch_with_timestamp(
66 &self,
67 key: &[u8],
68 patch: &[u8],
69 timestamp: Option<u64>,
70 ) -> Result<()> {
71 let timestamp = match timestamp {
72 Some(0) | None => self.get_timestamp(),
73 Some(ts) => ts,
74 };
75 self.validate_key(key)?;
76
77 // Get the value and release the lock immediately
78 let current_value = {
79 let record = self
80 .hash_table
81 .read(key, |_, v| v.clone())
82 .ok_or(FeoxError::KeyNotFound)?;
83
84 if timestamp < record.timestamp {
85 return Err(FeoxError::OlderTimestamp);
86 }
87
88 if let Some(val) = record.get_value() {
89 val.to_vec()
90 } else {
91 self.load_value_from_disk(&record)?
92 }
93 };
94
95 let new_value = crate::utils::json_patch::apply_json_patch(¤t_value, patch)?;
96
97 // Now update without holding any references
98 self.insert_with_timestamp(key, &new_value, Some(timestamp))?;
99 Ok(())
100 }
101}