elif_orm/relationships/constraints/
implementations.rs

1//! Constraint implementations for relationship queries
2
3use super::types::{ConstraintType, RelationshipConstraint};
4use crate::error::{ModelError, ModelResult};
5use crate::query::{OrderDirection, QueryBuilder, QueryOperator};
6use async_trait::async_trait;
7
8/// WHERE constraint implementation
9#[derive(Debug, Clone)]
10pub(crate) struct WhereConstraint {
11    pub field: String,
12    pub operator: QueryOperator,
13    pub value: serde_json::Value,
14}
15
16#[async_trait]
17impl RelationshipConstraint for WhereConstraint {
18    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
19        // Apply the WHERE condition using the appropriate method based on operator
20        *query = match self.operator {
21            QueryOperator::Equal => query.clone().where_eq(&self.field, self.value.clone()),
22            QueryOperator::NotEqual => query.clone().where_ne(&self.field, self.value.clone()),
23            QueryOperator::GreaterThan => query.clone().where_gt(&self.field, self.value.clone()),
24            QueryOperator::GreaterThanOrEqual => {
25                query.clone().where_gte(&self.field, self.value.clone())
26            }
27            QueryOperator::LessThan => query.clone().where_lt(&self.field, self.value.clone()),
28            QueryOperator::LessThanOrEqual => {
29                query.clone().where_lte(&self.field, self.value.clone())
30            }
31            QueryOperator::Like => {
32                if let Some(pattern) = self.value.as_str() {
33                    query.clone().where_like(&self.field, pattern)
34                } else {
35                    return Err(ModelError::Validation(
36                        "LIKE operator requires string value".to_string(),
37                    ));
38                }
39            }
40            QueryOperator::NotLike => {
41                if let Some(pattern) = self.value.as_str() {
42                    query.clone().where_not_like(&self.field, pattern)
43                } else {
44                    return Err(ModelError::Validation(
45                        "NOT LIKE operator requires string value".to_string(),
46                    ));
47                }
48            }
49            _ => {
50                return Err(ModelError::Validation(format!(
51                    "Unsupported operator {:?} for WHERE constraint",
52                    self.operator
53                )));
54            }
55        };
56        Ok(())
57    }
58
59    fn constraint_type(&self) -> ConstraintType {
60        ConstraintType::Where
61    }
62
63    fn description(&self) -> String {
64        format!("WHERE {} {:?} {}", self.field, self.operator, self.value)
65    }
66
67    fn validate(&self) -> ModelResult<()> {
68        if self.field.trim().is_empty() {
69            return Err(ModelError::Validation(
70                "WHERE constraint field cannot be empty".to_string(),
71            ));
72        }
73        Ok(())
74    }
75}
76
77/// ORDER BY constraint implementation  
78#[derive(Debug, Clone)]
79pub(crate) struct OrderConstraint {
80    pub field: String,
81    pub direction: OrderDirection,
82}
83
84#[async_trait]
85impl RelationshipConstraint for OrderConstraint {
86    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
87        // Apply the ORDER BY condition to the query builder
88        *query = match self.direction {
89            OrderDirection::Desc => query.clone().order_by_desc(&self.field),
90            OrderDirection::Asc => query.clone().order_by(&self.field),
91        };
92        Ok(())
93    }
94
95    fn constraint_type(&self) -> ConstraintType {
96        ConstraintType::Order
97    }
98
99    fn description(&self) -> String {
100        format!("ORDER BY {} {:?}", self.field, self.direction)
101    }
102
103    fn validate(&self) -> ModelResult<()> {
104        if self.field.trim().is_empty() {
105            return Err(ModelError::Validation(
106                "ORDER BY constraint field cannot be empty".to_string(),
107            ));
108        }
109        Ok(())
110    }
111}
112
113/// LIMIT constraint implementation
114#[derive(Debug, Clone)]
115pub(crate) struct LimitConstraint {
116    pub count: i64,
117}
118
119#[async_trait]
120impl RelationshipConstraint for LimitConstraint {
121    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
122        // Apply the LIMIT condition to the query builder
123        *query = query.clone().limit(self.count);
124        Ok(())
125    }
126
127    fn constraint_type(&self) -> ConstraintType {
128        ConstraintType::Limit
129    }
130
131    fn description(&self) -> String {
132        format!("LIMIT {}", self.count)
133    }
134
135    fn validate(&self) -> ModelResult<()> {
136        if self.count < 0 {
137            return Err(ModelError::Validation(
138                "LIMIT count must be non-negative".to_string(),
139            ));
140        }
141        Ok(())
142    }
143}
144
145/// OFFSET constraint implementation
146#[derive(Debug, Clone)]
147pub(crate) struct OffsetConstraint {
148    pub count: i64,
149}
150
151#[async_trait]
152impl RelationshipConstraint for OffsetConstraint {
153    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
154        *query = query.clone().offset(self.count);
155        Ok(())
156    }
157
158    fn constraint_type(&self) -> ConstraintType {
159        ConstraintType::Offset
160    }
161
162    fn description(&self) -> String {
163        format!("OFFSET {}", self.count)
164    }
165
166    fn validate(&self) -> ModelResult<()> {
167        if self.count < 0 {
168            return Err(ModelError::Validation(
169                "OFFSET count must be non-negative".to_string(),
170            ));
171        }
172        Ok(())
173    }
174}
175
176/// WHERE IN constraint implementation
177#[derive(Debug, Clone)]
178pub(crate) struct WhereInConstraint {
179    pub field: String,
180    pub values: Vec<serde_json::Value>,
181}
182
183#[async_trait]
184impl RelationshipConstraint for WhereInConstraint {
185    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
186        // Convert values to strings for the where_in method
187        let string_values: Vec<String> = self
188            .values
189            .iter()
190            .map(|v| match v {
191                serde_json::Value::String(s) => s.clone(),
192                _ => v.to_string(),
193            })
194            .collect();
195
196        *query = query.clone().where_in(&self.field, string_values);
197        Ok(())
198    }
199
200    fn constraint_type(&self) -> ConstraintType {
201        ConstraintType::Where
202    }
203
204    fn description(&self) -> String {
205        format!("WHERE {} IN ({} values)", self.field, self.values.len())
206    }
207
208    fn validate(&self) -> ModelResult<()> {
209        if self.field.trim().is_empty() {
210            return Err(ModelError::Validation(
211                "WHERE IN constraint field cannot be empty".to_string(),
212            ));
213        }
214        if self.values.is_empty() {
215            return Err(ModelError::Validation(
216                "WHERE IN constraint must have at least one value".to_string(),
217            ));
218        }
219        Ok(())
220    }
221}
222
223/// GROUP BY constraint implementation
224#[derive(Debug, Clone)]
225pub(crate) struct GroupByConstraint {
226    pub field: String,
227}
228
229#[async_trait]
230impl RelationshipConstraint for GroupByConstraint {
231    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
232        *query = query.clone().group_by(&self.field);
233        Ok(())
234    }
235
236    fn constraint_type(&self) -> ConstraintType {
237        ConstraintType::GroupBy
238    }
239
240    fn description(&self) -> String {
241        format!("GROUP BY {}", self.field)
242    }
243
244    fn validate(&self) -> ModelResult<()> {
245        if self.field.trim().is_empty() {
246            return Err(ModelError::Validation(
247                "GROUP BY constraint field cannot be empty".to_string(),
248            ));
249        }
250        Ok(())
251    }
252}
253
254/// HAVING constraint implementation
255#[derive(Debug, Clone)]
256pub(crate) struct HavingConstraint {
257    pub field: String,
258    pub operator: QueryOperator,
259    pub value: serde_json::Value,
260}
261
262#[async_trait]
263impl RelationshipConstraint for HavingConstraint {
264    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
265        // Apply HAVING constraint using the having method
266        *query = query
267            .clone()
268            .having(&self.field, self.operator, self.value.clone());
269        Ok(())
270    }
271
272    fn constraint_type(&self) -> ConstraintType {
273        ConstraintType::Having
274    }
275
276    fn description(&self) -> String {
277        format!("HAVING {} {:?} {}", self.field, self.operator, self.value)
278    }
279
280    fn validate(&self) -> ModelResult<()> {
281        if self.field.trim().is_empty() {
282            return Err(ModelError::Validation(
283                "HAVING constraint field cannot be empty".to_string(),
284            ));
285        }
286        Ok(())
287    }
288}
289
290/// Raw SQL constraint implementation for complex cases
291#[derive(Debug, Clone)]
292pub(crate) struct RawConstraint {
293    pub sql: String,
294    pub constraint_type: ConstraintType,
295}
296
297#[async_trait]
298impl RelationshipConstraint for RawConstraint {
299    async fn apply(&self, query: &mut QueryBuilder) -> ModelResult<()> {
300        // Apply raw constraint based on its type
301        match self.constraint_type {
302            ConstraintType::Where => {
303                *query = query.clone().where_raw(&self.sql);
304            }
305            ConstraintType::Having => {
306                *query = query.clone().having_raw(&self.sql);
307            }
308            ConstraintType::Raw => {
309                // For generic raw constraints, we'd need a way to append raw SQL
310                // This would require extending the QueryBuilder with a raw method
311                return Err(ModelError::Validation(
312                    "Raw constraints not yet supported".to_string(),
313                ));
314            }
315            _ => {
316                return Err(ModelError::Validation(format!(
317                    "Raw constraints not supported for type {:?}",
318                    self.constraint_type
319                )));
320            }
321        }
322        Ok(())
323    }
324
325    fn constraint_type(&self) -> ConstraintType {
326        self.constraint_type.clone()
327    }
328
329    fn description(&self) -> String {
330        format!("RAW {:?}: {}", self.constraint_type, self.sql)
331    }
332
333    fn validate(&self) -> ModelResult<()> {
334        if self.sql.trim().is_empty() {
335            return Err(ModelError::Validation(
336                "Raw constraint SQL cannot be empty".to_string(),
337            ));
338        }
339        Ok(())
340    }
341}