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