safety_postgres/access/
sql_base.rs

1use crate::access::errors::*;
2use crate::access::validators::validate_string;
3
4/// Represents the different types of SQL statements.
5#[derive(Clone)]
6pub(super) enum SqlType <'a> {
7    Select(&'a QueryColumns),
8    Update(&'a UpdateSets),
9    Insert(&'a InsertRecords),
10    Delete,
11}
12
13/// Trait for building SQL statements.
14///
15/// This trait defines a method for building SQL statements based on a given table name.
16trait SqlBuilder {
17    fn build_sql(&self, table_name: &str) -> String;
18}
19
20/// Represents a collection of query columns.
21///
22/// # Example
23///
24/// ```rust
25/// use safety_postgres::access::sql_base::QueryColumns;
26///
27/// let mut query_columns = QueryColumns::new(false);
28/// query_columns.add_column("schema_name", "table_name", "column_name").unwrap();
29///
30/// let query_text = query_columns.get_query_text();
31///
32/// assert_eq!(query_text, "SELECT schema_name.table_name.column_name FROM main_table_name");
33/// ```
34#[derive(Clone)]
35pub struct QueryColumns {
36    all_columns: bool,
37    columns: Vec<QueryColumn>,
38}
39
40/// Represents a single query column.
41#[derive(Clone)]
42struct QueryColumn {
43    schema_name: String,
44    table_name: String,
45    column: String,
46}
47
48impl QueryColumns {
49    /// Creates a new instance of `QueryColumns` struct.
50    ///
51    /// # Arguments
52    ///
53    /// * `all_columns` - A boolean value indicating whether all columns should be selected.
54    ///
55    pub fn new(all_columns: bool) -> Self {
56        Self {
57            all_columns,
58            columns: Vec::new(),
59        }
60    }
61
62    /// Adds a query selected column to the query.
63    ///
64    /// # Arguments
65    ///
66    /// * `schema_name` - The name of the schema (input "" if there is no schema name or in the same table).
67    /// * `table_name` - The name of the table (input "" if there is no table name or in the same table).
68    /// * `column` - The name of the column.
69    ///
70    /// # Returns
71    ///
72    /// Returns a mutable reference to `Self` (the query builder) on success, or a `QueryColumnError` on failure.
73    ///
74    /// # Errors
75    ///
76    /// An error is returned if:
77    /// * The `all_columns` flag is set to true, indicating that all columns will be queried,
78    /// so setting a specific column is not allowed.
79    /// * The `schema_name`, `table_name`, or `column` is an invalid string.
80    ///
81    /// # Example
82    ///
83    /// ```rust
84    /// use safety_postgres::access::sql_base::QueryColumns;
85    ///
86    /// let mut query_columns = QueryColumns::new(false);
87    /// query_columns.add_column("", "", "id").unwrap().add_column("", "", "username").unwrap();
88    /// ```
89    pub fn add_column(&mut self, schema_name: &str, table_name: &str, column: &str) -> Result<&mut Self, QueryColumnError> {
90        if self.all_columns {
91            return Err(QueryColumnError::InputInconsistentError("'all_columns' flag is true so all columns will queried so you can't set column. Please check your input.".to_string()));
92        }
93
94        validate_string(schema_name, "schema_name", &QueryColumnErrorGenerator)?;
95        validate_string(table_name, "table_name", &QueryColumnErrorGenerator)?;
96        validate_string(column, "column_name", &QueryColumnErrorGenerator)?;
97
98        let query_column = QueryColumn {
99            schema_name: schema_name.to_string(),
100            table_name: table_name.to_string(),
101            column: column.to_string(),
102        };
103
104        self.columns.push(query_column);
105        Ok(self)
106    }
107
108    /// Retrieves the query text for the current instance.
109    ///
110    /// # Returns
111    ///
112    /// A `String` representing the query text.
113    ///
114    /// # Example
115    ///
116    /// ```rust
117    /// use safety_postgres::access::sql_base::QueryColumns;
118    ///
119    /// let obj = QueryColumns::new(true);
120    /// let query_text = obj.get_query_text();
121    /// println!("Query Text: {}", query_text);
122    /// ```
123    pub fn get_query_text(&self) -> String {
124        self.build_sql("main_table_name")
125    }
126}
127
128impl SqlBuilder for QueryColumns {
129    /// Builds an SQL query based on the given parameters.
130    ///
131    /// # Arguments
132    ///
133    /// * `table_name` - The name of the table to query.
134    ///
135    /// # Returns
136    ///
137    /// A string representing the SQL query.
138    fn build_sql(&self, table_name: &str) -> String {
139        let mut sql_vec: Vec<String> = Vec::new();
140        sql_vec.push("SELECT".to_string());
141        if self.all_columns {
142            sql_vec.push("*".to_string());
143        }
144        else {
145            let mut columns: Vec<String> = Vec::new();
146            for query_column in &self.columns {
147                let mut column_condition: Vec<String> = Vec::new();
148                if !query_column.schema_name.is_empty() {
149                    column_condition.push(query_column.schema_name.clone());
150                }
151                if !query_column.table_name.is_empty() {
152                    column_condition.push(query_column.table_name.clone());
153                }
154                column_condition.push(query_column.column.clone());
155                columns.push(column_condition.join("."));
156            }
157            sql_vec.push(columns.join(", "));
158        }
159        sql_vec.push(format!("FROM {}", table_name));
160        sql_vec.join(" ")
161    }
162}
163
164/// Represents a collection of update sets.
165///
166/// Update sets are used to define the values to be updated in a database table.
167///
168/// # Example
169///
170/// ```rust
171/// use safety_postgres::access::sql_base::UpdateSets;
172///
173/// let mut update_sets = UpdateSets::new();
174///
175/// update_sets.add_set("column1", "value1").expect("adding update set failed");
176/// update_sets.add_set("column2", "value2").expect("adding update set failed");
177///
178/// let update_set_text = update_sets.get_update_text();
179///
180/// assert_eq!(update_set_text, "UPDATE main_table_name SET column1 = value1, column2 = value2");
181/// ```
182///
183#[derive(Clone)]
184pub struct UpdateSets {
185    update_sets: Vec<UpdateSet>
186}
187
188/// Represents a single column-value pair used in an update statement.
189///
190/// This struct is used to specify the column and its corresponding value for an update operation.
191#[derive(Clone)]
192struct UpdateSet {
193    column: String,
194    value: String,
195}
196
197impl UpdateSets {
198    /// Creates a new instance of the `UpdateSets` struct.
199    pub fn new() -> Self {
200        Self {
201            update_sets: Vec::new(),
202        }
203    }
204
205    /// Adds a set of column-value pair to the update sets of the struct.
206    ///
207    /// # Arguments
208    ///
209    /// * `column` - The name of the column to be updated.
210    /// * `value` - The new value for the column.
211    ///
212    /// # Errors
213    ///
214    /// Returns an `UpdateSetError` if the `column` is not a valid string.
215    ///
216    /// # Returns
217    ///
218    /// A mutable reference to `Self (UpdateSets)` on success.
219    ///
220    /// # Example
221    ///
222    /// ```rust
223    /// use safety_postgres::access::sql_base::UpdateSets;
224    ///
225    /// let mut update_sets = UpdateSets::new();
226    /// update_sets.add_set("name", "John").expect("adding update set failed");
227    /// ```
228    pub fn add_set(&mut self, column: &str, value: &str) -> Result<&mut Self, UpdateSetError> {
229        validate_string(column, "column", &UpdateSetErrorGenerator)?;
230
231        let update_set = UpdateSet {
232            column: column.to_string(),
233            value: value.to_string(),
234        };
235        self.update_sets.push(update_set);
236
237        Ok(self)
238    }
239
240    /// Retrieves all the values from the update sets as flatten vector.
241    ///
242    /// # Returns
243    ///
244    /// A vector of strings containing the values.
245    pub(super) fn get_flat_values(&self) -> Vec<String> {
246        let mut flat_values = Vec::new();
247        for update_set in &self.update_sets {
248            flat_values.push(update_set.value.clone());
249        }
250        flat_values
251    }
252
253    /// Returns the update text for the set parameters.
254    pub fn get_update_text(&self) -> String {
255        let mut update_text = self.build_sql("main_table_name");
256        let values = self.get_flat_values();
257        for (index, value) in values.iter().enumerate() {
258            update_text = update_text.replace(&format!("${}", index + 1), value);
259        }
260
261        update_text
262    }
263
264    /// Returns the number of values in the update sets.
265    ///
266    /// # Returns
267    ///
268    /// The number of values in the update sets.
269    pub fn get_num_values(&self) -> usize {
270        self.update_sets.len()
271    }
272}
273
274impl SqlBuilder for UpdateSets {
275    /// Builds an SQL UPDATE statement with the provided table name and set values.
276    ///
277    /// # Arguments
278    ///
279    /// * `table_name` - The name of the table to update.
280    ///
281    /// # Returns
282    ///
283    /// Returns the generated SQL statement as a string.
284    fn build_sql(&self, table_name: &str) -> String {
285        let mut sql_vec: Vec<String> = Vec::new();
286
287        sql_vec.push("UPDATE".to_string());
288        sql_vec.push(table_name.to_string());
289
290        let mut set_vec: Vec<String> = Vec::new();
291        for (index, update_set) in self.update_sets.iter().enumerate() {
292            set_vec.push(format!("{} = ${}", update_set.column, index + 1));
293        }
294        sql_vec.push(format!("SET {}", set_vec.join(", ")));
295
296        sql_vec.join(" ")
297    }
298}
299
300/// Represents a collection of insert records.
301///
302/// # Fields
303///
304/// - `keys`: A vector of strings representing the columns for the insert records.
305/// - `insert_records`: A vector of `InsertRecord` objects.
306///
307/// # Example
308///
309/// ```rust
310/// use safety_postgres::access::sql_base::InsertRecords;
311///
312/// let mut insert_records = InsertRecords::new(&["str_column1", "int_column2", "float_column3"]);
313///
314/// let record1 = vec!["value1", "2", "3.1"];
315/// let record2 = vec!["value3", "10", "0.7"];
316/// insert_records.add_record(&record1).expect("adding insert record failed");
317/// insert_records.add_record(&record2).expect("adding insert record failed");
318///
319/// let insert_query = insert_records.get_insert_text();
320///
321/// assert_eq!(
322///     insert_query,
323///     "INSERT INTO main_table_name (str_column1, int_column2, float_column3) VALUES (value1, 2, 3.1), (value3, 10, 0.7)"
324/// );
325/// ```
326#[derive(Clone)]
327pub struct InsertRecords {
328    keys: Vec<String>,
329    insert_records: Vec<InsertRecord>,
330}
331
332/// Represents the values of one record to be inserted into a table.
333#[derive(Clone)]
334struct InsertRecord {
335    values: Vec<String>,
336}
337
338impl InsertRecords {
339    /// Creates a new instance of the `Table` struct.
340    ///
341    /// # Arguments
342    ///
343    /// * `columns` - A slice of strings representing the column names to insert.
344    pub fn new(columns: &[&str]) -> Self {
345        let keys = columns.iter().map(|column| column.to_string()).collect::<Vec<String>>();
346
347        Self {
348            keys,
349            insert_records: Vec::new()
350        }
351    }
352
353    /// Adds a record to insert the database.
354    ///
355    /// # Arguments
356    ///
357    /// * `record` - A slice of strings representing the values to be inserted.
358    ///
359    /// # Returns
360    ///
361    /// Returns a mutable reference to the `Self` type. Returns an error of type `InsertValueError`
362    /// if there is an error during the insertion process.
363    ///
364    /// # Errors
365    ///
366    /// Returns an `InsertValueError` if some error occurred during process.
367    ///
368    /// # Examples
369    ///
370    /// ```rust
371    /// use safety_postgres::access::sql_base::InsertRecords;
372    ///
373    /// let mut insert_records = InsertRecords::new(&["first_name", "last_name", "age"]);
374    ///
375    /// let record = vec!["John", "Doe", "25"];
376    /// insert_records.add_record(&record).unwrap();
377    /// ```
378    pub fn add_record(&mut self, record: &[&str]) -> Result<&mut Self, InsertValueError> {
379        if self.insert_records.is_empty() {
380            self.keys.iter().map(|key| validate_string(key.as_str(), "columns", &InsertValueErrorGenerator)).collect::<Result<_, InsertValueError>>()?;
381        }
382        if record.len() != self.keys.len() {
383            return Err(InsertValueError::InputInconsistentError("'values' should match with the 'columns' number. Please input data.".to_string()));
384        }
385
386        let insert_record = InsertRecord {
387            values: record.iter().map(|value| value.to_string()).collect(),
388        };
389
390        self.insert_records.push(insert_record);
391
392        Ok(self)
393    }
394
395    /// Retrieves the insert text for the SQL statement.
396    ///
397    /// # Returns
398    ///
399    /// The insert text for the SQL statement.
400    ///
401    /// # Example
402    ///
403    /// ```
404    /// use safety_postgres::access::sql_base::InsertRecords;
405    ///
406    /// let columns = vec!["column1", "column2"];
407    /// let mut insert_records = InsertRecords::new(&columns);
408    ///
409    /// let record = vec!["value1", "value2"];
410    /// insert_records.add_record(&record).unwrap();
411    ///
412    /// let insert_text = insert_records.get_insert_text();
413    /// println!("Insert Text: {}", insert_text);
414    /// ```
415    pub fn get_insert_text(&self) -> String {
416        let mut insert_text = self.build_sql("main_table_name");
417        let values = self.get_flat_values();
418
419        for (index, value) in values.iter().enumerate() {
420            insert_text = insert_text.replace(&format!("${}", index + 1), value);
421        }
422
423        insert_text
424    }
425
426    /// Returns a vector of all the values from the insert records in a flattened vector.
427    ///
428    /// # Returns
429    ///
430    /// - `Vec<String>` - A vector containing all the values from the insert records.
431    pub(super) fn get_flat_values(&self) -> Vec<String> {
432        let mut flat_values = Vec::new();
433        for record in &self.insert_records {
434            flat_values.extend(record.values.clone());
435        }
436        flat_values
437    }
438}
439
440impl SqlBuilder for InsertRecords {
441    /// Builds an SQL statement for inserting records into a specified table.
442    ///
443    /// # Arguments
444    ///
445    /// * `table_name` - The name of the table to insert the records into.
446    ///
447    /// # Returns
448    ///
449    /// A string containing the SQL statement for inserting the records.
450    fn build_sql(&self, table_name: &str) -> String {
451        let mut sql_vec: Vec<String> = Vec::new();
452
453        sql_vec.extend(vec!["INSERT INTO".to_string(), table_name.to_string()]);
454        let number_elements = self.keys.len() * self.insert_records.len();
455        let mut values_placeholder_vec: Vec<String> = Vec::new();
456        for placeholder_index in 1..=number_elements {
457            match placeholder_index % self.keys.len() {
458                0 => values_placeholder_vec.push(format!("${})", placeholder_index)),
459                1 => values_placeholder_vec.push(format!("(${}", placeholder_index)),
460                _ => values_placeholder_vec.push(format!("${}", placeholder_index))
461            }
462        }
463        sql_vec.push(format!("({}) VALUES {}", self.keys.join(", "), values_placeholder_vec.join(", ")));
464        sql_vec.join(" ")
465    }
466
467}
468
469impl SqlType<'_> {
470    /// Function to build an SQL query based on the provided SqlType enum.
471    ///
472    /// # Arguments
473    ///
474    /// * `table_name` - The name of the table to perform the query on.
475    ///
476    /// # Returns
477    ///
478    /// A string representing the built SQL query.
479    pub(super) fn sql_build(&self, table_name: &str) -> String {
480        match self {
481            SqlType::Select(query_columns) => query_columns.build_sql(table_name),
482            SqlType::Insert(insert_values) => insert_values.build_sql(table_name),
483            SqlType::Update(update_sets) => update_sets.build_sql(table_name),
484            SqlType::Delete => format!("DELETE FROM {}", table_name),
485        }
486    }
487}