LCOV - code coverage report
Current view: top level - safekeeper/src - patch_control_file.rs (source / functions) Coverage Total Hit
Test: 5445d246133daeceb0507e6cc0797ab7c1c70cb8.info Lines: 0.0 % 45 0
Test Date: 2025-03-12 18:05:02 Functions: 0.0 % 10 0

            Line data    Source code
       1              : use std::sync::Arc;
       2              : 
       3              : use serde::{Deserialize, Serialize};
       4              : use serde_json::Value;
       5              : use tracing::info;
       6              : 
       7              : use crate::state::TimelinePersistentState;
       8              : use crate::timeline::Timeline;
       9              : 
      10            0 : #[derive(Deserialize, Debug, Clone)]
      11              : pub struct Request {
      12              :     /// JSON object with fields to update
      13              :     pub updates: serde_json::Value,
      14              :     /// List of fields to apply
      15              :     pub apply_fields: Vec<String>,
      16              : }
      17              : 
      18              : #[derive(Serialize)]
      19              : pub struct Response {
      20              :     pub old_control_file: TimelinePersistentState,
      21              :     pub new_control_file: TimelinePersistentState,
      22              : }
      23              : 
      24              : /// Patch control file with given request. Will update the persistent state using
      25              : /// fields from the request and persist the new state on disk.
      26            0 : pub async fn handle_request(tli: Arc<Timeline>, request: Request) -> anyhow::Result<Response> {
      27            0 :     let response = tli
      28            0 :         .map_control_file(|state| {
      29            0 :             let old_control_file = state.clone();
      30            0 :             let new_control_file = state_apply_diff(&old_control_file, &request)?;
      31              : 
      32            0 :             info!(
      33            0 :                 "patching control file, old: {:?}, new: {:?}, patch: {:?}",
      34              :                 old_control_file, new_control_file, request
      35              :             );
      36            0 :             *state = new_control_file.clone();
      37            0 : 
      38            0 :             Ok(Response {
      39            0 :                 old_control_file,
      40            0 :                 new_control_file,
      41            0 :             })
      42            0 :         })
      43            0 :         .await?;
      44              : 
      45            0 :     Ok(response)
      46            0 : }
      47              : 
      48            0 : fn state_apply_diff(
      49            0 :     state: &TimelinePersistentState,
      50            0 :     request: &Request,
      51            0 : ) -> anyhow::Result<TimelinePersistentState> {
      52            0 :     let mut json_value = serde_json::to_value(state)?;
      53              : 
      54            0 :     if let Value::Object(a) = &mut json_value {
      55            0 :         if let Value::Object(b) = &request.updates {
      56            0 :             json_apply_diff(a, b, &request.apply_fields)?;
      57              :         } else {
      58            0 :             anyhow::bail!("request.updates is not a json object")
      59              :         }
      60              :     } else {
      61            0 :         anyhow::bail!("TimelinePersistentState is not a json object")
      62              :     }
      63              : 
      64            0 :     let new_state: TimelinePersistentState = serde_json::from_value(json_value)?;
      65            0 :     Ok(new_state)
      66            0 : }
      67              : 
      68            0 : fn json_apply_diff(
      69            0 :     object: &mut serde_json::Map<String, Value>,
      70            0 :     updates: &serde_json::Map<String, Value>,
      71            0 :     apply_keys: &Vec<String>,
      72            0 : ) -> anyhow::Result<()> {
      73            0 :     for key in apply_keys {
      74            0 :         if let Some(new_value) = updates.get(key) {
      75            0 :             if let Some(existing_value) = object.get_mut(key) {
      76            0 :                 *existing_value = new_value.clone();
      77            0 :             } else {
      78            0 :                 anyhow::bail!("key not found in original object: {}", key);
      79              :             }
      80              :         } else {
      81            0 :             anyhow::bail!("key not found in request.updates: {}", key);
      82              :         }
      83              :     }
      84              : 
      85            0 :     Ok(())
      86            0 : }
        

Generated by: LCOV version 2.1-beta