stateset_embedded/
customers.rs1use stateset_core::{
4 AddressType, CreateCustomer, CreateCustomerAddress, Customer, CustomerAddress, CustomerFilter,
5 CustomerId, Result, UpdateCustomer, Validate,
6};
7use stateset_db::Database;
8use stateset_observability::Metrics;
9use std::sync::Arc;
10use uuid::Uuid;
11
12#[cfg(feature = "events")]
13use crate::events::EventSystem;
14#[cfg(feature = "events")]
15use stateset_core::CommerceEvent;
16
17pub struct Customers {
19 db: Arc<dyn Database>,
20 metrics: Metrics,
21 #[cfg(feature = "events")]
22 event_system: Arc<EventSystem>,
23}
24
25impl std::fmt::Debug for Customers {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 f.debug_struct("Customers").finish_non_exhaustive()
28 }
29}
30
31impl Customers {
32 #[cfg(feature = "events")]
33 pub(crate) fn new(
34 db: Arc<dyn Database>,
35 event_system: Arc<EventSystem>,
36 metrics: Metrics,
37 ) -> Self {
38 Self { db, metrics, event_system }
39 }
40
41 #[cfg(not(feature = "events"))]
42 pub(crate) fn new(db: Arc<dyn Database>, metrics: Metrics) -> Self {
43 Self { db, metrics }
44 }
45
46 #[cfg(feature = "events")]
47 fn emit(&self, event: CommerceEvent) {
48 self.event_system.emit(event);
49 }
50
51 #[cfg(feature = "events")]
52 fn fields_changed(input: &UpdateCustomer) -> Vec<String> {
53 let mut fields = Vec::new();
54 if input.email.is_some() {
55 fields.push("email".to_string());
56 }
57 if input.first_name.is_some() {
58 fields.push("first_name".to_string());
59 }
60 if input.last_name.is_some() {
61 fields.push("last_name".to_string());
62 }
63 if input.phone.is_some() {
64 fields.push("phone".to_string());
65 }
66 if input.status.is_some() {
67 fields.push("status".to_string());
68 }
69 if input.accepts_marketing.is_some() {
70 fields.push("accepts_marketing".to_string());
71 }
72 if input.tags.is_some() {
73 fields.push("tags".to_string());
74 }
75 if input.metadata.is_some() {
76 fields.push("metadata".to_string());
77 }
78 fields
79 }
80
81 pub fn create(&self, input: CreateCustomer) -> Result<Customer> {
98 input.validate()?;
100 let customer = self.db.customers().create(input)?;
101 self.metrics.record_customer_created(&customer.id.to_string());
102 #[cfg(feature = "events")]
103 {
104 self.emit(CommerceEvent::CustomerCreated {
105 customer_id: customer.id,
106 email: customer.email.clone(),
107 timestamp: customer.created_at,
108 });
109 }
110 Ok(customer)
111 }
112
113 pub fn get(&self, id: CustomerId) -> Result<Option<Customer>> {
115 self.db.customers().get(id)
116 }
117
118 pub fn get_by_email(&self, email: &str) -> Result<Option<Customer>> {
120 self.db.customers().get_by_email(email)
121 }
122
123 pub fn update(&self, id: CustomerId, input: UpdateCustomer) -> Result<Customer> {
125 #[cfg(feature = "events")]
126 let previous = self.db.customers().get(id)?;
127 #[cfg(feature = "events")]
128 let fields_changed = Self::fields_changed(&input);
129
130 let updated = self.db.customers().update(id, input)?;
131
132 #[cfg(feature = "events")]
133 {
134 if !fields_changed.is_empty() {
135 self.emit(CommerceEvent::CustomerUpdated {
136 customer_id: updated.id,
137 fields_changed,
138 timestamp: updated.updated_at,
139 });
140 }
141
142 if let Some(previous) = previous {
143 if previous.status != updated.status {
144 self.emit(CommerceEvent::CustomerStatusChanged {
145 customer_id: updated.id,
146 from_status: previous.status,
147 to_status: updated.status,
148 timestamp: updated.updated_at,
149 });
150 }
151 }
152 }
153
154 Ok(updated)
155 }
156
157 pub fn list(&self, filter: CustomerFilter) -> Result<Vec<Customer>> {
159 self.db.customers().list(filter)
160 }
161
162 pub fn delete(&self, id: CustomerId) -> Result<()> {
164 self.db.customers().delete(id)
165 }
166
167 pub fn add_address(&self, input: CreateCustomerAddress) -> Result<CustomerAddress> {
169 input.validate()?;
171 let address = self.db.customers().add_address(input)?;
172 #[cfg(feature = "events")]
173 {
174 self.emit(CommerceEvent::CustomerAddressAdded {
175 customer_id: address.customer_id,
176 address_id: address.id,
177 timestamp: address.created_at,
178 });
179 }
180 Ok(address)
181 }
182
183 pub fn get_addresses(&self, customer_id: CustomerId) -> Result<Vec<CustomerAddress>> {
185 self.db.customers().get_addresses(customer_id)
186 }
187
188 pub fn update_address(
190 &self,
191 address_id: Uuid,
192 input: CreateCustomerAddress,
193 ) -> Result<CustomerAddress> {
194 self.db.customers().update_address(address_id, input)
195 }
196
197 pub fn delete_address(&self, address_id: Uuid) -> Result<()> {
199 self.db.customers().delete_address(address_id)
200 }
201
202 pub fn set_default_address(
204 &self,
205 customer_id: CustomerId,
206 address_id: Uuid,
207 address_type: AddressType,
208 ) -> Result<()> {
209 self.db.customers().set_default_address(customer_id, address_id, address_type)
210 }
211
212 pub fn count(&self, filter: CustomerFilter) -> Result<u64> {
214 self.db.customers().count(filter)
215 }
216
217 pub fn find_or_create(&self, input: CreateCustomer) -> Result<Customer> {
219 if let Some(customer) = self.get_by_email(&input.email)? {
220 Ok(customer)
221 } else {
222 self.create(input)
223 }
224 }
225}