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}