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

Generated by: LCOV version 2.1-beta