statsig_rust/user/
statsig_user_builder.rs

1use super::unit_id::UnitID;
2use super::user_data::UserData;
3use super::StatsigUser;
4use crate::dyn_value;
5use crate::evaluation::dynamic_value::DynamicValue;
6use std::collections::HashMap;
7
8pub struct StatsigUserBuilder {
9    pub user_id: Option<UnitID>,
10    pub custom_ids: Option<HashMap<String, UnitID>>,
11
12    pub email: Option<DynamicValue>,
13    pub ip: Option<DynamicValue>,
14    pub user_agent: Option<DynamicValue>,
15    pub country: Option<DynamicValue>,
16    pub locale: Option<DynamicValue>,
17    pub app_version: Option<DynamicValue>,
18
19    pub custom: Option<HashMap<String, DynamicValue>>,
20    pub private_attributes: Option<HashMap<String, DynamicValue>>,
21
22    pub statsig_environment: Option<HashMap<String, DynamicValue>>,
23}
24
25impl StatsigUserBuilder {
26    #[must_use]
27    pub fn new_with_user_id(user_id: impl Into<UnitID>) -> Self {
28        Self {
29            user_id: Some(user_id.into()),
30            ..Self::new()
31        }
32    }
33
34    #[must_use]
35    pub fn new_with_custom_ids<K, U>(custom_ids: HashMap<K, U>) -> Self
36    where
37        K: Into<String>,
38        U: Into<UnitID>,
39    {
40        Self::new().custom_ids(Some(custom_ids))
41    }
42
43    fn new() -> Self {
44        Self {
45            user_id: None,
46            email: None,
47            ip: None,
48            user_agent: None,
49            country: None,
50            locale: None,
51            app_version: None,
52            custom: None,
53            private_attributes: None,
54            custom_ids: None,
55            statsig_environment: None,
56        }
57    }
58
59    pub fn user_id(mut self, user_id: Option<impl Into<UnitID>>) -> Self {
60        if let Some(user_id) = user_id {
61            self.user_id = Some(user_id.into());
62        }
63        self
64    }
65
66    pub fn custom_ids(
67        mut self,
68        custom_ids: Option<HashMap<impl Into<String>, impl Into<UnitID>>>,
69    ) -> Self {
70        if let Some(custom_ids) = custom_ids {
71            self.custom_ids = Some(
72                custom_ids
73                    .into_iter()
74                    .map(|(k, v)| (k.into(), v.into()))
75                    .collect(),
76            );
77        }
78        self
79    }
80
81    pub fn email(mut self, email: Option<String>) -> Self {
82        if let Some(email) = email {
83            self.email = Some(dyn_value!(email));
84        }
85        self
86    }
87
88    pub fn ip(mut self, ip: Option<String>) -> Self {
89        if let Some(ip) = ip {
90            self.ip = Some(dyn_value!(ip));
91        }
92        self
93    }
94
95    pub fn user_agent(mut self, user_agent: Option<String>) -> Self {
96        if let Some(user_agent) = user_agent {
97            self.user_agent = Some(dyn_value!(user_agent));
98        }
99        self
100    }
101
102    pub fn country(mut self, country: Option<String>) -> Self {
103        if let Some(country) = country {
104            self.country = Some(dyn_value!(country));
105        }
106        self
107    }
108
109    pub fn locale(mut self, locale: Option<String>) -> Self {
110        if let Some(locale) = locale {
111            self.locale = Some(dyn_value!(locale));
112        }
113        self
114    }
115
116    pub fn app_version(mut self, app_version: Option<String>) -> Self {
117        if let Some(app_version) = app_version {
118            self.app_version = Some(dyn_value!(app_version));
119        }
120        self
121    }
122
123    pub fn statsig_environment(
124        mut self,
125        statsig_environment: Option<HashMap<String, String>>,
126    ) -> Self {
127        if let Some(statsig_environment) = statsig_environment {
128            self.statsig_environment = Some(convert_str_map_to_dyn_values(statsig_environment));
129        }
130        self
131    }
132
133    // todo: support HashMap<String, String | Number | Boolean | Array<String>>
134    pub fn custom_from_str_map(mut self, custom: Option<HashMap<String, String>>) -> Self {
135        if let Some(custom) = custom {
136            self.custom = Some(convert_str_map_to_dyn_values(custom));
137        }
138        self
139    }
140
141    pub fn custom(mut self, custom: Option<HashMap<String, DynamicValue>>) -> Self {
142        if let Some(custom) = custom {
143            self.custom = Some(custom);
144        }
145        self
146    }
147
148    // todo: support HashMap<String, String | Number | Boolean | Array<String>>
149    pub fn private_attributes_from_str_map(
150        mut self,
151        private_attributes: Option<HashMap<String, String>>,
152    ) -> Self {
153        if let Some(private_attributes) = private_attributes {
154            self.private_attributes = Some(convert_str_map_to_dyn_values(private_attributes));
155        }
156        self
157    }
158
159    pub fn private_attributes(
160        mut self,
161        private_attributes: Option<HashMap<String, DynamicValue>>,
162    ) -> Self {
163        if let Some(private_attributes) = private_attributes {
164            self.private_attributes = Some(private_attributes);
165        }
166        self
167    }
168
169    pub fn build(self) -> StatsigUser {
170        let data = UserData {
171            user_id: self.user_id.map(|u| u.into()),
172            email: self.email,
173            ip: self.ip,
174            user_agent: self.user_agent,
175            country: self.country,
176            locale: self.locale,
177            app_version: self.app_version,
178            custom: self.custom,
179            private_attributes: self.private_attributes,
180            statsig_environment: self.statsig_environment,
181            custom_ids: self
182                .custom_ids
183                .map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect()),
184        };
185
186        StatsigUser::new(data)
187    }
188}
189
190fn convert_str_map_to_dyn_values(
191    custom_ids: HashMap<String, String>,
192) -> HashMap<String, DynamicValue> {
193    custom_ids
194        .into_iter()
195        .map(|(k, v)| (k, dyn_value!(v)))
196        .collect()
197}