Skip to main content

scconfig_rs/
environment.rs

1use std::collections::BTreeMap;
2
3use serde::de::DeserializeOwned;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::{
8    Result, ScalarCoercion,
9    binding::{coerce_json_value, deserialize_json_value, nested_value_from_flat_map},
10};
11
12/// Spring Cloud Config `Environment` payload returned by `/{application}/{profile}`.
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct Environment {
15    /// Application name resolved by the Config Server.
16    pub name: String,
17    /// Active profiles returned by the Config Server.
18    #[serde(default)]
19    pub profiles: Vec<String>,
20    /// Git label, branch, tag, or commit used by the Config Server.
21    #[serde(default)]
22    pub label: Option<String>,
23    /// Backend version metadata, when available.
24    #[serde(default)]
25    pub version: Option<String>,
26    /// Backend state metadata, when available.
27    #[serde(default)]
28    pub state: Option<String>,
29    /// Ordered property sources. Earlier entries have higher precedence.
30    #[serde(rename = "propertySources", default)]
31    pub property_sources: Vec<PropertySource>,
32}
33
34impl Environment {
35    /// Returns the effective flat property map after applying Spring property-source precedence.
36    ///
37    /// Spring Cloud Config returns higher-precedence property sources earlier in the list.
38    /// This method applies them accordingly and returns the final flat key-value map.
39    pub fn effective_properties(&self) -> BTreeMap<String, Value> {
40        let mut merged = BTreeMap::new();
41
42        for source in self.property_sources.iter().rev() {
43            for (key, value) in &source.source {
44                merged.insert(key.clone(), value.clone());
45            }
46        }
47
48        merged
49    }
50
51    /// Converts the effective flat property map into a nested JSON value without scalar coercion.
52    pub fn to_value(&self) -> Value {
53        self.to_value_with_coercion(ScalarCoercion::None)
54    }
55
56    /// Converts the effective flat property map into a nested JSON value.
57    pub fn to_value_with_coercion(&self, coercion: ScalarCoercion) -> Value {
58        nested_value_from_flat_map(self.effective_properties(), coercion)
59    }
60
61    /// Deserializes the effective configuration into a Rust type using smart scalar coercion.
62    pub fn deserialize<T>(&self) -> Result<T>
63    where
64        T: DeserializeOwned,
65    {
66        self.deserialize_with_coercion(ScalarCoercion::Smart)
67    }
68
69    /// Deserializes the effective configuration into a Rust type using the requested coercion mode.
70    pub fn deserialize_with_coercion<T>(&self, coercion: ScalarCoercion) -> Result<T>
71    where
72        T: DeserializeOwned,
73    {
74        deserialize_json_value(
75            coerce_json_value(self.to_value_with_coercion(ScalarCoercion::None), coercion),
76            format!("environment `{}`", self.name),
77        )
78    }
79
80    /// Deserializes the effective configuration into a Rust type without scalar coercion.
81    pub fn deserialize_strict<T>(&self) -> Result<T>
82    where
83        T: DeserializeOwned,
84    {
85        self.deserialize_with_coercion(ScalarCoercion::None)
86    }
87}
88
89/// A single Spring property source within an [`Environment`].
90#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
91pub struct PropertySource {
92    /// Property source name as reported by Spring Cloud Config.
93    pub name: String,
94    /// Flat key-value properties from the source.
95    #[serde(default)]
96    pub source: BTreeMap<String, Value>,
97}