Skip to main content

statsig_rust/user/
statsig_user_builder.rs

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