diff --git a/examples/demo.rs b/examples/demo.rs index 6aa7d37..c88f5be 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -14,12 +14,12 @@ use std::{collections::HashMap, env, thread, time::Duration}; -use appconfiguration_rust_sdk::{client::AppConfigurationClient, AttrValue, Entity, Feature, Property}; +use appconfiguration_rust_sdk::{ + AppConfigurationClient, AttrValue, Entity, Feature, Property, Value, +}; use dotenvy::dotenv; use std::error::Error; -type Result = std::result::Result>; - #[derive(Debug)] struct CustomerEntity { id: String, @@ -33,8 +33,6 @@ impl Entity for CustomerEntity { } fn get_attributes(&self) -> HashMap { - use AttrValue; - HashMap::from_iter(vec![ ("city".to_string(), AttrValue::String(self.city.clone())), ("radius".to_string(), AttrValue::Numeric(self.radius as f64)), @@ -42,7 +40,7 @@ impl Entity for CustomerEntity { } } -fn main() -> Result<()> { +fn main() -> std::result::Result<(), Box> { dotenv().ok(); let region = env::var("REGION").expect("REGION should be set."); let guid = env::var("GUID").expect("GUID should be set."); @@ -70,13 +68,15 @@ fn main() -> Result<()> { match client.get_feature_proxy(&feature_id) { Ok(feature) => { println!("Feature name: {}", feature.get_name()?); - println!("Feature id: {}", feature.get_id()); - println!("Feature data type: {}", feature.get_data_type()?); + let value = feature.get_value(&entity)?; + let data_type = match &value { + Value::Numeric(_) => "Numeric", + Value::String(_) => "String", + Value::Boolean(_) => "Boolean", + }; + println!("Feature data type: {}", data_type); println!("Is feature enabled: {}", feature.is_enabled()?); - println!( - "Feature evaluated value is: {:?}", - feature.get_value(&entity)? - ); + println!("Feature evaluated value is: {value:?}"); } Err(error) => { println!("There was an error getting the Feature Flag. Error {error}",); @@ -87,12 +87,14 @@ fn main() -> Result<()> { match client.get_property_proxy(&property_id) { Ok(property) => { println!("Property name: {}", property.get_name()?); - println!("Property id: {}", property.get_id()); - println!("Property data type: {}", property.get_data_type()?); - println!( - "Property evaluated value is: {:?}", - property.get_value(&entity)? - ); + let value = property.get_value(&entity)?; + let data_type = match &value { + Value::Numeric(_) => "Numeric", + Value::String(_) => "String", + Value::Boolean(_) => "Boolean", + }; + println!("Property data type: {data_type}"); + println!("Property evaluated value is: {value:?}"); } Err(error) => { println!("There was an error getting the Property. Error {error}",); diff --git a/src/client/feature_proxy.rs b/src/client/feature_proxy.rs index 4a1786c..eab0762 100644 --- a/src/client/feature_proxy.rs +++ b/src/client/feature_proxy.rs @@ -17,7 +17,7 @@ use std::io::Cursor; use murmur3::murmur3_32; use crate::entity::Entity; -use crate::Feature; +use crate::{Feature, Value}; use super::feature_snapshot::FeatureSnapshot; use super::AppConfigurationClient; @@ -38,29 +38,15 @@ impl<'a> FeatureProxy<'a> { } impl<'a> Feature for FeatureProxy<'a> { - fn get_id(&self) -> &str { - &self.feature_id - } - fn get_name(&self) -> crate::errors::Result { self.client.get_feature(&self.feature_id)?.get_name() } - fn get_data_type(&self) -> crate::errors::Result { - self.client.get_feature(&self.feature_id)?.get_data_type() - } - fn is_enabled(&self) -> crate::errors::Result { self.client.get_feature(&self.feature_id)?.is_enabled() } - fn get_enabled_value(&self) -> crate::errors::Result { - self.client - .get_feature(&self.feature_id)? - .get_enabled_value() - } - - fn get_value(&self, entity: &impl Entity) -> crate::errors::Result { + fn get_value(&self, entity: &impl Entity) -> crate::errors::Result { self.client.get_feature(&self.feature_id)?.get_value(entity) } } diff --git a/src/client/feature_snapshot.rs b/src/client/feature_snapshot.rs index c608924..f3881a3 100644 --- a/src/client/feature_snapshot.rs +++ b/src/client/feature_snapshot.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::client::value::{NumericValue, Value}; +use crate::value::{NumericValue, Value}; use crate::entity::Entity; use crate::Feature; use std::collections::HashMap; @@ -102,26 +102,14 @@ impl FeatureSnapshot { } impl Feature for FeatureSnapshot { - fn get_id(&self) -> &str { - &self.feature.feature_id - } - fn get_name(&self) -> Result { Ok(self.feature.name.clone()) } - fn get_data_type(&self) -> Result { - Ok(self.feature.kind) - } - fn is_enabled(&self) -> Result { Ok(self.feature.enabled) } - fn get_enabled_value(&self) -> Result { - Ok(self.feature.enabled_value.clone()) - } - fn get_value(&self, entity: &impl Entity) -> Result { let model_value = self.evaluate_feature_for_entity(entity)?; @@ -151,11 +139,8 @@ impl Feature for FeatureSnapshot { pub mod tests { use super::*; - use crate::{ - entity, - models::{ConfigValue, Segment, SegmentRule, Segments, TargetingRule, ValueKind}, - AttrValue, - }; + use crate::entity::AttrValue; + use crate::models::{ConfigValue, Segment, SegmentRule, Segments, TargetingRule, ValueKind}; use rstest::rstest; #[rstest] diff --git a/src/client/mod.rs b/src/client/mod.rs index b009efc..a4d5d6a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -15,12 +15,12 @@ mod app_configuration_client; pub(crate) mod cache; -pub mod feature_snapshot; +pub(crate) mod feature_snapshot; pub(crate) mod feature_proxy; pub(crate) mod http; -pub mod property_snapshot; +pub(crate) mod property_snapshot; pub(crate) mod property_proxy; -pub mod value; + pub use app_configuration_client::AppConfigurationClient; diff --git a/src/client/property_proxy.rs b/src/client/property_proxy.rs index 50475fe..42dd72a 100644 --- a/src/client/property_proxy.rs +++ b/src/client/property_proxy.rs @@ -14,10 +14,10 @@ use crate::Property; -use crate::entity::Entity; - use super::property_snapshot::PropertySnapshot; use super::AppConfigurationClient; +use crate::value::Value; +use crate::Entity; pub struct PropertyProxy<'a> { client: &'a AppConfigurationClient, @@ -38,25 +38,11 @@ impl<'a> PropertyProxy<'a> { } impl<'a> Property for PropertyProxy<'a> { - fn get_id(&self) -> &str { - &self.property_id - } - fn get_name(&self) -> crate::errors::Result { self.client.get_property(&self.property_id)?.get_name() } - fn get_data_type(&self) -> crate::errors::Result { - self.client.get_property(&self.property_id)?.get_data_type() - } - - fn get_value_default(&self) -> crate::errors::Result { - self.client - .get_property(&self.property_id)? - .get_value_default() - } - - fn get_value(&self, entity: &impl Entity) -> crate::errors::Result { + fn get_value(&self, entity: &impl Entity) -> crate::errors::Result { self.client .get_property(&self.property_id)? .get_value(entity) diff --git a/src/client/property_snapshot.rs b/src/client/property_snapshot.rs index 649cf88..42f66de 100644 --- a/src/client/property_snapshot.rs +++ b/src/client/property_snapshot.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::client::value::{NumericValue, Value}; +use crate::value::{NumericValue, Value}; use crate::entity::Entity; use crate::Property; use std::collections::HashMap; @@ -63,22 +63,10 @@ impl PropertySnapshot { } impl Property for PropertySnapshot { - fn get_id(&self) -> &str { - &self.property.property_id - } - fn get_name(&self) -> Result { Ok(self.property.name.clone()) } - fn get_data_type(&self) -> Result { - Ok(self.property.kind) - } - - fn get_value_default(&self) -> Result { - Ok(self.property.value.clone()) - } - fn get_value(&self, entity: &impl Entity) -> Result { let model_value = self.evaluate_feature_for_entity(entity)?; @@ -104,14 +92,11 @@ impl Property for PropertySnapshot { } } - #[cfg(test)] pub mod tests { use super::*; - use crate::{ - models::{ConfigValue, Segment, SegmentRule, Segments, TargetingRule, ValueKind}, - AttrValue, - }; + use crate::entity::AttrValue; + use crate::models::{ConfigValue, Segment, SegmentRule, Segments, TargetingRule, ValueKind}; #[test] fn test_get_value_segment_with_default_value() { diff --git a/src/errors.rs b/src/errors.rs index 5431181..e53c162 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,7 +2,7 @@ use std::sync::PoisonError; use thiserror::Error; -use crate::segment_evaluation::SegmentEvaluationError; +use crate::segment_evaluation::errors::SegmentEvaluationError; pub type Result = std::result::Result; diff --git a/src/feature.rs b/src/feature.rs index ebc77dd..031ffe5 100644 --- a/src/feature.rs +++ b/src/feature.rs @@ -12,20 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::client::value::Value; use crate::errors::Result; -use crate::Entity; +use crate::{Entity, Value}; pub trait Feature { - fn get_id(&self) -> &str; - fn get_name(&self) -> Result; - fn get_data_type(&self) -> Result; - fn is_enabled(&self) -> Result; - fn get_enabled_value(&self) -> Result; - fn get_value(&self, entity: &impl Entity) -> Result; } diff --git a/src/lib.rs b/src/lib.rs index d59e1fc..0361a76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,17 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod client; -pub mod entity; -pub mod errors; -pub mod models; -mod segment_evaluation; +mod client; +mod entity; +mod errors; mod feature; +mod models; mod property; +mod segment_evaluation; +mod value; +pub use client::AppConfigurationClient; +pub use entity::{Entity, AttrValue}; pub use feature::Feature; pub use property::Property; -pub use entity::{AttrValue, Entity}; +pub use value::Value; +pub use errors::{Result, Error}; #[cfg(test)] mod tests; diff --git a/src/models.rs b/src/models.rs index b869ae6..23fca1d 100644 --- a/src/models.rs +++ b/src/models.rs @@ -66,7 +66,7 @@ pub(crate) struct Property { } #[derive(Copy, Clone, Debug, Deserialize, PartialEq)] -pub enum ValueKind { +pub(crate) enum ValueKind { #[serde(rename(deserialize = "NUMERIC"))] Numeric, #[serde(rename(deserialize = "BOOLEAN"))] @@ -87,7 +87,7 @@ impl Display for ValueKind { } #[derive(Debug, Clone, Deserialize)] -pub struct ConfigValue(pub(crate) serde_json::Value); +pub(crate) struct ConfigValue(pub(crate) serde_json::Value); impl ConfigValue { pub fn as_i64(&self) -> Option { @@ -133,7 +133,7 @@ pub(crate) struct SegmentRule { } #[derive(Debug, Deserialize, Clone)] -pub struct TargetingRule { +pub(crate) struct TargetingRule { pub rules: Vec, pub value: ConfigValue, pub order: u32, @@ -141,19 +141,19 @@ pub struct TargetingRule { } #[derive(Debug, Deserialize, Clone)] -pub struct Segments { +pub(crate) struct Segments { pub segments: Vec, } #[cfg(test)] -pub mod tests { +pub(crate) mod tests { use super::*; use rstest::*; use std::{fs, path::PathBuf}; #[fixture] - pub fn example_configuration_enterprise() -> Configuration { + pub(crate) fn example_configuration_enterprise() -> Configuration { // Create a configuration object from the data files let mut mocked_data = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -166,7 +166,7 @@ pub mod tests { } #[fixture] - pub fn configuration_feature1_enabled() -> Configuration { + pub(crate) fn configuration_feature1_enabled() -> Configuration { Configuration { environments: vec![Environment { name: "name".to_string(), @@ -189,7 +189,7 @@ pub mod tests { } #[fixture] - pub fn configuration_property1_enabled() -> Configuration { + pub(crate) fn configuration_property1_enabled() -> Configuration { Configuration { environments: vec![Environment { name: "name".to_string(), diff --git a/src/property.rs b/src/property.rs index 30cc16c..2315b5c 100644 --- a/src/property.rs +++ b/src/property.rs @@ -12,18 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::client::value::Value; use crate::errors::Result; -use crate::Entity; +use crate::{Entity, Value}; pub trait Property { - fn get_id(&self) -> &str; - fn get_name(&self) -> Result; - fn get_data_type(&self) -> Result; - - fn get_value_default(&self) -> Result; - fn get_value(&self, entity: &impl Entity) -> Result; } diff --git a/src/segment_evaluation/mod.rs b/src/segment_evaluation/mod.rs index 48dcf0a..02c6364 100644 --- a/src/segment_evaluation/mod.rs +++ b/src/segment_evaluation/mod.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod errors; +pub(crate) mod errors; use std::collections::HashMap; @@ -20,7 +20,7 @@ use crate::entity::{AttrValue, Entity}; use crate::errors::Result; use crate::models::Segment; use crate::models::TargetingRule; -pub(crate) use errors::{CheckOperatorErrorDetail, SegmentEvaluationError}; +use errors::{CheckOperatorErrorDetail, SegmentEvaluationError}; pub(crate) fn find_applicable_segment_rule_for_entity( segments: &HashMap, @@ -164,10 +164,7 @@ fn check_operator( pub mod tests { use super::*; use crate::errors::{EntityEvaluationError, Error}; - use crate::{ - models::{ConfigValue, Segment, SegmentRule, Segments, TargetingRule}, - AttrValue, - }; + use crate::models::{ConfigValue, Segment, SegmentRule, Segments, TargetingRule}; use rstest::*; #[fixture] diff --git a/src/tests/mod.rs b/src/tests/mod.rs index ff07706..9d3d28e 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -22,9 +22,10 @@ mod test_using_example_data; use crate::client::cache::ConfigurationSnapshot; use crate::client::AppConfigurationClient; +use crate::entity::AttrValue; use crate::models::tests::example_configuration_enterprise; use crate::models::Configuration; -use crate::{AttrValue, Entity}; +use crate::Entity; use rstest::fixture; use std::sync::{Arc, Mutex}; diff --git a/src/tests/test_using_example_data.rs b/src/tests/test_using_example_data.rs index 6b4aafb..fea97a9 100644 --- a/src/tests/test_using_example_data.rs +++ b/src/tests/test_using_example_data.rs @@ -13,36 +13,32 @@ // limitations under the License. use crate::client::AppConfigurationClient; - +use crate::tests::TrivialEntity; use rstest::*; use super::client_enterprise; -use crate::{Feature, Property}; +use crate::{Feature, Property, Value}; #[rstest] fn test_get_a_specific_feature(client_enterprise: AppConfigurationClient) { - use crate::models::ValueKind; let specific_feature = client_enterprise.get_feature_proxy("f1").unwrap(); let name = specific_feature.get_name().unwrap(); - let data_type = specific_feature.get_data_type().unwrap(); let is_enabled = specific_feature.is_enabled().unwrap(); + let value = specific_feature.get_value(&TrivialEntity).unwrap(); assert_eq!(name, "F1".to_string()); - assert_eq!(data_type, ValueKind::Numeric); - assert_eq!(is_enabled, true); - assert_eq!(specific_feature.get_enabled_value().unwrap().as_i64().unwrap(), 5); + assert!(is_enabled); + assert!(matches!(value, Value::Numeric(ref v) if v.as_i64() == Some(5))); } #[rstest] fn test_get_a_specific_property(client_enterprise: AppConfigurationClient) { - use crate::models::ValueKind; let property = client_enterprise.get_property_proxy("p1").unwrap(); let name = property.get_name().unwrap(); - let data_type = property.get_data_type().unwrap(); + let value = property.get_value(&TrivialEntity).unwrap(); assert_eq!(name, "p1"); - assert_eq!(data_type, ValueKind::Numeric); - assert_eq!(property.get_value_default().unwrap().as_u64().unwrap(), 5); + assert!(matches!(value, Value::Numeric(ref v) if v.as_i64() == Some(5))); } diff --git a/src/client/value.rs b/src/value.rs similarity index 100% rename from src/client/value.rs rename to src/value.rs diff --git a/tests/test_app_config.rs b/tests/test_app_config.rs index 5ebea11..c95d466 100644 --- a/tests/test_app_config.rs +++ b/tests/test_app_config.rs @@ -15,10 +15,23 @@ use dotenvy::dotenv; use rstest::*; -use appconfiguration_rust_sdk::client::AppConfigurationClient; -use appconfiguration_rust_sdk::models::ValueKind; +use appconfiguration_rust_sdk::{ + AppConfigurationClient, AttrValue, Entity, Feature, Property, Value, +}; +use std::collections::HashMap; use std::env; -use appconfiguration_rust_sdk::{Feature, Property}; + +struct TrivialEntity; + +impl Entity for TrivialEntity { + fn get_id(&self) -> String { + "TrivialId".into() + } + + fn get_attributes(&self) -> HashMap { + HashMap::new() + } +} #[fixture] fn setup_client() -> AppConfigurationClient { @@ -48,12 +61,12 @@ fn test_get_a_specific_feature(setup_client: AppConfigurationClient) { .unwrap(); let name = specific_feature.get_name().unwrap(); - let data_type = specific_feature.get_data_type().unwrap(); + let value = specific_feature.get_value(&TrivialEntity).unwrap(); let is_enabled = specific_feature.is_enabled().unwrap(); assert_eq!(name, "test feature flag 1".to_string()); - assert_eq!(data_type, ValueKind::Boolean); - assert_eq!(is_enabled, false); + assert!(matches!(value, Value::Boolean(ref v) if v == &false)); + assert!(!is_enabled); } #[rstest] @@ -68,8 +81,8 @@ fn test_get_a_specific_property(setup_client: AppConfigurationClient) { let property = setup_client.get_property_proxy("test-property-1").unwrap(); let name = property.get_name().unwrap(); - let data_type = property.get_data_type().unwrap(); + let value = property.get_value(&TrivialEntity).unwrap(); assert_eq!(name, "Test Property 1"); - assert_eq!(data_type, ValueKind::Boolean); + assert!(matches!(value, Value::Boolean(_))); }