vantage_sql/primitives/
concat.rs1use std::fmt::{Debug, Display};
2
3use vantage_core::util::IntoVec;
4use vantage_expressions::{Expression, Expressive};
5
6#[derive(Debug, Clone)]
24pub struct Concat<T: Debug + Display + Clone> {
25 parts: Vec<Expression<T>>,
26 separator: Option<Expression<T>>,
27}
28
29impl<T: Debug + Display + Clone> Concat<T> {
30 pub fn new(parts: impl IntoVec<Expression<T>>) -> Self {
31 Self {
32 parts: parts.into_vec(),
33 separator: None,
34 }
35 }
36
37 pub fn ws(mut self, separator: impl Expressive<T>) -> Self {
39 self.separator = Some(separator.expr());
40 self
41 }
42}
43
44#[macro_export]
57macro_rules! concat_ {
58 ($($part:expr),+ $(,)?) => {
59 $crate::primitives::concat::Concat::new(vec![
60 $({
61 #[allow(unused_imports)]
62 use vantage_expressions::Expressive;
63 ($part).expr()
64 }),+
65 ])
66 };
67}
68
69#[cfg(feature = "sqlite")]
72impl Expressive<crate::sqlite::types::AnySqliteType>
73 for Concat<crate::sqlite::types::AnySqliteType>
74{
75 fn expr(&self) -> Expression<crate::sqlite::types::AnySqliteType> {
76 if let Some(sep) = &self.separator {
77 let mut interleaved = Vec::with_capacity(self.parts.len() * 2 - 1);
79 for (i, part) in self.parts.iter().enumerate() {
80 if i > 0 {
81 interleaved.push(sep.clone());
82 }
83 interleaved.push(part.clone());
84 }
85 Expression::from_vec(interleaved, " || ")
86 } else {
87 Expression::from_vec(self.parts.clone(), " || ")
88 }
89 }
90}
91
92#[cfg(feature = "mysql")]
95impl Expressive<crate::mysql::types::AnyMysqlType> for Concat<crate::mysql::types::AnyMysqlType> {
96 fn expr(&self) -> Expression<crate::mysql::types::AnyMysqlType> {
97 use vantage_expressions::ExpressiveEnum;
98
99 if let Some(sep) = &self.separator {
100 let mut all = vec![sep.clone()];
101 all.extend(self.parts.clone());
102 let args = Expression::from_vec(all, ", ");
103 Expression::new("CONCAT_WS({})", vec![ExpressiveEnum::Nested(args)])
104 } else {
105 let args = Expression::from_vec(self.parts.clone(), ", ");
106 Expression::new("CONCAT({})", vec![ExpressiveEnum::Nested(args)])
107 }
108 }
109}
110
111#[cfg(feature = "postgres")]
114impl Expressive<crate::postgres::types::AnyPostgresType>
115 for Concat<crate::postgres::types::AnyPostgresType>
116{
117 fn expr(&self) -> Expression<crate::postgres::types::AnyPostgresType> {
118 use vantage_expressions::ExpressiveEnum;
119
120 if let Some(sep) = &self.separator {
121 let mut all = vec![sep.clone()];
122 all.extend(self.parts.clone());
123 let args = Expression::from_vec(all, ", ");
124 Expression::new("CONCAT_WS({})", vec![ExpressiveEnum::Nested(args)])
125 } else {
126 Expression::from_vec(self.parts.clone(), " || ")
127 }
128 }
129}