Skip to content

Commit dcd114f

Browse files
committed
Declare a Property trait, implement PropertyProxy in terms of inner Property
Signed-off-by: Javier G. Sogo <[email protected]>
1 parent 4645800 commit dcd114f

File tree

10 files changed

+124
-156
lines changed

10 files changed

+124
-156
lines changed

examples/demo.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
use std::{collections::HashMap, env, thread, time::Duration};
1616

17-
use appconfiguration_rust_sdk::{client::AppConfigurationClient, AttrValue, Entity, Feature};
17+
use appconfiguration_rust_sdk::{client::AppConfigurationClient, AttrValue, Entity, Feature, Property};
1818
use dotenvy::dotenv;
1919
use std::error::Error;
2020

@@ -86,12 +86,12 @@ fn main() -> Result<()> {
8686
println!("\n\nPROPERTY OPERATIONS\n");
8787
match client.get_property_proxy(&property_id) {
8888
Ok(property) => {
89-
println!("Property name: {}", property.get_name());
89+
println!("Property name: {}", property.get_name()?);
9090
println!("Property id: {}", property.get_id());
91-
println!("Property data type: {}", property.get_data_type());
91+
println!("Property data type: {}", property.get_data_type()?);
9292
println!(
93-
"Property evaluated value is: {}",
94-
property.get_current_value(&entity)
93+
"Property evaluated value is: {:?}",
94+
property.get_value(&entity)?
9595
);
9696
}
9797
Err(error) => {

src/client/app_configuration_client.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::client::cache::ConfigurationSnapshot;
1616
use crate::client::feature_snapshot::FeatureSnapshot;
1717
pub use crate::client::feature_proxy::FeatureProxy;
1818
use crate::client::http;
19-
use crate::client::property::Property;
19+
use crate::client::property_snapshot::PropertySnapshot;
2020
pub use crate::client::property_proxy::PropertyProxy;
2121
use crate::errors::{ConfigurationAccessError, Error, Result};
2222
use crate::models::Segment;
@@ -246,7 +246,7 @@ impl AppConfigurationClient {
246246
.collect())
247247
}
248248

249-
pub fn get_property(&self, property_id: &str) -> Result<Property> {
249+
pub fn get_property(&self, property_id: &str) -> Result<PropertySnapshot> {
250250
let config_snapshot = self.latest_config_snapshot.lock()?;
251251

252252
// Get the property from the snapshot
@@ -284,18 +284,15 @@ impl AppConfigurationClient {
284284
segments
285285
};
286286

287-
Ok(Property::new(property.clone(), segments))
287+
Ok(PropertySnapshot::new(property.clone(), segments))
288288
}
289289

290290
/// Searches for the property `property_id` inside the current configured
291291
/// collection, and environment.
292292
///
293293
/// Return `Ok(property)` if the feature exists or `Err` if it does not.
294294
pub fn get_property_proxy(&self, property_id: &str) -> Result<PropertyProxy> {
295-
Ok(PropertyProxy::new(
296-
self.latest_config_snapshot.clone(),
297-
property_id.to_string(),
298-
))
295+
Ok(PropertyProxy::new(self, property_id.to_string()))
299296
}
300297

301298
fn update_cache_in_background(

src/client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub(crate) mod cache;
1818
pub mod feature_snapshot;
1919
pub(crate) mod feature_proxy;
2020
pub(crate) mod http;
21-
pub mod property;
21+
pub mod property_snapshot;
2222
pub(crate) mod property_proxy;
2323
pub mod value;
2424

src/client/property_proxy.rs

Lines changed: 27 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -12,134 +12,53 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use std::sync::{Arc, Mutex};
16-
17-
use crate::{
18-
client::cache::ConfigurationSnapshot, models,
19-
segment_evaluation::find_applicable_segment_rule_for_entity,
20-
};
15+
use crate::Property;
2116

2217
use crate::entity::Entity;
2318

24-
use crate::errors::ConfigurationAccessError;
25-
26-
const MISSING_PROPERTY_ERROR_MSG: &str = "The property should exist in the index. It should have been validated in `AppConfigurationClient::get_property()`.";
19+
use super::property_snapshot::PropertySnapshot;
20+
use super::AppConfigurationClient;
2721

28-
/// A property in a collection and environment. Use the `get_property()`
29-
/// method of the `AppConfigurationClient` to create instances of properties.
30-
#[derive(Debug)]
31-
pub struct PropertyProxy {
32-
configuration_snapshot: Arc<Mutex<ConfigurationSnapshot>>,
22+
pub struct PropertyProxy<'a> {
23+
client: &'a AppConfigurationClient,
3324
property_id: String,
3425
}
3526

36-
impl PropertyProxy {
37-
pub(crate) fn new(
38-
configuration_snapshot: Arc<Mutex<ConfigurationSnapshot>>,
39-
property_id: String,
40-
) -> Self {
41-
PropertyProxy {
42-
configuration_snapshot,
27+
impl<'a> PropertyProxy<'a> {
28+
pub(crate) fn new(client: &'a AppConfigurationClient, property_id: String) -> Self {
29+
Self {
30+
client,
4331
property_id,
4432
}
4533
}
4634

47-
/// Returns the name of the property.
48-
pub fn get_name(&self) -> String {
49-
self.configuration_snapshot
50-
.lock()
51-
.unwrap_or_else(|_| panic!("{}", ConfigurationAccessError::LockAcquisitionError))
52-
.get_property(&self.property_id)
53-
.expect(MISSING_PROPERTY_ERROR_MSG)
54-
.name
55-
.clone()
56-
}
57-
58-
/// Returns the value of the property as a `models::ConfigValue`.
59-
pub fn get_value(&self) -> models::ConfigValue {
60-
self.configuration_snapshot
61-
.lock()
62-
.unwrap_or_else(|_| panic!("{}", ConfigurationAccessError::LockAcquisitionError))
63-
.get_property(&self.property_id)
64-
.expect(MISSING_PROPERTY_ERROR_MSG)
65-
.value
66-
.clone()
67-
}
68-
69-
/// Returns the id of the property.
70-
pub fn get_id(&self) -> String {
71-
self.configuration_snapshot
72-
.lock()
73-
.unwrap_or_else(|_| panic!("{}", ConfigurationAccessError::LockAcquisitionError))
74-
.get_property(&self.property_id)
75-
.expect(MISSING_PROPERTY_ERROR_MSG)
76-
.property_id
77-
.clone()
35+
pub fn snapshot(&self) -> crate::errors::Result<PropertySnapshot> {
36+
self.client.get_property(&self.property_id)
7837
}
38+
}
7939

80-
/// Returns the data type as a member of the `models::ValueKind` enumeration.
81-
pub fn get_data_type(&self) -> models::ValueKind {
82-
self.configuration_snapshot
83-
.lock()
84-
.unwrap_or_else(|_| panic!("{}", ConfigurationAccessError::LockAcquisitionError))
85-
.get_property(&self.property_id)
86-
.expect(MISSING_PROPERTY_ERROR_MSG)
87-
.kind
40+
impl<'a> Property for PropertyProxy<'a> {
41+
fn get_id(&self) -> &str {
42+
&self.property_id
8843
}
8944

90-
/// Gets the `Some(data_format)` if the feature data type is
91-
/// `models::ValueKind::STRING`, or `None` otherwise.
92-
pub fn get_data_format(&self) -> Option<String> {
93-
self.configuration_snapshot
94-
.lock()
95-
.unwrap_or_else(|_| panic!("{}", ConfigurationAccessError::LockAcquisitionError))
96-
.get_property(&self.property_id)
97-
.expect(MISSING_PROPERTY_ERROR_MSG)
98-
.format
99-
.clone()
45+
fn get_name(&self) -> crate::errors::Result<String> {
46+
self.client.get_property(&self.property_id)?.get_name()
10047
}
10148

102-
/// Returns the targeting rules for the property. I.e.: what value to
103-
/// associate with an entity, and under what circumstances it applies.
104-
pub fn get_targeting_rules(&self) -> Vec<models::TargetingRule> {
105-
self.configuration_snapshot
106-
.lock()
107-
.unwrap_or_else(|_| panic!("{}", ConfigurationAccessError::LockAcquisitionError))
108-
.get_property(&self.property_id)
109-
.expect(MISSING_PROPERTY_ERROR_MSG)
110-
.segment_rules
111-
.clone()
49+
fn get_data_type(&self) -> crate::errors::Result<crate::models::ValueKind> {
50+
self.client.get_property(&self.property_id)?.get_data_type()
11251
}
11352

114-
/// Evaluates the property for `entity` and returns the evaluation as a
115-
/// `models::ConfigValue`.
116-
pub fn get_current_value(&self, entity: &impl Entity) -> models::ConfigValue {
117-
self.evaluate_feature_for_entity(entity)
53+
fn get_value_default(&self) -> crate::errors::Result<crate::models::ConfigValue> {
54+
self.client
55+
.get_property(&self.property_id)?
56+
.get_value_default()
11857
}
11958

120-
fn evaluate_feature_for_entity(&self, entity: &impl Entity) -> models::ConfigValue {
121-
let segment_rule = find_applicable_segment_rule_for_entity(
122-
&self
123-
.configuration_snapshot
124-
.lock()
125-
.unwrap_or_else(|e| panic!("Failed to acquire configuration snapshot lock: {e}"))
126-
.segments,
127-
self.get_targeting_rules().into_iter(),
128-
entity,
129-
)
130-
.unwrap_or_else(|e| panic!("Failed to evaluate segment rules: {e}"));
131-
if let Some(segment_rule) = segment_rule {
132-
self.resolve_value(&segment_rule)
133-
} else {
134-
self.get_value()
135-
}
136-
}
137-
138-
fn resolve_value(&self, segment_rule: &models::TargetingRule) -> models::ConfigValue {
139-
if segment_rule.value.is_default() {
140-
self.get_value()
141-
} else {
142-
segment_rule.value.clone()
143-
}
59+
fn get_value(&self, entity: &impl Entity) -> crate::errors::Result<super::value::Value> {
60+
self.client
61+
.get_property(&self.property_id)?
62+
.get_value(entity)
14463
}
14564
}

src/client/property.rs renamed to src/client/property_snapshot.rs

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,26 @@
1414

1515
use crate::client::value::{NumericValue, Value};
1616
use crate::entity::Entity;
17+
use crate::Property;
1718
use std::collections::HashMap;
1819

1920
use crate::errors::{Error, Result};
2021
use crate::segment_evaluation::find_applicable_segment_rule_for_entity;
2122

2223
#[derive(Debug)]
23-
pub struct Property {
24+
pub struct PropertySnapshot {
2425
property: crate::models::Property,
2526
segments: HashMap<String, crate::models::Segment>,
2627
}
2728

28-
impl Property {
29+
impl PropertySnapshot {
2930
pub(crate) fn new(
3031
property: crate::models::Property,
3132
segments: HashMap<String, crate::models::Segment>,
3233
) -> Self {
3334
Self { property, segments }
3435
}
3536

36-
pub fn get_value(&self, entity: &impl Entity) -> Result<Value> {
37-
let model_value = self.evaluate_feature_for_entity(entity)?;
38-
39-
let value = match self.property.kind {
40-
crate::models::ValueKind::Numeric => {
41-
Value::Numeric(NumericValue(model_value.0.clone()))
42-
}
43-
crate::models::ValueKind::Boolean => Value::Boolean(
44-
model_value
45-
.0
46-
.as_bool()
47-
.ok_or(Error::ProtocolError("Expected Boolean".into()))?,
48-
),
49-
crate::models::ValueKind::String => Value::String(
50-
model_value
51-
.0
52-
.as_str()
53-
.ok_or(Error::ProtocolError("Expected String".into()))?
54-
.to_string(),
55-
),
56-
};
57-
Ok(value)
58-
}
59-
6037
fn evaluate_feature_for_entity(
6138
&self,
6239
entity: &impl Entity,
@@ -85,6 +62,49 @@ impl Property {
8562
}
8663
}
8764

65+
impl Property for PropertySnapshot {
66+
fn get_id(&self) -> &str {
67+
&self.property.property_id
68+
}
69+
70+
fn get_name(&self) -> Result<String> {
71+
Ok(self.property.name.clone())
72+
}
73+
74+
fn get_data_type(&self) -> Result<crate::models::ValueKind> {
75+
Ok(self.property.kind)
76+
}
77+
78+
fn get_value_default(&self) -> Result<crate::models::ConfigValue> {
79+
Ok(self.property.value.clone())
80+
}
81+
82+
fn get_value(&self, entity: &impl Entity) -> Result<Value> {
83+
let model_value = self.evaluate_feature_for_entity(entity)?;
84+
85+
let value = match self.property.kind {
86+
crate::models::ValueKind::Numeric => {
87+
Value::Numeric(NumericValue(model_value.0.clone()))
88+
}
89+
crate::models::ValueKind::Boolean => Value::Boolean(
90+
model_value
91+
.0
92+
.as_bool()
93+
.ok_or(Error::ProtocolError("Expected Boolean".into()))?,
94+
),
95+
crate::models::ValueKind::String => Value::String(
96+
model_value
97+
.0
98+
.as_str()
99+
.ok_or(Error::ProtocolError("Expected String".into()))?
100+
.to_string(),
101+
),
102+
};
103+
Ok(value)
104+
}
105+
}
106+
107+
88108
#[cfg(test)]
89109
pub mod tests {
90110
use super::*;
@@ -111,7 +131,7 @@ pub mod tests {
111131
}],
112132
tags: None,
113133
};
114-
let property = Property::new(
134+
let property = PropertySnapshot::new(
115135
inner_property,
116136
HashMap::from([(
117137
"some_segment_id_1".into(),
@@ -166,7 +186,7 @@ pub mod tests {
166186
],
167187
tags: None,
168188
};
169-
let property = Property::new(
189+
let property = PropertySnapshot::new(
170190
inner_property,
171191
HashMap::from([
172192
(

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ pub mod errors;
1818
pub mod models;
1919
mod segment_evaluation;
2020
mod feature;
21+
mod property;
2122

2223
pub use feature::Feature;
24+
pub use property::Property;
2325
pub use entity::{AttrValue, Entity};
2426

2527
#[cfg(test)]

src/property.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// (C) Copyright IBM Corp. 2024.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
use crate::client::value::Value;
16+
use crate::errors::Result;
17+
use crate::Entity;
18+
19+
pub trait Property {
20+
fn get_id(&self) -> &str;
21+
22+
fn get_name(&self) -> Result<String>;
23+
24+
fn get_data_type(&self) -> Result<crate::models::ValueKind>;
25+
26+
fn get_value_default(&self) -> Result<crate::models::ConfigValue>;
27+
28+
fn get_value(&self, entity: &impl Entity) -> Result<Value>;
29+
}

0 commit comments

Comments
 (0)