mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2025-06-20 00:15:17 +00:00
Update mysql
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
use core::fmt;
|
||||
use std::error;
|
||||
use std::error::Error;
|
||||
use std::fmt::Formatter;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
/// Simple rust error
|
||||
///
|
||||
@ -21,7 +21,7 @@ impl ExecError {
|
||||
ExecError(msg.to_string())
|
||||
}
|
||||
|
||||
pub fn boxed_new(msg: &str) -> Box<ExecError> {
|
||||
pub fn boxed_new<D: Display>(msg: D) -> Box<ExecError> {
|
||||
Box::new(ExecError(msg.to_string()))
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,17 @@
|
||||
use std::collections;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::ops::Add;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use chrono::{TimeZone, Utc};
|
||||
use mysql::*;
|
||||
use mysql::{Binary, Pool, ResultSet, Value};
|
||||
use mysql::prelude::Queryable;
|
||||
use mysql::prelude::*;
|
||||
|
||||
use crate::data::admin::AdminID;
|
||||
use crate::data::config::{conf, DatabaseConfig};
|
||||
use crate::data::conversation::ConvID;
|
||||
use crate::data::error::{ExecError, Res, ResultBoxError};
|
||||
use crate::data::error::{ExecError, Res};
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::user::UserID;
|
||||
|
||||
@ -19,19 +19,19 @@ use crate::data::user::UserID;
|
||||
///
|
||||
/// @author Pierre Hubert
|
||||
|
||||
pub type ProcessRowResult<E> = Result<E, Box<dyn Error>>;
|
||||
pub type ProcessRowResult<E> = Res<E>;
|
||||
|
||||
// Pool shared across threads
|
||||
static mut POOL: Option<Arc<Mutex<mysql::Pool>>> = None;
|
||||
|
||||
/// Connect to the database
|
||||
pub fn connect(conf: &DatabaseConfig) -> Result<(), Box<dyn Error>> {
|
||||
pub fn connect(conf: &DatabaseConfig) -> Res {
|
||||
let url = format!(
|
||||
"mysql://{}:{}@{}:3306/{}",
|
||||
conf.username, conf.password, conf.host, conf.name
|
||||
);
|
||||
|
||||
let pool = Pool::new(url)?;
|
||||
let pool = Pool::new(Opts::from_url(&url)?)?;
|
||||
let pool = Some(Arc::new(Mutex::new(pool)));
|
||||
|
||||
unsafe {
|
||||
@ -42,7 +42,7 @@ pub fn connect(conf: &DatabaseConfig) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
/// Get a connection to the database
|
||||
pub fn get_connection() -> Result<mysql::PooledConn, Box<dyn Error>> {
|
||||
pub fn get_connection() -> Res<mysql::PooledConn> {
|
||||
let pool: Pool;
|
||||
|
||||
unsafe {
|
||||
@ -258,18 +258,18 @@ impl QueryInfo {
|
||||
|
||||
/// Execute query
|
||||
pub fn exec<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(self, process_function: F)
|
||||
-> Result<Vec<E>, Box<dyn Error>> {
|
||||
-> Res<Vec<E>> {
|
||||
query(self, process_function)
|
||||
}
|
||||
|
||||
/// Query just a row
|
||||
pub fn query_row<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(self, process_function: F)
|
||||
-> Result<E, Box<dyn Error>> {
|
||||
-> Res<E> {
|
||||
query_row(self, process_function)
|
||||
}
|
||||
|
||||
/// Execute count query
|
||||
pub fn exec_count(self) -> ResultBoxError<usize> {
|
||||
pub fn exec_count(self) -> Res<usize> {
|
||||
count(self)
|
||||
}
|
||||
|
||||
@ -281,7 +281,7 @@ impl QueryInfo {
|
||||
|
||||
/// Struct used to read the result of a request
|
||||
pub struct RowResult<'a> {
|
||||
row: &'a mysql::Row
|
||||
row: &'a mysql::Row,
|
||||
}
|
||||
|
||||
impl<'a> RowResult<'a> {
|
||||
@ -292,7 +292,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Find a column in result set
|
||||
fn find_col(&self, name: &str) -> Result<usize, ExecError> {
|
||||
fn find_col(&self, name: &str) -> Res<usize> {
|
||||
let name_bytes = name.as_bytes();
|
||||
let mut index = 0;
|
||||
for c in self.row.columns_ref() {
|
||||
@ -303,11 +303,11 @@ impl<'a> RowResult<'a> {
|
||||
index += 1;
|
||||
}
|
||||
|
||||
Err(ExecError(format!("Column {} not found in database result set!", name)))
|
||||
Err(ExecError::boxed_new(format!("Column {} not found in database result set!", name)))
|
||||
}
|
||||
|
||||
/// Find an integer included in the request
|
||||
pub fn get_int64(&self, name: &str) -> Result<i64, Box<dyn Error>> {
|
||||
pub fn get_int64(&self, name: &str) -> Res<i64> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -318,7 +318,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Find an integer included in the request
|
||||
pub fn get_u64(&self, name: &str) -> Result<u64, Box<dyn Error>> {
|
||||
pub fn get_u64(&self, name: &str) -> Res<u64> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -329,14 +329,14 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Get an optional unsigned number => Set to None if value is null / empty
|
||||
pub fn get_optional_u64(&self, name: &str) -> ResultBoxError<Option<u64>> {
|
||||
pub fn get_optional_u64(&self, name: &str) -> Res<Option<u64>> {
|
||||
match self.is_null(name)? {
|
||||
true => Ok(None),
|
||||
false => Ok(Some(self.get_u64(name)?))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_optional_u32(&self, name: &str) -> ResultBoxError<Option<u32>> {
|
||||
pub fn get_optional_u32(&self, name: &str) -> Res<Option<u32>> {
|
||||
match self.is_null(name)? {
|
||||
true => Ok(None),
|
||||
false => Ok(Some(self.get_u32(name)?))
|
||||
@ -344,14 +344,14 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Get an optional unsigned number => Set to None if value is null / empty / 0
|
||||
pub fn get_optional_positive_u64(&self, name: &str) -> ResultBoxError<Option<u64>> {
|
||||
pub fn get_optional_positive_u64(&self, name: &str) -> Res<Option<u64>> {
|
||||
Ok(match self.get_optional_u64(name)? {
|
||||
None | Some(0) => None,
|
||||
Some(val) => Some(val)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_u32(&self, name: &str) -> ResultBoxError<u32> {
|
||||
pub fn get_u32(&self, name: &str) -> Res<u32> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -361,7 +361,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_u16(&self, name: &str) -> ResultBoxError<u16> {
|
||||
pub fn get_u16(&self, name: &str) -> Res<u16> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -372,7 +372,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Find an integer included in the request
|
||||
pub fn get_usize(&self, name: &str) -> Result<usize, Box<dyn Error>> {
|
||||
pub fn get_usize(&self, name: &str) -> Res<usize> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -383,22 +383,22 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Get the ID of a user included in the request
|
||||
pub fn get_user_id(&self, name: &str) -> ResultBoxError<UserID> {
|
||||
pub fn get_user_id(&self, name: &str) -> Res<UserID> {
|
||||
Ok(UserID::new(self.get_u64(name)?))
|
||||
}
|
||||
|
||||
/// Get the ID of an admin included in the request
|
||||
pub fn get_admin_id(&self, name: &str) -> ResultBoxError<AdminID> {
|
||||
pub fn get_admin_id(&self, name: &str) -> Res<AdminID> {
|
||||
Ok(AdminID::new(self.get_u64(name)?))
|
||||
}
|
||||
|
||||
/// Get the ID of a group included in the response
|
||||
pub fn get_group_id(&self, name: &str) -> ResultBoxError<GroupID> {
|
||||
pub fn get_group_id(&self, name: &str) -> Res<GroupID> {
|
||||
Ok(GroupID::new(self.get_u64(name)?))
|
||||
}
|
||||
|
||||
/// Get the optional ID of a group included in the response
|
||||
pub fn get_optional_group_id(&self, name: &str) -> ResultBoxError<Option<GroupID>> {
|
||||
pub fn get_optional_group_id(&self, name: &str) -> Res<Option<GroupID>> {
|
||||
Ok(match self.get_optional_u64(name)? {
|
||||
None | Some(0) => None,
|
||||
Some(id) => Some(GroupID::new(id))
|
||||
@ -406,12 +406,12 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Get the ID of a conversation included in the response
|
||||
pub fn get_conv_id(&self, name: &str) -> ResultBoxError<ConvID> {
|
||||
pub fn get_conv_id(&self, name: &str) -> Res<ConvID> {
|
||||
Ok(ConvID::new(self.get_u64(name)?))
|
||||
}
|
||||
|
||||
/// Find a string included in the request
|
||||
pub fn get_str(&self, name: &str) -> Result<String, Box<dyn Error>> {
|
||||
pub fn get_str(&self, name: &str) -> Res<String> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -422,7 +422,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Check out whether a given value is null or not
|
||||
pub fn is_null(&self, name: &str) -> ResultBoxError<bool> {
|
||||
pub fn is_null(&self, name: &str) -> Res<bool> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
|
||||
match value {
|
||||
@ -433,7 +433,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Check out whether a given value is null or empty or not
|
||||
pub fn is_null_or_empty(&self, name: &str) -> ResultBoxError<bool> {
|
||||
pub fn is_null_or_empty(&self, name: &str) -> Res<bool> {
|
||||
if self.is_null(name)? {
|
||||
return Ok(true);
|
||||
}
|
||||
@ -442,7 +442,7 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Get an optional string => Set to None if string is null / empty
|
||||
pub fn get_optional_str(&self, name: &str) -> ResultBoxError<Option<String>> {
|
||||
pub fn get_optional_str(&self, name: &str) -> Res<Option<String>> {
|
||||
match self.is_null(name)? {
|
||||
true => Ok(None),
|
||||
false => Ok(Some(self.get_str(name)?).map_or(None, |d| {
|
||||
@ -455,12 +455,12 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
|
||||
/// Get legacy boolean value : 1 = true / 0 = false
|
||||
pub fn get_legacy_bool(&self, name: &str) -> ResultBoxError<bool> {
|
||||
pub fn get_legacy_bool(&self, name: &str) -> Res<bool> {
|
||||
Ok(self.get_int64(name)? == 1)
|
||||
}
|
||||
|
||||
/// Get a MYSQL date as a timestamp
|
||||
pub fn get_date_as_time(&self, name: &str) -> ResultBoxError<u64> {
|
||||
pub fn get_date_as_time(&self, name: &str) -> Res<u64> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
let value: Value = value.ok_or(ExecError(format!("Could not find date field {} !", name)))??;
|
||||
|
||||
@ -479,7 +479,7 @@ impl<'a> RowResult<'a> {
|
||||
|
||||
/// Query a single row of the database
|
||||
pub fn query_row<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(mut info: QueryInfo,
|
||||
process_function: F) -> Result<E, Box<dyn Error>> {
|
||||
process_function: F) -> Res<E> {
|
||||
let table = info.table.clone();
|
||||
|
||||
info.limit = 1;
|
||||
@ -494,7 +494,7 @@ pub fn query_row<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(mut info: QueryInf
|
||||
|
||||
/// Make a simple query
|
||||
pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, process_function: F)
|
||||
-> Result<Vec<E>, Box<dyn Error>> {
|
||||
-> Res<Vec<E>> {
|
||||
let mut params = vec![];
|
||||
|
||||
let select_elements = match info.fields.len() {
|
||||
@ -576,11 +576,11 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
|
||||
let mut res = con.exec_iter(stmt, params)?;
|
||||
|
||||
// This system is made to support only one dataset
|
||||
let result_set = res.next_set();
|
||||
let result_set = res.iter();
|
||||
if let None = result_set {
|
||||
return Err(Box::new(ExecError::new("No result set in a query!")));
|
||||
}
|
||||
let result_set: ResultSet<Binary> = result_set.unwrap()?;
|
||||
let result_set: ResultSet<Binary> = result_set.unwrap();
|
||||
|
||||
|
||||
// Parse each result of the dataset
|
||||
@ -598,7 +598,7 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
|
||||
}
|
||||
|
||||
/// Count the number of results a query would have produced
|
||||
pub fn count(mut q: QueryInfo) -> ResultBoxError<usize> {
|
||||
pub fn count(mut q: QueryInfo) -> Res<usize> {
|
||||
q.fields.clear();
|
||||
q.fields.push("COUNT(*) as count".to_string());
|
||||
|
||||
@ -725,25 +725,25 @@ impl InsertQuery {
|
||||
}
|
||||
|
||||
/// Process insert
|
||||
pub fn insert(self) -> ResultBoxError<Option<u64>> {
|
||||
pub fn insert(self) -> Res<Option<u64>> {
|
||||
insert(self)
|
||||
}
|
||||
|
||||
/// Process insert, drop the result of the operation
|
||||
pub fn insert_drop_result(self) -> ResultBoxError<()> {
|
||||
pub fn insert_drop_result(self) -> Res<()> {
|
||||
insert(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Process insert, excepting an ID in the response
|
||||
pub fn insert_expect_result(self) -> ResultBoxError<u64> {
|
||||
pub fn insert_expect_result(self) -> Res<u64> {
|
||||
let res = insert(self)?;
|
||||
res.ok_or(ExecError::boxed_new("Expected an ID in insert result!"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a new entry into the database
|
||||
pub fn insert(query: InsertQuery) -> ResultBoxError<Option<u64>> {
|
||||
pub fn insert(query: InsertQuery) -> Res<Option<u64>> {
|
||||
|
||||
// Collect keys
|
||||
let keys = query.values
|
||||
@ -862,13 +862,13 @@ impl DeleteQuery {
|
||||
}
|
||||
|
||||
/// Execute the delete query
|
||||
pub fn exec(self) -> ResultBoxError<()> {
|
||||
pub fn exec(self) -> Res<()> {
|
||||
delete(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete an entry from the database
|
||||
pub fn delete(query: DeleteQuery) -> ResultBoxError<()> {
|
||||
pub fn delete(query: DeleteQuery) -> Res<()> {
|
||||
if query.conditions.is_empty() && query.custom_where.is_none() {
|
||||
return Err(ExecError::boxed_new("DELETE without WHERE condition blocked for security reasons!"));
|
||||
}
|
||||
@ -993,9 +993,9 @@ impl UpdateInfo {
|
||||
}
|
||||
|
||||
/// Set an u64 number
|
||||
///
|
||||
/// None => 0
|
||||
/// Some => The value
|
||||
///
|
||||
/// None => 0
|
||||
/// Some => The value
|
||||
pub fn set_opt_u64_or_zero(mut self, name: &str, val: Option<u64>) -> UpdateInfo {
|
||||
self.set.insert(name.to_string(), Value::from(val.unwrap_or(0)));
|
||||
self
|
||||
@ -1025,13 +1025,13 @@ impl UpdateInfo {
|
||||
}
|
||||
|
||||
/// Execute the update
|
||||
pub fn exec(self) -> ResultBoxError<()> {
|
||||
pub fn exec(self) -> Res<()> {
|
||||
update(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute an update query
|
||||
pub fn update(u: UpdateInfo) -> ResultBoxError<()> {
|
||||
pub fn update(u: UpdateInfo) -> Res<()> {
|
||||
if u.cond.is_empty() {
|
||||
Err(ExecError::boxed_new("Update without conditions blocked for security!"))?;
|
||||
}
|
||||
|
Reference in New Issue
Block a user