rorm_sql/
create_index.rs

1use crate::error::Error;
2
3/**
4Representation of a CREATE INDEX builder.
5*/
6pub trait CreateIndex<'until_build> {
7    /**
8    Creates a unique index.
9
10    Null values are considered different from all other null values.
11     */
12    fn unique(self) -> Self;
13
14    /**
15    Creates the index only if it doesn't exist yet.
16     */
17    fn if_not_exists(self) -> Self;
18
19    /**
20    Adds a column to the index.
21
22    **Parameter**:
23    - `column`: String representing the column to index.
24     */
25    fn add_column(self, column: &'until_build str) -> Self;
26
27    /**
28    Sets the condition to apply. This will build a partial index.
29
30    **Parameter**:
31    - `condition`: String representing condition to apply the index to
32     */
33    fn set_condition(self, condition: String) -> Self;
34
35    /**
36    This method is used to build the create index operation
37     */
38    fn build(self) -> Result<String, Error>;
39}
40
41/**
42Representation of a create index operation
43*/
44pub struct CreateIndexData<'until_build> {
45    pub(crate) name: &'until_build str,
46    pub(crate) table_name: &'until_build str,
47    pub(crate) unique: bool,
48    pub(crate) if_not_exists: bool,
49    pub(crate) columns: Vec<&'until_build str>,
50    pub(crate) condition: Option<String>,
51}
52
53/**
54Implementation of database specific implementations of the [CreateIndex] trait.
55
56Should only be constructed via [crate::DBImpl::create_index].
57*/
58pub enum CreateIndexImpl<'until_build> {
59    /**
60    SQLite representation of the CREATE INDEX operation.
61     */
62    #[cfg(feature = "sqlite")]
63    Sqlite(CreateIndexData<'until_build>),
64    /**
65    MySQL representation of the CREATE INDEX operation.
66     */
67    #[cfg(feature = "mysql")]
68    MySQL(CreateIndexData<'until_build>),
69    /**
70    Postgres representation of the CREATE INDEX operation.
71     */
72    #[cfg(feature = "postgres")]
73    Postgres(CreateIndexData<'until_build>),
74}
75
76impl<'until_build> CreateIndex<'until_build> for CreateIndexImpl<'until_build> {
77    fn unique(mut self) -> Self {
78        match self {
79            #[cfg(feature = "sqlite")]
80            CreateIndexImpl::Sqlite(ref mut d) => d.unique = true,
81            #[cfg(feature = "mysql")]
82            CreateIndexImpl::MySQL(ref mut d) => d.unique = true,
83            #[cfg(feature = "postgres")]
84            CreateIndexImpl::Postgres(ref mut d) => d.unique = true,
85        };
86        self
87    }
88
89    fn if_not_exists(mut self) -> Self {
90        match self {
91            #[cfg(feature = "sqlite")]
92            CreateIndexImpl::Sqlite(ref mut d) => d.if_not_exists = true,
93            #[cfg(feature = "mysql")]
94            CreateIndexImpl::MySQL(ref mut d) => d.if_not_exists = true,
95            #[cfg(feature = "postgres")]
96            CreateIndexImpl::Postgres(ref mut d) => d.if_not_exists = true,
97        };
98        self
99    }
100
101    fn add_column(mut self, column: &'until_build str) -> Self {
102        match self {
103            #[cfg(feature = "sqlite")]
104            CreateIndexImpl::Sqlite(ref mut d) => d.columns.push(column),
105            #[cfg(feature = "mysql")]
106            CreateIndexImpl::MySQL(ref mut d) => d.columns.push(column),
107            #[cfg(feature = "postgres")]
108            CreateIndexImpl::Postgres(ref mut d) => d.columns.push(column),
109        }
110        self
111    }
112
113    fn set_condition(mut self, condition: String) -> Self {
114        match self {
115            #[cfg(feature = "sqlite")]
116            CreateIndexImpl::Sqlite(ref mut d) => d.condition = Some(condition),
117            #[cfg(feature = "mysql")]
118            CreateIndexImpl::MySQL(ref mut d) => d.condition = Some(condition),
119            #[cfg(feature = "postgres")]
120            CreateIndexImpl::Postgres(ref mut d) => d.condition = Some(condition),
121        }
122        self
123    }
124
125    fn build(self) -> Result<String, Error> {
126        match self {
127            #[cfg(feature = "sqlite")]
128            CreateIndexImpl::Sqlite(d) => {
129                if d.columns.is_empty() {
130                    return Err(Error::SQLBuildError(format!(
131                        "Couldn't create index on {}: Missing column(s) to create the index on",
132                        d.table_name
133                    )));
134                }
135
136                Ok(format!(
137                    "CREATE {} INDEX{} {} ON {} ({}) {};",
138                    if d.unique { "UNIQUE" } else { "" },
139                    if d.if_not_exists {
140                        " IF NOT EXISTS"
141                    } else {
142                        ""
143                    },
144                    d.name,
145                    d.table_name,
146                    d.columns.join(", "),
147                    d.condition.as_ref().map_or("", |x| x.as_str()),
148                ))
149            }
150            #[cfg(feature = "mysql")]
151            CreateIndexImpl::MySQL(d) => {
152                if d.columns.is_empty() {
153                    return Err(Error::SQLBuildError(format!(
154                        "Couldn't create index on {}: Missing column(s) to create the index on",
155                        d.table_name
156                    )));
157                }
158
159                Ok(format!(
160                    "CREATE {} INDEX{} {} ON {} ({});",
161                    if d.unique { "UNIQUE" } else { "" },
162                    if d.if_not_exists {
163                        " IF NOT EXISTS"
164                    } else {
165                        ""
166                    },
167                    d.name,
168                    d.table_name,
169                    d.columns.join(", "),
170                ))
171            }
172            #[cfg(feature = "postgres")]
173            CreateIndexImpl::Postgres(d) => {
174                if d.columns.is_empty() {
175                    return Err(Error::SQLBuildError(format!(
176                        "Couldn't create index on {}: Missing column(s) to create the index on",
177                        d.table_name
178                    )));
179                }
180
181                Ok(format!(
182                    "CREATE{} INDEX{} {} ON {} ({}){};",
183                    if d.unique { " UNIQUE" } else { "" },
184                    if d.if_not_exists {
185                        " IF NOT EXISTS"
186                    } else {
187                        ""
188                    },
189                    d.name,
190                    d.table_name,
191                    d.columns.join(", "),
192                    match d.condition {
193                        None => String::from(""),
194                        Some(cond) => format!(" WHERE {}", cond.as_str()),
195                    }
196                ))
197            }
198        }
199    }
200}