1use crate::dyn_value;
2use crate::evaluation::dynamic_value::DynamicValue;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6pub struct StatsigUserBuilder {
7 pub user_id: Option<DynamicValue>,
8 pub email: Option<DynamicValue>,
9 pub ip: Option<DynamicValue>,
10 pub user_agent: Option<DynamicValue>,
11 pub country: Option<DynamicValue>,
12 pub locale: Option<DynamicValue>,
13 pub app_version: Option<DynamicValue>,
14 pub custom: Option<HashMap<String, DynamicValue>>,
15 pub private_attributes: Option<HashMap<String, DynamicValue>>,
16 pub custom_ids: Option<HashMap<String, DynamicValue>>,
17}
18
19impl StatsigUserBuilder {
20 #[must_use]
21 pub fn new_with_user_id(user_id: String) -> Self {
22 Self {
23 user_id: Some(dyn_value!(user_id)),
24 ..Self::new()
25 }
26 }
27
28 #[must_use]
29 pub fn new_with_custom_ids<V>(custom_ids: HashMap<String, V>) -> Self
30 where
31 V: Into<DynamicValue>,
32 {
33 Self {
34 custom_ids: Some(custom_ids.into_iter().map(|(k, v)| (k, v.into())).collect()),
35 ..Self::new()
36 }
37 }
38
39 fn new() -> Self {
40 Self {
41 user_id: None,
42 email: None,
43 ip: None,
44 user_agent: None,
45 country: None,
46 locale: None,
47 app_version: None,
48 custom: None,
49 private_attributes: None,
50 custom_ids: None,
51 }
52 }
53
54 pub fn user_id(mut self, user_id: Option<String>) -> Self {
55 if let Some(user_id) = user_id {
56 self.user_id = Some(dyn_value!(user_id));
57 }
58 self
59 }
60
61 pub fn custom_ids(mut self, custom_ids: Option<HashMap<String, String>>) -> Self {
62 if let Some(custom_ids) = custom_ids {
63 self.custom_ids = Some(convert_str_map_to_dyn_values(custom_ids));
64 }
65 self
66 }
67
68 pub fn email(mut self, email: Option<String>) -> Self {
69 if let Some(email) = email {
70 self.email = Some(dyn_value!(email));
71 }
72 self
73 }
74
75 pub fn ip(mut self, ip: Option<String>) -> Self {
76 if let Some(ip) = ip {
77 self.ip = Some(dyn_value!(ip));
78 }
79 self
80 }
81
82 pub fn user_agent(mut self, user_agent: Option<String>) -> Self {
83 if let Some(user_agent) = user_agent {
84 self.user_agent = Some(dyn_value!(user_agent));
85 }
86 self
87 }
88
89 pub fn country(mut self, country: Option<String>) -> Self {
90 if let Some(country) = country {
91 self.country = Some(dyn_value!(country));
92 }
93 self
94 }
95
96 pub fn locale(mut self, locale: Option<String>) -> Self {
97 if let Some(locale) = locale {
98 self.locale = Some(dyn_value!(locale));
99 }
100 self
101 }
102
103 pub fn app_version(mut self, app_version: Option<String>) -> Self {
104 if let Some(app_version) = app_version {
105 self.app_version = Some(dyn_value!(app_version));
106 }
107 self
108 }
109
110 pub fn custom_from_str_map(mut self, custom: Option<HashMap<String, String>>) -> Self {
112 if let Some(custom) = custom {
113 self.custom = Some(convert_str_map_to_dyn_values(custom));
114 }
115 self
116 }
117
118 pub fn custom(mut self, custom: Option<HashMap<String, DynamicValue>>) -> Self {
119 if let Some(custom) = custom {
120 self.custom = Some(custom);
121 }
122 self
123 }
124
125 pub fn private_attributes_from_str_map(
127 mut self,
128 private_attributes: Option<HashMap<String, String>>,
129 ) -> Self {
130 if let Some(private_attributes) = private_attributes {
131 self.private_attributes = Some(convert_str_map_to_dyn_values(private_attributes));
132 }
133 self
134 }
135
136 pub fn private_attributes(
137 mut self,
138 private_attributes: Option<HashMap<String, DynamicValue>>,
139 ) -> Self {
140 if let Some(private_attributes) = private_attributes {
141 self.private_attributes = Some(private_attributes);
142 }
143 self
144 }
145
146 pub fn build(self) -> StatsigUser {
147 StatsigUser {
148 user_id: self.user_id,
149 email: self.email,
150 ip: self.ip,
151 user_agent: self.user_agent,
152 country: self.country,
153 locale: self.locale,
154 app_version: self.app_version,
155 custom: self.custom,
156 private_attributes: self.private_attributes,
157 custom_ids: self.custom_ids,
158 }
159 }
160}
161
162#[derive(Clone, Deserialize, Serialize)]
163#[serde(rename_all = "camelCase")]
164pub struct StatsigUser {
165 #[serde(rename = "userID", skip_serializing_if = "Option::is_none")]
166 pub user_id: Option<DynamicValue>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub email: Option<DynamicValue>,
170
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub ip: Option<DynamicValue>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
175 pub user_agent: Option<DynamicValue>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub country: Option<DynamicValue>,
179
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub locale: Option<DynamicValue>,
182
183 #[serde(skip_serializing_if = "Option::is_none")]
184 pub app_version: Option<DynamicValue>,
185
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub custom: Option<HashMap<String, DynamicValue>>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub private_attributes: Option<HashMap<String, DynamicValue>>,
191
192 #[serde(rename = "customIDs", skip_serializing_if = "Option::is_none")]
193 pub custom_ids: Option<HashMap<String, DynamicValue>>,
194}
195
196impl StatsigUser {
197 #[must_use]
198 pub fn with_user_id(user_id: String) -> Self {
199 StatsigUser {
200 user_id: Some(dyn_value!(user_id)),
201 ..Self::default()
202 }
203 }
204
205 #[must_use]
206 pub fn with_custom_ids<V>(custom_ids: HashMap<String, V>) -> Self
207 where
208 V: Into<DynamicValue>,
209 {
210 StatsigUser {
211 custom_ids: Some(custom_ids.into_iter().map(|(k, v)| (k, v.into())).collect()),
212 ..Self::default()
213 }
214 }
215
216 fn default() -> Self {
217 StatsigUser {
218 user_id: None,
219 email: None,
220 ip: None,
221 user_agent: None,
222 country: None,
223 locale: None,
224 app_version: None,
225 custom: None,
226 private_attributes: None,
227 custom_ids: None,
228 }
229 }
230}
231
232fn convert_str_map_to_dyn_values(
233 custom_ids: HashMap<String, String>,
234) -> HashMap<String, DynamicValue> {
235 custom_ids
236 .into_iter()
237 .map(|(k, v)| (k, dyn_value!(v)))
238 .collect()
239}