Skip to main content

reinhardt_db/orm/
functions.rs

1use crate::orm::annotation::AnnotationValue;
2use serde::{Deserialize, Serialize};
3
4/// Base database function trait
5pub trait DatabaseFunction {
6	/// Converts the function call to its SQL representation.
7	fn to_sql(&self) -> String;
8	/// Returns the SQL function name.
9	fn function_name(&self) -> &'static str;
10}
11
12/// Cast expression - convert a value to a specific type
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Cast {
15	expression: Box<AnnotationValue>,
16	/// The target type.
17	pub target_type: SqlType,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21/// Defines possible sql type values.
22pub enum SqlType {
23	/// Integer variant.
24	Integer,
25	/// BigInt variant.
26	BigInt,
27	/// SmallInt variant.
28	SmallInt,
29	/// Float variant.
30	Float,
31	/// Real variant.
32	Real,
33	/// Double variant.
34	Double,
35	/// Decimal variant.
36	Decimal {
37		/// The precision.
38		precision: Option<u8>,
39		/// The scale.
40		scale: Option<u8>,
41	},
42	/// Text variant.
43	Text,
44	/// Varchar variant.
45	Varchar {
46		/// The length.
47		length: Option<usize>,
48	},
49	/// Char variant.
50	Char {
51		/// The length.
52		length: usize,
53	},
54	/// Boolean variant.
55	Boolean,
56	/// Date variant.
57	Date,
58	/// Time variant.
59	Time,
60	/// Timestamp variant.
61	Timestamp,
62	/// Json variant.
63	Json,
64}
65
66impl SqlType {
67	/// Generate SQL type representation
68	///
69	/// # Examples
70	///
71	/// ```
72	/// use reinhardt_db::orm::functions::SqlType;
73	///
74	/// assert_eq!(SqlType::Integer.to_sql(), "INTEGER");
75	/// assert_eq!(SqlType::Varchar { length: Some(255) }.to_sql(), "VARCHAR(255)");
76	/// assert_eq!(SqlType::Decimal { precision: Some(10), scale: Some(2) }.to_sql(), "DECIMAL(10, 2)");
77	/// ```
78	pub fn to_sql(&self) -> String {
79		match self {
80			SqlType::Integer => "INTEGER".to_string(),
81			SqlType::BigInt => "BIGINT".to_string(),
82			SqlType::SmallInt => "SMALLINT".to_string(),
83			SqlType::Float => "FLOAT".to_string(),
84			SqlType::Real => "REAL".to_string(),
85			SqlType::Double => "DOUBLE PRECISION".to_string(),
86			SqlType::Decimal { precision, scale } => match (precision, scale) {
87				(Some(p), Some(s)) => format!("DECIMAL({}, {})", p, s),
88				(Some(p), None) => format!("DECIMAL({})", p),
89				_ => "DECIMAL".to_string(),
90			},
91			SqlType::Text => "TEXT".to_string(),
92			SqlType::Varchar { length } => {
93				if let Some(len) = length {
94					format!("VARCHAR({})", len)
95				} else {
96					"VARCHAR".to_string()
97				}
98			}
99			SqlType::Char { length } => format!("CHAR({})", length),
100			SqlType::Boolean => "BOOLEAN".to_string(),
101			SqlType::Date => "DATE".to_string(),
102			SqlType::Time => "TIME".to_string(),
103			SqlType::Timestamp => "TIMESTAMP".to_string(),
104			SqlType::Json => "JSON".to_string(),
105		}
106	}
107}
108
109impl Cast {
110	/// Cast an expression to a specific SQL type
111	///
112	/// # Examples
113	///
114	/// ```
115	/// use reinhardt_db::orm::functions::{Cast, SqlType};
116	/// use reinhardt_db::orm::annotation::AnnotationValue;
117	/// use reinhardt_db::orm::expressions::F;
118	///
119	/// let cast = Cast::new(
120	///     AnnotationValue::Field(F::new("price")),
121	///     SqlType::Integer
122	/// );
123	/// assert_eq!(cast.to_sql(), "CAST(\"price\" AS INTEGER)");
124	/// ```
125	pub fn new(expression: AnnotationValue, target_type: SqlType) -> Self {
126		Self {
127			expression: Box::new(expression),
128			target_type,
129		}
130	}
131
132	/// Get a reference to the expression
133	///
134	/// # Examples
135	///
136	/// ```
137	/// use reinhardt_db::orm::functions::{Cast, SqlType};
138	/// use reinhardt_db::orm::annotation::AnnotationValue;
139	/// use reinhardt_db::orm::expressions::F;
140	///
141	/// let cast = Cast::new(
142	///     AnnotationValue::Field(F::new("price")),
143	///     SqlType::Integer
144	/// );
145	/// let expr = cast.expression();
146	/// ```
147	pub fn expression(&self) -> &AnnotationValue {
148		&self.expression
149	}
150
151	/// Convert into the inner expression, consuming self
152	///
153	/// # Examples
154	///
155	/// ```
156	/// use reinhardt_db::orm::functions::{Cast, SqlType};
157	/// use reinhardt_db::orm::annotation::AnnotationValue;
158	/// use reinhardt_db::orm::expressions::F;
159	///
160	/// let cast = Cast::new(
161	///     AnnotationValue::Field(F::new("price")),
162	///     SqlType::Integer
163	/// );
164	/// let expr = cast.into_expression();
165	/// ```
166	pub fn into_expression(self) -> AnnotationValue {
167		*self.expression
168	}
169	/// Generate SQL for CAST expression
170	///
171	/// # Examples
172	///
173	/// ```
174	/// use reinhardt_db::orm::functions::{Cast, SqlType};
175	/// use reinhardt_db::orm::annotation::AnnotationValue;
176	/// use reinhardt_db::orm::expressions::F;
177	///
178	/// let cast = Cast::new(
179	///     AnnotationValue::Field(F::new("id")),
180	///     SqlType::Varchar { length: Some(50) }
181	/// );
182	/// assert_eq!(cast.to_sql(), "CAST(\"id\" AS VARCHAR(50))");
183	/// ```
184	pub fn to_sql(&self) -> String {
185		format!(
186			"CAST({} AS {})",
187			self.expression.to_sql(),
188			self.target_type.to_sql()
189		)
190	}
191}
192
193/// Greatest - return the maximum value among expressions
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct Greatest {
196	/// The expressions.
197	pub expressions: Vec<AnnotationValue>,
198}
199
200impl Greatest {
201	/// Create a new Greatest function to return the maximum value from multiple expressions
202	///
203	/// # Examples
204	///
205	/// ```
206	/// use reinhardt_db::orm::functions::Greatest;
207	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
208	///
209	/// let expr1 = AnnotationValue::Value(Value::Int(10));
210	/// let expr2 = AnnotationValue::Value(Value::Int(20));
211	/// let greatest = Greatest::new(vec![expr1, expr2]).unwrap();
212	/// assert_eq!(greatest.expressions.len(), 2);
213	/// ```
214	pub fn new(expressions: Vec<AnnotationValue>) -> Result<Self, String> {
215		if expressions.len() < 2 {
216			return Err("Greatest must take at least two expressions".to_string());
217		}
218		Ok(Self { expressions })
219	}
220	/// Documentation for `to_sql`
221	///
222	pub fn to_sql(&self) -> String {
223		let exprs: Vec<String> = self.expressions.iter().map(|e| e.to_sql()).collect();
224		format!("GREATEST({})", exprs.join(", "))
225	}
226}
227
228/// Least - return the minimum value among expressions
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct Least {
231	/// The expressions.
232	pub expressions: Vec<AnnotationValue>,
233}
234
235impl Least {
236	/// Create a new Least function to return the minimum value from multiple expressions
237	///
238	/// # Examples
239	///
240	/// ```
241	/// use reinhardt_db::orm::functions::Least;
242	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
243	///
244	/// let expr1 = AnnotationValue::Value(Value::Int(10));
245	/// let expr2 = AnnotationValue::Value(Value::Int(20));
246	/// let least = Least::new(vec![expr1, expr2]).unwrap();
247	/// assert_eq!(least.expressions.len(), 2);
248	/// ```
249	pub fn new(expressions: Vec<AnnotationValue>) -> Result<Self, String> {
250		if expressions.len() < 2 {
251			return Err("Least must take at least two expressions".to_string());
252		}
253		Ok(Self { expressions })
254	}
255	/// Documentation for `to_sql`
256	///
257	pub fn to_sql(&self) -> String {
258		let exprs: Vec<String> = self.expressions.iter().map(|e| e.to_sql()).collect();
259		format!("LEAST({})", exprs.join(", "))
260	}
261}
262
263/// NullIf - return NULL if two expressions are equal
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct NullIf {
266	expr1: Box<AnnotationValue>,
267	expr2: Box<AnnotationValue>,
268}
269
270impl NullIf {
271	/// Create a NULLIF function that returns NULL if two expressions are equal
272	///
273	/// # Examples
274	///
275	/// ```
276	/// use reinhardt_db::orm::functions::NullIf;
277	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
278	///
279	/// let nullif = NullIf::new(
280	///     AnnotationValue::Value(Value::Int(0)),
281	///     AnnotationValue::Value(Value::Int(0))
282	/// );
283	/// assert_eq!(nullif.to_sql(), "NULLIF(0, 0)");
284	/// ```
285	pub fn new(expr1: AnnotationValue, expr2: AnnotationValue) -> Self {
286		Self {
287			expr1: Box::new(expr1),
288			expr2: Box::new(expr2),
289		}
290	}
291	/// Documentation for `to_sql`
292	///
293	pub fn to_sql(&self) -> String {
294		format!("NULLIF({}, {})", self.expr1.to_sql(), self.expr2.to_sql())
295	}
296
297	/// Get a reference to the first expression
298	pub fn expr1(&self) -> &AnnotationValue {
299		&self.expr1
300	}
301
302	/// Get a reference to the second expression
303	pub fn expr2(&self) -> &AnnotationValue {
304		&self.expr2
305	}
306
307	/// Convert into the first expression, consuming self
308	pub fn into_expr1(self) -> AnnotationValue {
309		*self.expr1
310	}
311
312	/// Convert into the second expression, consuming self
313	pub fn into_expr2(self) -> AnnotationValue {
314		*self.expr2
315	}
316}
317
318// Text functions
319
320/// Concat - concatenate multiple strings
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct Concat {
323	/// The expressions.
324	pub expressions: Vec<AnnotationValue>,
325}
326
327impl Concat {
328	/// Concatenate multiple string expressions
329	///
330	/// # Examples
331	///
332	/// ```
333	/// use reinhardt_db::orm::functions::Concat;
334	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
335	/// use reinhardt_db::orm::expressions::F;
336	///
337	/// let concat = Concat::new(vec![
338	///     AnnotationValue::Field(F::new("first_name")),
339	///     AnnotationValue::Value(Value::String(" ".into())),
340	///     AnnotationValue::Field(F::new("last_name")),
341	/// ]).unwrap();
342	/// assert_eq!(concat.to_sql(), "CONCAT(\"first_name\", ' ', \"last_name\")");
343	/// ```
344	pub fn new(expressions: Vec<AnnotationValue>) -> Result<Self, String> {
345		if expressions.len() < 2 {
346			return Err("Concat must take at least two expressions".to_string());
347		}
348		Ok(Self { expressions })
349	}
350	/// Generate CONCAT SQL
351	///
352	/// # Examples
353	///
354	/// ```
355	/// use reinhardt_db::orm::functions::Concat;
356	/// use reinhardt_db::orm::annotation::AnnotationValue;
357	/// use reinhardt_db::orm::expressions::F;
358	///
359	/// let concat = Concat::new(vec![
360	///     AnnotationValue::Field(F::new("city")),
361	///     AnnotationValue::Field(F::new("country")),
362	/// ]).unwrap();
363	/// assert!(concat.to_sql().starts_with("CONCAT("));
364	/// ```
365	pub fn to_sql(&self) -> String {
366		let exprs: Vec<String> = self.expressions.iter().map(|e| e.to_sql()).collect();
367		format!("CONCAT({})", exprs.join(", "))
368	}
369}
370
371/// Upper - convert string to uppercase
372#[derive(Debug, Clone, Serialize, Deserialize)]
373pub struct Upper {
374	expression: Box<AnnotationValue>,
375}
376
377impl Upper {
378	/// Convert string to uppercase
379	///
380	/// # Examples
381	///
382	/// ```
383	/// use reinhardt_db::orm::functions::Upper;
384	/// use reinhardt_db::orm::annotation::AnnotationValue;
385	/// use reinhardt_db::orm::expressions::F;
386	///
387	/// let upper = Upper::new(AnnotationValue::Field(F::new("email")));
388	/// assert_eq!(upper.to_sql(), "UPPER(\"email\")");
389	/// ```
390	pub fn new(expression: AnnotationValue) -> Self {
391		Self {
392			expression: Box::new(expression),
393		}
394	}
395	/// Generate UPPER SQL
396	///
397	/// # Examples
398	///
399	/// ```
400	/// use reinhardt_db::orm::functions::Upper;
401	/// use reinhardt_db::orm::annotation::AnnotationValue;
402	/// use reinhardt_db::orm::expressions::F;
403	///
404	/// let upper = Upper::new(AnnotationValue::Field(F::new("name")));
405	/// assert_eq!(upper.to_sql(), "UPPER(\"name\")");
406	/// ```
407	pub fn to_sql(&self) -> String {
408		format!("UPPER({})", self.expression.to_sql())
409	}
410
411	/// Get a reference to the expression
412	pub fn expression(&self) -> &AnnotationValue {
413		&self.expression
414	}
415
416	/// Convert into the expression, consuming self
417	pub fn into_expression(self) -> AnnotationValue {
418		*self.expression
419	}
420}
421
422/// Lower - convert string to lowercase
423#[derive(Debug, Clone, Serialize, Deserialize)]
424pub struct Lower {
425	expression: Box<AnnotationValue>,
426}
427
428impl Lower {
429	/// Create a new Lower function to convert string to lowercase
430	///
431	/// # Examples
432	///
433	/// ```
434	/// use reinhardt_db::orm::functions::Lower;
435	/// use reinhardt_db::orm::annotation::AnnotationValue;
436	/// use reinhardt_db::orm::expressions::F;
437	///
438	/// let lower = Lower::new(AnnotationValue::Field(F::new("name")));
439	/// assert_eq!(lower.to_sql(), "LOWER(\"name\")");
440	/// ```
441	pub fn new(expression: AnnotationValue) -> Self {
442		Self {
443			expression: Box::new(expression),
444		}
445	}
446	/// Documentation for `to_sql`
447	///
448	pub fn to_sql(&self) -> String {
449		format!("LOWER({})", self.expression.to_sql())
450	}
451
452	/// Get a reference to the expression
453	pub fn expression(&self) -> &AnnotationValue {
454		&self.expression
455	}
456
457	/// Convert into the expression, consuming self
458	pub fn into_expression(self) -> AnnotationValue {
459		*self.expression
460	}
461}
462
463/// Length - return the length of a string
464#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct Length {
466	expression: Box<AnnotationValue>,
467}
468
469impl Length {
470	/// Create a new Length function to return the length of a string
471	///
472	/// # Examples
473	///
474	/// ```
475	/// use reinhardt_db::orm::functions::Length;
476	/// use reinhardt_db::orm::annotation::AnnotationValue;
477	/// use reinhardt_db::orm::expressions::F;
478	///
479	/// let length = Length::new(AnnotationValue::Field(F::new("name")));
480	/// assert_eq!(length.to_sql(), "LENGTH(\"name\")");
481	/// ```
482	pub fn new(expression: AnnotationValue) -> Self {
483		Self {
484			expression: Box::new(expression),
485		}
486	}
487	/// Documentation for `to_sql`
488	///
489	pub fn to_sql(&self) -> String {
490		format!("LENGTH({})", self.expression.to_sql())
491	}
492
493	/// Get a reference to the expression
494	pub fn expression(&self) -> &AnnotationValue {
495		&self.expression
496	}
497
498	/// Convert into the expression, consuming self
499	pub fn into_expression(self) -> AnnotationValue {
500		*self.expression
501	}
502}
503
504/// Trim - remove leading and trailing whitespace
505#[derive(Debug, Clone, Serialize, Deserialize)]
506pub struct Trim {
507	expression: Box<AnnotationValue>,
508	/// The trim type.
509	pub trim_type: TrimType,
510}
511
512#[derive(Debug, Clone, Serialize, Deserialize)]
513/// Defines possible trim type values.
514pub enum TrimType {
515	/// Both variant.
516	Both,
517	/// Leading variant.
518	Leading,
519	/// Trailing variant.
520	Trailing,
521}
522
523impl Trim {
524	/// Create a Trim function to remove leading and trailing whitespace
525	///
526	/// # Examples
527	///
528	/// ```
529	/// use reinhardt_db::orm::functions::Trim;
530	/// use reinhardt_db::orm::annotation::AnnotationValue;
531	/// use reinhardt_db::orm::expressions::F;
532	///
533	/// let trim = Trim::new(AnnotationValue::Field(F::new("name")));
534	/// assert_eq!(trim.to_sql(), "TRIM(\"name\")");
535	/// ```
536	pub fn new(expression: AnnotationValue) -> Self {
537		Self {
538			expression: Box::new(expression),
539			trim_type: TrimType::Both,
540		}
541	}
542	/// Documentation for `leading`
543	///
544	pub fn leading(mut self) -> Self {
545		self.trim_type = TrimType::Leading;
546		self
547	}
548	/// Documentation for `trailing`
549	///
550	pub fn trailing(mut self) -> Self {
551		self.trim_type = TrimType::Trailing;
552		self
553	}
554	/// Documentation for `to_sql`
555	///
556	pub fn to_sql(&self) -> String {
557		match self.trim_type {
558			TrimType::Both => format!("TRIM({})", self.expression.to_sql()),
559			TrimType::Leading => format!("LTRIM({})", self.expression.to_sql()),
560			TrimType::Trailing => format!("RTRIM({})", self.expression.to_sql()),
561		}
562	}
563
564	/// Get a reference to the expression
565	pub fn expression(&self) -> &AnnotationValue {
566		&self.expression
567	}
568
569	/// Convert into the expression, consuming self
570	pub fn into_expression(self) -> AnnotationValue {
571		*self.expression
572	}
573}
574
575/// Substr - extract a substring
576#[derive(Debug, Clone, Serialize, Deserialize)]
577pub struct Substr {
578	expression: Box<AnnotationValue>,
579	start: Box<AnnotationValue>,
580	length: Option<Box<AnnotationValue>>,
581}
582
583impl Substr {
584	/// Create a new Substr function to extract a substring
585	///
586	/// # Examples
587	///
588	/// ```
589	/// use reinhardt_db::orm::functions::Substr;
590	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
591	/// use reinhardt_db::orm::expressions::F;
592	///
593	/// let substr = Substr::new(
594	///     AnnotationValue::Field(F::new("name")),
595	///     AnnotationValue::Value(Value::Int(1)),
596	///     Some(AnnotationValue::Value(Value::Int(5))),
597	/// );
598	/// assert_eq!(substr.to_sql(), "SUBSTR(\"name\", 1, 5)");
599	/// ```
600	pub fn new(
601		expression: AnnotationValue,
602		start: AnnotationValue,
603		length: Option<AnnotationValue>,
604	) -> Self {
605		Self {
606			expression: Box::new(expression),
607			start: Box::new(start),
608			length: length.map(Box::new),
609		}
610	}
611	/// Documentation for `to_sql`
612	///
613	pub fn to_sql(&self) -> String {
614		if let Some(len) = &self.length {
615			format!(
616				"SUBSTR({}, {}, {})",
617				self.expression.to_sql(),
618				self.start.to_sql(),
619				len.to_sql()
620			)
621		} else {
622			format!(
623				"SUBSTR({}, {})",
624				self.expression.to_sql(),
625				self.start.to_sql()
626			)
627		}
628	}
629
630	/// Get a reference to the expression
631	pub fn expression(&self) -> &AnnotationValue {
632		&self.expression
633	}
634
635	/// Get a reference to the start position
636	pub fn start(&self) -> &AnnotationValue {
637		&self.start
638	}
639
640	/// Get a reference to the length (if provided)
641	pub fn length(&self) -> Option<&AnnotationValue> {
642		self.length.as_deref()
643	}
644
645	/// Convert into the expression, consuming self
646	pub fn into_expression(self) -> AnnotationValue {
647		*self.expression
648	}
649
650	/// Convert into the start position, consuming self
651	pub fn into_start(self) -> AnnotationValue {
652		*self.start
653	}
654
655	/// Convert into the length (if provided), consuming self
656	pub fn into_length(self) -> Option<AnnotationValue> {
657		self.length.map(|b| *b)
658	}
659}
660
661// Math functions
662
663/// Abs - absolute value
664#[derive(Debug, Clone, Serialize, Deserialize)]
665pub struct Abs {
666	expression: Box<AnnotationValue>,
667}
668
669impl Abs {
670	/// Create a new Abs function to return the absolute value
671	///
672	/// # Examples
673	///
674	/// ```
675	/// use reinhardt_db::orm::functions::Abs;
676	/// use reinhardt_db::orm::annotation::AnnotationValue;
677	/// use reinhardt_db::orm::expressions::F;
678	///
679	/// let abs = Abs::new(AnnotationValue::Field(F::new("temperature")));
680	/// assert_eq!(abs.to_sql(), "ABS(\"temperature\")");
681	/// ```
682	pub fn new(expression: AnnotationValue) -> Self {
683		Self {
684			expression: Box::new(expression),
685		}
686	}
687	/// Documentation for `to_sql`
688	///
689	pub fn to_sql(&self) -> String {
690		format!("ABS({})", self.expression.to_sql())
691	}
692
693	/// Get a reference to the expression
694	pub fn expression(&self) -> &AnnotationValue {
695		&self.expression
696	}
697
698	/// Convert into the expression, consuming self
699	pub fn into_expression(self) -> AnnotationValue {
700		*self.expression
701	}
702}
703
704/// Ceil - round up to nearest integer
705#[derive(Debug, Clone, Serialize, Deserialize)]
706pub struct Ceil {
707	expression: Box<AnnotationValue>,
708}
709
710impl Ceil {
711	/// Create a new Ceil function to round up to the nearest integer
712	///
713	/// # Examples
714	///
715	/// ```
716	/// use reinhardt_db::orm::functions::Ceil;
717	/// use reinhardt_db::orm::annotation::AnnotationValue;
718	/// use reinhardt_db::orm::expressions::F;
719	///
720	/// let ceil = Ceil::new(AnnotationValue::Field(F::new("price")));
721	/// assert_eq!(ceil.to_sql(), "CEIL(\"price\")");
722	/// ```
723	pub fn new(expression: AnnotationValue) -> Self {
724		Self {
725			expression: Box::new(expression),
726		}
727	}
728	/// Documentation for `to_sql`
729	///
730	pub fn to_sql(&self) -> String {
731		format!("CEIL({})", self.expression.to_sql())
732	}
733
734	/// Get a reference to the expression
735	pub fn expression(&self) -> &AnnotationValue {
736		&self.expression
737	}
738
739	/// Convert into the expression, consuming self
740	pub fn into_expression(self) -> AnnotationValue {
741		*self.expression
742	}
743}
744
745/// Floor - round down to nearest integer
746#[derive(Debug, Clone, Serialize, Deserialize)]
747pub struct Floor {
748	expression: Box<AnnotationValue>,
749}
750
751impl Floor {
752	/// Create a new Floor function to round down to the nearest integer
753	///
754	/// # Examples
755	///
756	/// ```
757	/// use reinhardt_db::orm::functions::Floor;
758	/// use reinhardt_db::orm::annotation::AnnotationValue;
759	/// use reinhardt_db::orm::expressions::F;
760	///
761	/// let floor = Floor::new(AnnotationValue::Field(F::new("price")));
762	/// assert_eq!(floor.to_sql(), "FLOOR(\"price\")");
763	/// ```
764	pub fn new(expression: AnnotationValue) -> Self {
765		Self {
766			expression: Box::new(expression),
767		}
768	}
769	/// Documentation for `to_sql`
770	///
771	pub fn to_sql(&self) -> String {
772		format!("FLOOR({})", self.expression.to_sql())
773	}
774
775	/// Get a reference to the expression
776	pub fn expression(&self) -> &AnnotationValue {
777		&self.expression
778	}
779
780	/// Convert into the expression, consuming self
781	pub fn into_expression(self) -> AnnotationValue {
782		*self.expression
783	}
784}
785
786/// Round - round to specified decimal places
787#[derive(Debug, Clone, Serialize, Deserialize)]
788pub struct Round {
789	expression: Box<AnnotationValue>,
790	/// The decimals.
791	pub decimals: Option<i32>,
792}
793
794impl Round {
795	/// Create a new Round function to round to specified decimal places
796	///
797	/// # Examples
798	///
799	/// ```
800	/// use reinhardt_db::orm::functions::Round;
801	/// use reinhardt_db::orm::annotation::AnnotationValue;
802	/// use reinhardt_db::orm::expressions::F;
803	///
804	/// let round = Round::new(AnnotationValue::Field(F::new("price")), Some(2));
805	/// assert_eq!(round.to_sql(), "ROUND(\"price\", 2)");
806	/// ```
807	pub fn new(expression: AnnotationValue, decimals: Option<i32>) -> Self {
808		Self {
809			expression: Box::new(expression),
810			decimals,
811		}
812	}
813	/// Documentation for `to_sql`
814	///
815	pub fn to_sql(&self) -> String {
816		if let Some(d) = self.decimals {
817			format!("ROUND({}, {})", self.expression.to_sql(), d)
818		} else {
819			format!("ROUND({})", self.expression.to_sql())
820		}
821	}
822
823	/// Get a reference to the expression
824	pub fn expression(&self) -> &AnnotationValue {
825		&self.expression
826	}
827
828	/// Convert into the expression, consuming self
829	pub fn into_expression(self) -> AnnotationValue {
830		*self.expression
831	}
832}
833
834/// Mod - modulo operation
835#[derive(Debug, Clone, Serialize, Deserialize)]
836pub struct Mod {
837	dividend: Box<AnnotationValue>,
838	divisor: Box<AnnotationValue>,
839}
840
841impl Mod {
842	/// Create a Mod function for modulo operation
843	///
844	/// # Examples
845	///
846	/// ```
847	/// use reinhardt_db::orm::functions::Mod;
848	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
849	///
850	/// let mod_op = Mod::new(
851	///     AnnotationValue::Value(Value::Int(10)),
852	///     AnnotationValue::Value(Value::Int(3))
853	/// );
854	/// assert_eq!(mod_op.to_sql(), "MOD(10, 3)");
855	/// ```
856	pub fn new(dividend: AnnotationValue, divisor: AnnotationValue) -> Self {
857		Self {
858			dividend: Box::new(dividend),
859			divisor: Box::new(divisor),
860		}
861	}
862	/// Documentation for `to_sql`
863	///
864	pub fn to_sql(&self) -> String {
865		format!("MOD({}, {})", self.dividend.to_sql(), self.divisor.to_sql())
866	}
867
868	/// Get a reference to the dividend
869	pub fn dividend(&self) -> &AnnotationValue {
870		&self.dividend
871	}
872
873	/// Get a reference to the divisor
874	pub fn divisor(&self) -> &AnnotationValue {
875		&self.divisor
876	}
877
878	/// Convert into the dividend, consuming self
879	pub fn into_dividend(self) -> AnnotationValue {
880		*self.dividend
881	}
882
883	/// Convert into the divisor, consuming self
884	pub fn into_divisor(self) -> AnnotationValue {
885		*self.divisor
886	}
887}
888
889/// Power - raise to a power
890#[derive(Debug, Clone, Serialize, Deserialize)]
891pub struct Power {
892	base: Box<AnnotationValue>,
893	exponent: Box<AnnotationValue>,
894}
895
896impl Power {
897	/// Create a Power function to raise to a power
898	///
899	/// # Examples
900	///
901	/// ```
902	/// use reinhardt_db::orm::functions::Power;
903	/// use reinhardt_db::orm::annotation::{AnnotationValue, Value};
904	///
905	/// let power = Power::new(
906	///     AnnotationValue::Value(Value::Int(2)),
907	///     AnnotationValue::Value(Value::Int(3))
908	/// );
909	/// assert_eq!(power.to_sql(), "POWER(2, 3)"); // 2^3 = 8
910	/// ```
911	pub fn new(base: AnnotationValue, exponent: AnnotationValue) -> Self {
912		Self {
913			base: Box::new(base),
914			exponent: Box::new(exponent),
915		}
916	}
917	/// Documentation for `to_sql`
918	///
919	pub fn to_sql(&self) -> String {
920		format!("POWER({}, {})", self.base.to_sql(), self.exponent.to_sql())
921	}
922
923	/// Get a reference to the base
924	pub fn base(&self) -> &AnnotationValue {
925		&self.base
926	}
927
928	/// Get a reference to the exponent
929	pub fn exponent(&self) -> &AnnotationValue {
930		&self.exponent
931	}
932
933	/// Convert into the base, consuming self
934	pub fn into_base(self) -> AnnotationValue {
935		*self.base
936	}
937
938	/// Convert into the exponent, consuming self
939	pub fn into_exponent(self) -> AnnotationValue {
940		*self.exponent
941	}
942}
943
944/// Sqrt - square root
945#[derive(Debug, Clone, Serialize, Deserialize)]
946pub struct Sqrt {
947	expression: Box<AnnotationValue>,
948}
949
950impl Sqrt {
951	/// Create a new Sqrt function to return the square root
952	///
953	/// # Examples
954	///
955	/// ```
956	/// use reinhardt_db::orm::functions::Sqrt;
957	/// use reinhardt_db::orm::annotation::AnnotationValue;
958	/// use reinhardt_db::orm::expressions::F;
959	///
960	/// let sqrt = Sqrt::new(AnnotationValue::Field(F::new("area")));
961	/// assert_eq!(sqrt.to_sql(), "SQRT(\"area\")");
962	/// ```
963	pub fn new(expression: AnnotationValue) -> Self {
964		Self {
965			expression: Box::new(expression),
966		}
967	}
968	/// Documentation for `to_sql`
969	///
970	pub fn to_sql(&self) -> String {
971		format!("SQRT({})", self.expression.to_sql())
972	}
973
974	/// Get a reference to the expression
975	pub fn expression(&self) -> &AnnotationValue {
976		&self.expression
977	}
978
979	/// Convert into the expression, consuming self
980	pub fn into_expression(self) -> AnnotationValue {
981		*self.expression
982	}
983}
984
985// Date/Time functions
986
987/// Extract component from date/time
988#[derive(Debug, Clone, Serialize, Deserialize)]
989pub struct Extract {
990	expression: Box<AnnotationValue>,
991	/// The component.
992	pub component: ExtractComponent,
993}
994
995#[derive(Debug, Clone, Serialize, Deserialize)]
996/// Defines possible extract component values.
997pub enum ExtractComponent {
998	/// Year variant.
999	Year,
1000	/// Month variant.
1001	Month,
1002	/// Day variant.
1003	Day,
1004	/// Hour variant.
1005	Hour,
1006	/// Minute variant.
1007	Minute,
1008	/// Second variant.
1009	Second,
1010	/// Week variant.
1011	Week,
1012	/// Quarter variant.
1013	Quarter,
1014	/// WeekDay variant.
1015	WeekDay,
1016	/// IsoWeekDay variant.
1017	IsoWeekDay,
1018	/// IsoYear variant.
1019	IsoYear,
1020}
1021
1022impl ExtractComponent {
1023	/// Documentation for `to_sql`
1024	///
1025	pub fn to_sql(&self) -> &'static str {
1026		match self {
1027			ExtractComponent::Year => "YEAR",
1028			ExtractComponent::Month => "MONTH",
1029			ExtractComponent::Day => "DAY",
1030			ExtractComponent::Hour => "HOUR",
1031			ExtractComponent::Minute => "MINUTE",
1032			ExtractComponent::Second => "SECOND",
1033			ExtractComponent::Week => "WEEK",
1034			ExtractComponent::Quarter => "QUARTER",
1035			ExtractComponent::WeekDay => "DOW",
1036			ExtractComponent::IsoWeekDay => "ISODOW",
1037			ExtractComponent::IsoYear => "ISOYEAR",
1038		}
1039	}
1040}
1041
1042impl Extract {
1043	/// Extract a component from a date/time value
1044	///
1045	/// # Examples
1046	///
1047	/// ```
1048	/// use reinhardt_db::orm::functions::{Extract, ExtractComponent};
1049	/// use reinhardt_db::orm::annotation::AnnotationValue;
1050	/// use reinhardt_db::orm::expressions::F;
1051	///
1052	/// let extract = Extract::new(
1053	///     AnnotationValue::Field(F::new("created_at")),
1054	///     ExtractComponent::Year
1055	/// );
1056	/// assert_eq!(extract.to_sql(), "EXTRACT(YEAR FROM \"created_at\")");
1057	/// ```
1058	pub fn new(expression: AnnotationValue, component: ExtractComponent) -> Self {
1059		Self {
1060			expression: Box::new(expression),
1061			component,
1062		}
1063	}
1064	/// Extract year from a date/time
1065	///
1066	/// # Examples
1067	///
1068	/// ```
1069	/// use reinhardt_db::orm::functions::Extract;
1070	/// use reinhardt_db::orm::annotation::AnnotationValue;
1071	/// use reinhardt_db::orm::expressions::F;
1072	///
1073	/// let year_extract = Extract::year(AnnotationValue::Field(F::new("birth_date")));
1074	/// assert_eq!(year_extract.to_sql(), "EXTRACT(YEAR FROM \"birth_date\")");
1075	/// ```
1076	pub fn year(expression: AnnotationValue) -> Self {
1077		Self::new(expression, ExtractComponent::Year)
1078	}
1079	/// Extract month from a date/time
1080	///
1081	/// # Examples
1082	///
1083	/// ```
1084	/// use reinhardt_db::orm::functions::Extract;
1085	/// use reinhardt_db::orm::annotation::AnnotationValue;
1086	/// use reinhardt_db::orm::expressions::F;
1087	///
1088	/// let month_extract = Extract::month(AnnotationValue::Field(F::new("order_date")));
1089	/// assert_eq!(month_extract.to_sql(), "EXTRACT(MONTH FROM \"order_date\")");
1090	/// ```
1091	pub fn month(expression: AnnotationValue) -> Self {
1092		Self::new(expression, ExtractComponent::Month)
1093	}
1094	/// Extract day from a date/time
1095	///
1096	/// # Examples
1097	///
1098	/// ```
1099	/// use reinhardt_db::orm::functions::Extract;
1100	/// use reinhardt_db::orm::annotation::AnnotationValue;
1101	/// use reinhardt_db::orm::expressions::F;
1102	///
1103	/// let day_extract = Extract::day(AnnotationValue::Field(F::new("timestamp")));
1104	/// assert_eq!(day_extract.to_sql(), "EXTRACT(DAY FROM \"timestamp\")");
1105	/// ```
1106	pub fn day(expression: AnnotationValue) -> Self {
1107		Self::new(expression, ExtractComponent::Day)
1108	}
1109	/// Extract hour from a date/time
1110	///
1111	/// # Examples
1112	///
1113	/// ```
1114	/// use reinhardt_db::orm::functions::Extract;
1115	/// use reinhardt_db::orm::annotation::AnnotationValue;
1116	/// use reinhardt_db::orm::expressions::F;
1117	///
1118	/// let hour_extract = Extract::hour(AnnotationValue::Field(F::new("event_time")));
1119	/// assert_eq!(hour_extract.to_sql(), "EXTRACT(HOUR FROM \"event_time\")");
1120	/// ```
1121	pub fn hour(expression: AnnotationValue) -> Self {
1122		Self::new(expression, ExtractComponent::Hour)
1123	}
1124	/// Extract minute from a date/time
1125	///
1126	/// # Examples
1127	///
1128	/// ```
1129	/// use reinhardt_db::orm::functions::Extract;
1130	/// use reinhardt_db::orm::annotation::AnnotationValue;
1131	/// use reinhardt_db::orm::expressions::F;
1132	///
1133	/// let minute_extract = Extract::minute(AnnotationValue::Field(F::new("timestamp")));
1134	/// assert_eq!(minute_extract.to_sql(), "EXTRACT(MINUTE FROM \"timestamp\")");
1135	/// ```
1136	pub fn minute(expression: AnnotationValue) -> Self {
1137		Self::new(expression, ExtractComponent::Minute)
1138	}
1139	/// Extract second from a date/time
1140	///
1141	/// # Examples
1142	///
1143	/// ```
1144	/// use reinhardt_db::orm::functions::Extract;
1145	/// use reinhardt_db::orm::annotation::AnnotationValue;
1146	/// use reinhardt_db::orm::expressions::F;
1147	///
1148	/// let second_extract = Extract::second(AnnotationValue::Field(F::new("timestamp")));
1149	/// assert_eq!(second_extract.to_sql(), "EXTRACT(SECOND FROM \"timestamp\")");
1150	/// ```
1151	pub fn second(expression: AnnotationValue) -> Self {
1152		Self::new(expression, ExtractComponent::Second)
1153	}
1154	/// Generate EXTRACT SQL
1155	///
1156	/// # Examples
1157	///
1158	/// ```
1159	/// use reinhardt_db::orm::functions::Extract;
1160	/// use reinhardt_db::orm::annotation::AnnotationValue;
1161	/// use reinhardt_db::orm::expressions::F;
1162	///
1163	/// let extract = Extract::year(AnnotationValue::Field(F::new("created_at")));
1164	/// assert!(extract.to_sql().starts_with("EXTRACT("));
1165	/// ```
1166	pub fn to_sql(&self) -> String {
1167		format!(
1168			"EXTRACT({} FROM {})",
1169			self.component.to_sql(),
1170			self.expression.to_sql()
1171		)
1172	}
1173
1174	/// Get a reference to the expression
1175	pub fn expression(&self) -> &AnnotationValue {
1176		&self.expression
1177	}
1178
1179	/// Convert into the expression, consuming self
1180	pub fn into_expression(self) -> AnnotationValue {
1181		*self.expression
1182	}
1183}
1184
1185/// Now - current timestamp
1186#[derive(Debug, Clone, Serialize, Deserialize)]
1187pub struct Now;
1188
1189impl Now {
1190	/// Create a new Now function to get the current timestamp
1191	///
1192	/// # Examples
1193	///
1194	/// ```
1195	/// use reinhardt_db::orm::functions::Now;
1196	///
1197	/// let now = Now::new();
1198	/// assert_eq!(now.to_sql(), "CURRENT_TIMESTAMP");
1199	/// ```
1200	pub fn new() -> Self {
1201		Self
1202	}
1203	/// Documentation for `to_sql`
1204	///
1205	pub fn to_sql(&self) -> String {
1206		"CURRENT_TIMESTAMP".to_string()
1207	}
1208}
1209
1210impl Default for Now {
1211	fn default() -> Self {
1212		Self::new()
1213	}
1214}
1215
1216/// CurrentDate - current date
1217#[derive(Debug, Clone, Serialize, Deserialize)]
1218pub struct CurrentDate;
1219
1220impl CurrentDate {
1221	/// Create a CurrentDate function to get the current date
1222	///
1223	/// # Examples
1224	///
1225	/// ```
1226	/// use reinhardt_db::orm::functions::CurrentDate;
1227	///
1228	/// let current_date = CurrentDate::new();
1229	/// assert_eq!(current_date.to_sql(), "CURRENT_DATE");
1230	/// ```
1231	pub fn new() -> Self {
1232		Self
1233	}
1234	/// Documentation for `to_sql`
1235	///
1236	pub fn to_sql(&self) -> String {
1237		"CURRENT_DATE".to_string()
1238	}
1239}
1240
1241impl Default for CurrentDate {
1242	fn default() -> Self {
1243		Self::new()
1244	}
1245}
1246
1247/// CurrentTime - current time
1248#[derive(Debug, Clone, Serialize, Deserialize)]
1249pub struct CurrentTime;
1250
1251impl CurrentTime {
1252	/// Create a CurrentTime function to get the current time
1253	///
1254	/// # Examples
1255	///
1256	/// ```
1257	/// use reinhardt_db::orm::functions::CurrentTime;
1258	///
1259	/// let current_time = CurrentTime::new();
1260	/// assert_eq!(current_time.to_sql(), "CURRENT_TIME");
1261	/// ```
1262	pub fn new() -> Self {
1263		Self
1264	}
1265	/// Documentation for `to_sql`
1266	///
1267	pub fn to_sql(&self) -> String {
1268		"CURRENT_TIME".to_string()
1269	}
1270}
1271
1272impl Default for CurrentTime {
1273	fn default() -> Self {
1274		Self::new()
1275	}
1276}
1277
1278#[cfg(test)]
1279mod tests {
1280	use super::*;
1281	use crate::orm::annotation::Value;
1282	use crate::orm::expressions::F;
1283
1284	#[test]
1285	fn test_cast_to_integer() {
1286		let cast = Cast::new(AnnotationValue::Field(F::new("price")), SqlType::Integer);
1287		assert_eq!(cast.to_sql(), "CAST(\"price\" AS INTEGER)");
1288	}
1289
1290	#[test]
1291	fn test_cast_to_varchar() {
1292		let cast = Cast::new(
1293			AnnotationValue::Field(F::new("id")),
1294			SqlType::Varchar { length: Some(50) },
1295		);
1296		assert_eq!(cast.to_sql(), "CAST(\"id\" AS VARCHAR(50))");
1297	}
1298
1299	#[test]
1300	fn test_greatest() {
1301		let greatest = Greatest::new(vec![
1302			AnnotationValue::Field(F::new("price1")),
1303			AnnotationValue::Field(F::new("price2")),
1304			AnnotationValue::Value(Value::Int(100)),
1305		])
1306		.unwrap();
1307		assert_eq!(greatest.to_sql(), "GREATEST(\"price1\", \"price2\", 100)");
1308	}
1309
1310	#[test]
1311	fn test_least() {
1312		let least = Least::new(vec![
1313			AnnotationValue::Field(F::new("score1")),
1314			AnnotationValue::Field(F::new("score2")),
1315		])
1316		.unwrap();
1317		assert_eq!(least.to_sql(), "LEAST(\"score1\", \"score2\")");
1318	}
1319
1320	#[test]
1321	fn test_nullif() {
1322		let nullif = NullIf::new(
1323			AnnotationValue::Field(F::new("status")),
1324			AnnotationValue::Value(Value::String("inactive".into())),
1325		);
1326		assert_eq!(nullif.to_sql(), "NULLIF(\"status\", 'inactive')");
1327	}
1328
1329	#[test]
1330	fn test_concat() {
1331		let concat = Concat::new(vec![
1332			AnnotationValue::Field(F::new("first_name")),
1333			AnnotationValue::Value(Value::String(" ".into())),
1334			AnnotationValue::Field(F::new("last_name")),
1335		])
1336		.unwrap();
1337		assert_eq!(
1338			concat.to_sql(),
1339			"CONCAT(\"first_name\", ' ', \"last_name\")"
1340		);
1341	}
1342
1343	#[test]
1344	fn test_upper() {
1345		let upper = Upper::new(AnnotationValue::Field(F::new("name")));
1346		assert_eq!(upper.to_sql(), "UPPER(\"name\")");
1347	}
1348
1349	#[test]
1350	fn test_lower() {
1351		let lower = Lower::new(AnnotationValue::Field(F::new("email")));
1352		assert_eq!(lower.to_sql(), "LOWER(\"email\")");
1353	}
1354
1355	#[test]
1356	fn test_length() {
1357		let length = Length::new(AnnotationValue::Field(F::new("description")));
1358		assert_eq!(length.to_sql(), "LENGTH(\"description\")");
1359	}
1360
1361	#[test]
1362	fn test_trim() {
1363		let trim = Trim::new(AnnotationValue::Field(F::new("name")));
1364		assert_eq!(trim.to_sql(), "TRIM(\"name\")");
1365	}
1366
1367	#[test]
1368	fn test_trim_leading() {
1369		let trim = Trim::new(AnnotationValue::Field(F::new("name"))).leading();
1370		assert_eq!(trim.to_sql(), "LTRIM(\"name\")");
1371	}
1372
1373	#[test]
1374	fn test_substr() {
1375		let substr = Substr::new(
1376			AnnotationValue::Field(F::new("description")),
1377			AnnotationValue::Value(Value::Int(1)),
1378			Some(AnnotationValue::Value(Value::Int(100))),
1379		);
1380		assert_eq!(substr.to_sql(), "SUBSTR(\"description\", 1, 100)");
1381	}
1382
1383	#[test]
1384	fn test_abs() {
1385		let abs = Abs::new(AnnotationValue::Field(F::new("balance")));
1386		assert_eq!(abs.to_sql(), "ABS(\"balance\")");
1387	}
1388
1389	#[test]
1390	fn test_ceil() {
1391		let ceil = Ceil::new(AnnotationValue::Field(F::new("price")));
1392		assert_eq!(ceil.to_sql(), "CEIL(\"price\")");
1393	}
1394
1395	#[test]
1396	fn test_floor() {
1397		let floor = Floor::new(AnnotationValue::Field(F::new("score")));
1398		assert_eq!(floor.to_sql(), "FLOOR(\"score\")");
1399	}
1400
1401	#[test]
1402	fn test_round() {
1403		let round = Round::new(AnnotationValue::Field(F::new("price")), Some(2));
1404		assert_eq!(round.to_sql(), "ROUND(\"price\", 2)");
1405	}
1406
1407	#[test]
1408	fn test_mod() {
1409		let mod_op = Mod::new(
1410			AnnotationValue::Field(F::new("value")),
1411			AnnotationValue::Value(Value::Int(10)),
1412		);
1413		assert_eq!(mod_op.to_sql(), "MOD(\"value\", 10)");
1414	}
1415
1416	#[test]
1417	fn test_power() {
1418		let power = Power::new(
1419			AnnotationValue::Field(F::new("base")),
1420			AnnotationValue::Value(Value::Int(2)),
1421		);
1422		assert_eq!(power.to_sql(), "POWER(\"base\", 2)");
1423	}
1424
1425	#[test]
1426	fn test_sqrt() {
1427		let sqrt = Sqrt::new(AnnotationValue::Field(F::new("area")));
1428		assert_eq!(sqrt.to_sql(), "SQRT(\"area\")");
1429	}
1430
1431	#[test]
1432	fn test_greatest_minimum_expressions() {
1433		let result = Greatest::new(vec![AnnotationValue::Field(F::new("x"))]);
1434		assert!(result.is_err());
1435	}
1436
1437	#[test]
1438	fn test_least_minimum_expressions() {
1439		let result = Least::new(vec![AnnotationValue::Field(F::new("x"))]);
1440		assert!(result.is_err());
1441	}
1442
1443	#[test]
1444	fn test_concat_minimum_expressions() {
1445		let result = Concat::new(vec![AnnotationValue::Field(F::new("x"))]);
1446		assert!(result.is_err());
1447	}
1448
1449	#[test]
1450	fn test_extract_year() {
1451		let extract = Extract::year(AnnotationValue::Field(F::new("created_at")));
1452		assert_eq!(extract.to_sql(), "EXTRACT(YEAR FROM \"created_at\")");
1453	}
1454
1455	#[test]
1456	fn test_extract_month() {
1457		let extract = Extract::month(AnnotationValue::Field(F::new("order_date")));
1458		assert_eq!(extract.to_sql(), "EXTRACT(MONTH FROM \"order_date\")");
1459	}
1460
1461	#[test]
1462	fn test_extract_day() {
1463		let extract = Extract::day(AnnotationValue::Field(F::new("timestamp")));
1464		assert_eq!(extract.to_sql(), "EXTRACT(DAY FROM \"timestamp\")");
1465	}
1466
1467	#[test]
1468	fn test_extract_hour() {
1469		let extract = Extract::hour(AnnotationValue::Field(F::new("event_time")));
1470		assert_eq!(extract.to_sql(), "EXTRACT(HOUR FROM \"event_time\")");
1471	}
1472
1473	#[test]
1474	fn test_orm_functions_now() {
1475		let now = Now::new();
1476		assert_eq!(now.to_sql(), "CURRENT_TIMESTAMP");
1477	}
1478
1479	#[test]
1480	fn test_current_date() {
1481		let date = CurrentDate::new();
1482		assert_eq!(date.to_sql(), "CURRENT_DATE");
1483	}
1484
1485	#[test]
1486	fn test_current_time() {
1487		let time = CurrentTime::new();
1488		assert_eq!(time.to_sql(), "CURRENT_TIME");
1489	}
1490}