Common/Storage/SetStorageItem.rs
1// File: Common/Source/Storage/SetStorageItem.rs
2// Role: Defines the `SetStorageItem` ActionEffect.
3// Responsibilities:
4// - Provide a declarative effect for setting or updating a single item in
5// Memento storage.
6// - This effect abstracts the "what" (set a storage item) from the "how" (the
7// StorageProvider implementation).
8//
9// NOTE: This effect is part of a legacy, per-key storage model. The newer,
10
11// high-performance storage model in Cocoon uses a batch-oriented approach
12// (`GetAllStorage`, `SetAllStorage`), making this effect obsolete for that
13// use case. It is kept for potential other uses or until fully deprecated.
14
15//! # SetStorageItem Effect
16//!
17//! Defines the `ActionEffect` for setting or updating an item in Memento-style
18//! storage.
19
20use std::sync::Arc;
21
22use serde_json::Value;
23
24use super::StorageProvider::StorageProvider;
25use crate::{Effect::ActionEffect::ActionEffect, Error::CommonError::CommonError};
26
27/// Creates an effect that, when executed, will set or update an item in either
28/// global or workspace-scoped Memento storage.
29///
30/// It uses the `StorageProvider` capability from the environment to perform the
31/// actual data persistence on the host.
32///
33/// # Parameters
34/// * `TargetObjectValue`: A `serde_json::Value` expected to be an object with
35/// the following fields:
36/// - `Scope` (boolean, optional): `true` for global scope, `false` or
37/// absent for workspace scope.
38/// - `Key` (string, required): The key of the item to set or update.
39/// * `ValueToSet`: The `serde_json::Value` to store. If this value is
40/// `Value::Null`, the effect will delete the item from storage.
41///
42/// # Returns
43/// An `ActionEffect` that resolves to `()` on success.
44pub fn SetStorageItem(
45 TargetObjectValue:Value,
46
47 ValueToSet:Value,
48) -> ActionEffect<Arc<dyn StorageProvider>, CommonError, ()> {
49 ActionEffect::New(Arc::new(move |Provider:Arc<dyn StorageProvider>| {
50 let TargetObjectClone = TargetObjectValue.clone();
51
52 let ValueToSetClone = ValueToSet.clone();
53
54 Box::pin(async move {
55 let IsGlobal = TargetObjectClone.get("Scope").and_then(Value::as_bool).unwrap_or(false);
56
57 let Key = TargetObjectClone
58 .get("Key")
59 .and_then(Value::as_str)
60 .ok_or_else(|| {
61 CommonError::InvalidArgument {
62 ArgumentName:"TargetObject.Key".to_string(),
63
64 Reason:"Expected a 'Key' string field in TargetObject.".to_string(),
65 }
66 })?
67 .to_string();
68
69 // A JSON null from the caller signals deletion to the provider.
70 let ValueToStore = if ValueToSetClone.is_null() { None } else { Some(ValueToSetClone) };
71
72 Provider.UpdateStorageValue(IsGlobal, Key, ValueToStore).await
73 })
74 }))
75}