apollo_rust_client/namespace/properties.rs
1//! Properties namespace implementation for handling key-value configuration data.
2//!
3//! This module provides the `Properties` struct which wraps a `serde_json::Value` and
4//! provides methods for working with properties-style configuration data. Properties
5//! format is commonly used for application configuration where data is stored as
6//! simple key-value pairs.
7//!
8//! # Usage
9//!
10//! The `Properties` struct is typically created automatically by the namespace detection
11//! system when a namespace name has no file extension (defaulting to properties format),
12//! but can also be created directly from any `serde_json::Value`.
13//!
14//! # Supported Data Types
15//!
16//! The properties implementation supports automatic parsing of the following types:
17//! - `String` - Text values
18//! - `i64` - Integer values
19//! - `f64` - Floating-point values
20//! - `bool` - Boolean values
21//!
22//! # Examples
23//!
24//! ```ignore
25//! use serde_json::json;
26//! use apollo_client::namespace::properties::Properties;
27//!
28//! let props_data = json!({
29//! "app.name": "MyApplication",
30//! "app.version": "1.0.0",
31//! "app.port": "8080",
32//! "app.debug": "true"
33//! });
34//!
35//! let properties = Properties::from(props_data);
36//! ```
37
38use log::debug;
39use wasm_bindgen::prelude::wasm_bindgen;
40
41/// A wrapper around `serde_json::Value` for properties-style configuration data.
42///
43/// This struct provides a type-safe interface for working with properties configuration
44/// data retrieved from Apollo. Properties are typically stored as key-value pairs where
45/// all values are strings that can be parsed into various types.
46///
47/// # Thread Safety
48///
49/// This struct is `Clone` and `Debug`, making it easy to work with in concurrent
50/// environments. The underlying `serde_json::Value` is also thread-safe.
51///
52/// # Examples
53///
54/// ```ignore
55/// use serde_json::json;
56/// use apollo_client::namespace::properties::Properties;
57///
58/// let props_data = json!({
59/// "database.host": "localhost",
60/// "database.port": "5432",
61/// "database.ssl": "true"
62/// });
63///
64/// let properties = Properties::from(props_data);
65/// ```
66#[wasm_bindgen]
67#[derive(Clone, Debug)]
68pub struct Properties {
69 /// The underlying JSON value containing the properties data
70 value: serde_json::Value,
71}
72
73impl Properties {
74 /// Gets a property value and attempts to parse it into the specified type.
75 ///
76 /// This is a generic method that can parse string values into any type that
77 /// implements `FromStr`. It first retrieves the value as a string, then
78 /// attempts to parse it into the target type.
79 ///
80 /// # Type Parameters
81 ///
82 /// * `T` - The target type to parse into. Must implement `std::str::FromStr`.
83 ///
84 /// # Arguments
85 ///
86 /// * `key` - The property key to retrieve
87 ///
88 /// # Returns
89 ///
90 /// * `Some(T)` - The parsed value if the key exists and parsing succeeds
91 /// * `None` - If the key doesn't exist, the value is not a string, or parsing fails
92 ///
93 /// # Examples
94 ///
95 /// ```ignore
96 /// use serde_json::json;
97 /// use apollo_client::namespace::properties::Properties;
98 ///
99 /// let props_data = json!({"timeout": "30", "retries": "3"});
100 /// let properties = Properties::from(props_data);
101 ///
102 /// let timeout: Option<u32> = properties.get_property("timeout");
103 /// let retries: Option<i32> = properties.get_property("retries");
104 /// ```
105 #[must_use]
106 pub fn get_property<T: std::str::FromStr>(&self, key: &str) -> Option<T> {
107 debug!("Getting property for key {key}");
108
109 let value = self.value.get(key)?;
110 value.as_str().and_then(|s| s.parse::<T>().ok())
111 }
112}
113
114#[wasm_bindgen]
115impl Properties {
116 /// Get a property from the cache as a string.
117 ///
118 /// This method retrieves a property value and returns it as a `String`.
119 /// It's a convenience method that wraps `get_property::<String>()`.
120 ///
121 /// # Arguments
122 ///
123 /// * `key` - The key to get the property for.
124 ///
125 /// # Returns
126 ///
127 /// * `Some(String)` - The property value as a string if it exists
128 /// * `None` - If the key doesn't exist or the value cannot be converted to a string
129 ///
130 /// # Examples
131 ///
132 /// ```ignore
133 /// use serde_json::json;
134 /// use apollo_client::namespace::properties::Properties;
135 ///
136 /// let props_data = json!({"app.name": "MyApp"});
137 /// let properties = Properties::from(props_data);
138 ///
139 /// let app_name = properties.get_string("app.name");
140 /// assert_eq!(app_name, Some("MyApp".to_string()));
141 /// ```
142 #[must_use]
143 pub fn get_string(&self, key: &str) -> Option<String> {
144 self.get_property::<String>(key)
145 }
146
147 /// Get a property from the cache as an integer.
148 ///
149 /// This method retrieves a property value and attempts to parse it as an `i64`.
150 /// It's a convenience method that wraps `get_property::<i64>()`.
151 ///
152 /// # Arguments
153 ///
154 /// * `key` - The key to get the property for.
155 ///
156 /// # Returns
157 ///
158 /// * `Some(i64)` - The property value as an integer if it exists and can be parsed
159 /// * `None` - If the key doesn't exist or the value cannot be parsed as an integer
160 ///
161 /// # Examples
162 ///
163 /// ```ignore
164 /// use serde_json::json;
165 /// use apollo_client::namespace::properties::Properties;
166 ///
167 /// let props_data = json!({"server.port": "8080"});
168 /// let properties = Properties::from(props_data);
169 ///
170 /// let port = properties.get_int("server.port");
171 /// assert_eq!(port, Some(8080));
172 /// ```
173 #[must_use]
174 pub fn get_int(&self, key: &str) -> Option<i64> {
175 self.get_property::<i64>(key)
176 }
177
178 /// Get a property from the cache as a float.
179 ///
180 /// This method retrieves a property value and attempts to parse it as an `f64`.
181 /// It's a convenience method that wraps `get_property::<f64>()`.
182 ///
183 /// # Arguments
184 ///
185 /// * `key` - The key to get the property for.
186 ///
187 /// # Returns
188 ///
189 /// * `Some(f64)` - The property value as a float if it exists and can be parsed
190 /// * `None` - If the key doesn't exist or the value cannot be parsed as a float
191 ///
192 /// # Examples
193 ///
194 /// ```ignore
195 /// use serde_json::json;
196 /// use apollo_client::namespace::properties::Properties;
197 ///
198 /// let props_data = json!({"timeout.seconds": "30.5"});
199 /// let properties = Properties::from(props_data);
200 ///
201 /// let timeout = properties.get_float("timeout.seconds");
202 /// assert_eq!(timeout, Some(30.5));
203 /// ```
204 #[must_use]
205 pub fn get_float(&self, key: &str) -> Option<f64> {
206 self.get_property::<f64>(key)
207 }
208
209 /// Get a property from the cache as a boolean.
210 ///
211 /// This method retrieves a property value and attempts to parse it as a `bool`.
212 /// It's a convenience method that wraps `get_property::<bool>()`. The parsing
213 /// follows Rust's standard boolean parsing rules (accepts "true"/"false").
214 ///
215 /// # Arguments
216 ///
217 /// * `key` - The key to get the property for.
218 ///
219 /// # Returns
220 ///
221 /// * `Some(bool)` - The property value as a boolean if it exists and can be parsed
222 /// * `None` - If the key doesn't exist or the value cannot be parsed as a boolean
223 ///
224 /// # Examples
225 ///
226 /// ```ignore
227 /// use serde_json::json;
228 /// use apollo_client::namespace::properties::Properties;
229 ///
230 /// let props_data = json!({"debug.enabled": "true"});
231 /// let properties = Properties::from(props_data);
232 ///
233 /// let debug_enabled = properties.get_bool("debug.enabled");
234 /// assert_eq!(debug_enabled, Some(true));
235 /// ```
236 #[must_use]
237 pub fn get_bool(&self, key: &str) -> Option<bool> {
238 self.get_property::<bool>(key)
239 }
240}
241
242/// Converts a `serde_json::Value` into a `Properties` instance.
243///
244/// This implementation allows for easy creation of `Properties` instances from
245/// raw JSON data, typically used by the namespace detection system. The JSON
246/// value is expected to be an object where keys are property names and values
247/// are the property values (typically strings).
248///
249/// # Examples
250///
251/// ```ignore
252/// use serde_json::json;
253/// use apollo_client::namespace::properties::Properties;
254///
255/// let props_data = json!({
256/// "app.name": "MyApp",
257/// "app.version": "1.0.0"
258/// });
259///
260/// let properties = Properties::from(props_data);
261/// ```
262impl From<serde_json::Value> for Properties {
263 fn from(value: serde_json::Value) -> Self {
264 Self { value }
265 }
266}