fix: merge query with params

This commit is contained in:
Dmitriy Pleshevskiy 2021-02-19 22:17:01 +03:00
parent a7ab5572df
commit 7bd4f3d1f9
3 changed files with 45 additions and 26 deletions

View File

@ -4,6 +4,8 @@ pub trait ToSql {
fn to_sql(&self) -> String; fn to_sql(&self) -> String;
} }
pub type ToSqlParams<'a> = &'a [&'a dyn ToSql];
impl ToSql for &str { impl ToSql for &str {
fn to_sql(&self) -> String { fn to_sql(&self) -> String {
format!("'{}'", self) format!("'{}'", self)
@ -21,11 +23,39 @@ pub trait OpenDatabaseConnection: Sized {
pub trait DatabaseConnection { pub trait DatabaseConnection {
fn batch_execute(&mut self, query: &str) -> StdResult<()>; fn batch_execute(&mut self, query: &str) -> StdResult<()>;
fn execute<'b>(&mut self, query: &str, params: &'b [&'b dyn ToSql]) -> StdResult<u64>; fn execute<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult<u64>;
fn query<'b>( fn query<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult<Vec<Vec<String>>>;
&mut self, }
query: &str,
params: &'b [&'b dyn ToSql], pub(crate) fn merge_query_with_params(query: &str, params: ToSqlParams) -> String {
) -> StdResult<Vec<Vec<String>>>; params
.iter()
.enumerate()
.fold(query.to_string(), |acc, (i, p)| {
str::replace(&acc, &format!("${}", i + 1), &p.to_sql())
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merge_query_with_params_successfully() {
assert_eq!(
merge_query_with_params("SELECT $1", &[&"foo"]),
"SELECT 'foo'"
);
assert_eq!(
merge_query_with_params("SELECT $1, $2", &[&"foo", &"bar"]),
"SELECT 'foo', 'bar'"
);
assert_eq!(
merge_query_with_params("SELECT $1, $1", &[&"foo"]),
"SELECT 'foo', 'foo'"
);
}
} }

View File

@ -17,7 +17,10 @@ impl DatabaseConnectionManager {
} }
} }
pub fn connect_with_string(&self, connection_string: &str) -> StdResult<Box<dyn DatabaseConnection>> { pub fn connect_with_string(
&self,
connection_string: &str,
) -> StdResult<Box<dyn DatabaseConnection>> {
let conn = match self.config.client()? { let conn = match self.config.client()? {
SupportedDatabaseClient::Postgres => PostgresConnection::open(&connection_string)?, SupportedDatabaseClient::Postgres => PostgresConnection::open(&connection_string)?,
}; };

View File

@ -1,4 +1,4 @@
use crate::database::{DatabaseConnection, OpenDatabaseConnection, ToSql}; use crate::database::*;
use crate::error::StdResult; use crate::error::StdResult;
use postgres::{Client, NoTls}; use postgres::{Client, NoTls};
@ -19,29 +19,15 @@ impl DatabaseConnection for PostgresConnection {
Ok(()) Ok(())
} }
fn execute<'b>(&mut self, query: &str, params: &'b [&'b dyn ToSql]) -> StdResult<u64> { fn execute<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult<u64> {
let stmt = params let stmt = merge_query_with_params(query, params);
.iter()
.enumerate()
.fold(query.to_string(), |acc, (i, p)| {
str::replace(&acc, &format!("${}", i), &p.to_sql())
});
let res = self.client.execute(stmt.as_str(), &[])?; let res = self.client.execute(stmt.as_str(), &[])?;
Ok(res) Ok(res)
} }
fn query<'b>( fn query<'b>(&mut self, query: &str, params: ToSqlParams<'b>) -> StdResult<Vec<Vec<String>>> {
&mut self, let stmt = merge_query_with_params(query, params);
query: &str,
params: &'b [&'b dyn ToSql],
) -> StdResult<Vec<Vec<String>>> {
let stmt = params
.iter()
.enumerate()
.fold(query.to_string(), |acc, (i, p)| {
str::replace(&acc, &format!("${}", i), &p.to_sql())
});
let res = self.client.query(stmt.as_str(), &[])?; let res = self.client.query(stmt.as_str(), &[])?;