statsig_rust/user/
statsig_user_builder.rs

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