Skip to main content

stateset_embedded/
segments.rs

1//! Customer segment operations for grouping and targeting customers
2//!
3//! # Example
4//!
5//! ```rust,ignore
6//! use stateset_embedded::{Commerce, CreateSegment, SegmentType};
7//!
8//! let commerce = Commerce::new("./store.db")?;
9//!
10//! let segment = commerce.segments().create(CreateSegment {
11//!     name: "VIP Customers".into(),
12//!     segment_type: SegmentType::Static,
13//!     ..Default::default()
14//! })?;
15//!
16//! println!("Segment created: {}", segment.name);
17//! # Ok::<(), stateset_embedded::CommerceError>(())
18//! ```
19
20use stateset_core::{
21    CreateSegment, CustomerId, Result, Segment, SegmentFilter, SegmentId, SegmentMembership,
22    UpdateSegment,
23};
24use stateset_db::{Database, DatabaseCapability};
25use std::sync::Arc;
26
27/// Customer segment operations for grouping and targeting.
28pub struct Segments {
29    db: Arc<dyn Database>,
30}
31
32impl std::fmt::Debug for Segments {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.debug_struct("Segments").finish_non_exhaustive()
35    }
36}
37
38impl Segments {
39    pub(crate) fn new(db: Arc<dyn Database>) -> Self {
40        Self { db }
41    }
42
43    /// Whether customer segments are supported by the active backend.
44    #[must_use]
45    pub fn is_supported(&self) -> bool {
46        self.db.supports_capability(DatabaseCapability::Segments)
47    }
48
49    fn ensure_supported(&self) -> Result<()> {
50        self.db.ensure_capability(DatabaseCapability::Segments)
51    }
52
53    /// Create a new customer segment.
54    ///
55    /// # Example
56    ///
57    /// ```rust,ignore
58    /// use stateset_embedded::{Commerce, CreateSegment, SegmentType};
59    ///
60    /// let commerce = Commerce::new("./store.db")?;
61    ///
62    /// let segment = commerce.segments().create(CreateSegment {
63    ///     name: "High Spenders".into(),
64    ///     segment_type: SegmentType::Dynamic,
65    ///     description: Some("Customers who have spent over $1000".into()),
66    ///     ..Default::default()
67    /// })?;
68    /// # Ok::<(), stateset_embedded::CommerceError>(())
69    /// ```
70    pub fn create(&self, input: CreateSegment) -> Result<Segment> {
71        self.ensure_supported()?;
72        self.db.segments().create(input)
73    }
74
75    /// Get a segment by ID.
76    pub fn get(&self, id: SegmentId) -> Result<Option<Segment>> {
77        self.ensure_supported()?;
78        self.db.segments().get(id)
79    }
80
81    /// Update a segment.
82    pub fn update(&self, id: SegmentId, input: UpdateSegment) -> Result<Segment> {
83        self.ensure_supported()?;
84        self.db.segments().update(id, input)
85    }
86
87    /// List segments with optional filtering.
88    pub fn list(&self, filter: SegmentFilter) -> Result<Vec<Segment>> {
89        self.ensure_supported()?;
90        self.db.segments().list(filter)
91    }
92
93    /// Delete a segment.
94    pub fn delete(&self, id: SegmentId) -> Result<()> {
95        self.ensure_supported()?;
96        self.db.segments().delete(id)
97    }
98
99    /// Add a customer to a static segment.
100    pub fn add_member(
101        &self,
102        segment_id: SegmentId,
103        customer_id: CustomerId,
104    ) -> Result<SegmentMembership> {
105        self.ensure_supported()?;
106        self.db.segments().add_member(segment_id, customer_id)
107    }
108
109    /// Remove a customer from a static segment.
110    pub fn remove_member(&self, segment_id: SegmentId, customer_id: CustomerId) -> Result<()> {
111        self.ensure_supported()?;
112        self.db.segments().remove_member(segment_id, customer_id)
113    }
114
115    /// List members of a segment.
116    pub fn list_members(
117        &self,
118        segment_id: SegmentId,
119        limit: Option<u32>,
120        offset: Option<u32>,
121    ) -> Result<Vec<SegmentMembership>> {
122        self.ensure_supported()?;
123        self.db.segments().list_members(segment_id, limit, offset)
124    }
125
126    /// Check if a customer is a member of a segment.
127    pub fn is_member(&self, segment_id: SegmentId, customer_id: CustomerId) -> Result<bool> {
128        self.ensure_supported()?;
129        self.db.segments().is_member(segment_id, customer_id)
130    }
131
132    /// Count the number of members in a segment.
133    pub fn count_members(&self, segment_id: SegmentId) -> Result<u64> {
134        self.ensure_supported()?;
135        self.db.segments().count_members(segment_id)
136    }
137}