Skip to main content

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    Postgres representation of the CREATE INDEX operation.
66     */
67    #[cfg(feature = "postgres")]
68    Postgres(CreateIndexData<'until_build>),
69}
70
71impl<'until_build> CreateIndex<'until_build> for CreateIndexImpl<'until_build> {
72    fn unique(mut self) -> Self {
73        match self {
74            #[cfg(feature = "sqlite")]
75            CreateIndexImpl::Sqlite(ref mut d) => d.unique = true,
76            #[cfg(feature = "postgres")]
77            CreateIndexImpl::Postgres(ref mut d) => d.unique = true,
78        };
79        self
80    }
81
82    fn if_not_exists(mut self) -> Self {
83        match self {
84            #[cfg(feature = "sqlite")]
85            CreateIndexImpl::Sqlite(ref mut d) => d.if_not_exists = true,
86            #[cfg(feature = "postgres")]
87            CreateIndexImpl::Postgres(ref mut d) => d.if_not_exists = true,
88        };
89        self
90    }
91
92    fn add_column(mut self, column: &'until_build str) -> Self {
93        match self {
94            #[cfg(feature = "sqlite")]
95            CreateIndexImpl::Sqlite(ref mut d) => d.columns.push(column),
96            #[cfg(feature = "postgres")]
97            CreateIndexImpl::Postgres(ref mut d) => d.columns.push(column),
98        }
99        self
100    }
101
102    fn set_condition(mut self, condition: String) -> Self {
103        match self {
104            #[cfg(feature = "sqlite")]
105            CreateIndexImpl::Sqlite(ref mut d) => d.condition = Some(condition),
106            #[cfg(feature = "postgres")]
107            CreateIndexImpl::Postgres(ref mut d) => d.condition = Some(condition),
108        }
109        self
110    }
111
112    fn build(self) -> Result<String, Error> {
113        match self {
114            #[cfg(feature = "sqlite")]
115            CreateIndexImpl::Sqlite(d) => {
116                if d.columns.is_empty() {
117                    return Err(Error::SQLBuildError(format!(
118                        "Couldn't create index on {}: Missing column(s) to create the index on",
119                        d.table_name
120                    )));
121                }
122
123                Ok(format!(
124                    "CREATE {} INDEX{} {} ON {} ({}) {};",
125                    if d.unique { "UNIQUE" } else { "" },
126                    if d.if_not_exists {
127                        " IF NOT EXISTS"
128                    } else {
129                        ""
130                    },
131                    d.name,
132                    d.table_name,
133                    d.columns.join(", "),
134                    d.condition.as_ref().map_or("", |x| x.as_str()),
135                ))
136            }
137            #[cfg(feature = "postgres")]
138            CreateIndexImpl::Postgres(d) => {
139                if d.columns.is_empty() {
140                    return Err(Error::SQLBuildError(format!(
141                        "Couldn't create index on {}: Missing column(s) to create the index on",
142                        d.table_name
143                    )));
144                }
145
146                Ok(format!(
147                    "CREATE{} INDEX{} {} ON {} ({}){};",
148                    if d.unique { " UNIQUE" } else { "" },
149                    if d.if_not_exists {
150                        " IF NOT EXISTS"
151                    } else {
152                        ""
153                    },
154                    d.name,
155                    d.table_name,
156                    d.columns.join(", "),
157                    match d.condition {
158                        None => String::from(""),
159                        Some(cond) => format!(" WHERE {}", cond.as_str()),
160                    }
161                ))
162            }
163        }
164    }
165}