I implemented the Repository Pattern as follow, there is allot of room for improvement, and I will be glad to improve it more.
use sqlx::{pool::PoolConnection, Postgres, Error};
use crate::models::application::model::Model;
#[async_trait::async_trait]
pub trait Repository<TEntity>
where
TEntity: Model,
{
/// get all entities
async fn get_all(&self, connection: PoolConnection<Postgres>) -> Result<Vec<TEntity>, Error>;
/// get a single entity by id
async fn get_by_id(&self, connection: PoolConnection<Postgres>, id: &String) -> Result<TEntity, String>;
/// add an entity to the database
async fn add(&mut self, connection: PoolConnection<Postgres>, entity: &TEntity) -> Result<(), String>;
/// update an entity
async fn update(&mut self, connection: PoolConnection<Postgres>, entity: &TEntity) -> Result<(), String>;
/// delete an entity by its id
async fn delete(&mut self, connection: PoolConnection<Postgres>, id: &String) -> Result<(), String>;
}
Now Implementation
pub use sqlx::{
pool::PoolConnection,
postgres::{PgArguments, PgPoolOptions, PgRow},
Arguments, Error, PgPool, Postgres, Row,
};
use crate::handlers::db_repository::Repository;
use crate::models::application::model::Model;
use crate::models::application::roles::users::User;
pub struct UserRepository { }
#[async_trait::async_trait]
impl Repository<User> for UserRepository {
async fn get_all(&self, mut connection: PoolConnection<Postgres>) -> Result<Vec<User>, Error> {
let result = sqlx::query("SELECT \"UserId\", \"Username\", \"DisplayName\", \"Language\", \"Password\", \"Salt\", \"StatusId\" FROM \"Role\".\"User\"")
.map(|row: PgRow| User::from_row(&row))
.fetch_all(&mut *connection)
.await?;
Ok(result)
}
async fn get_by_id(
&self,
mut connection: PoolConnection<Postgres>,
id: &String,
) -> Result<User, String> {
let mut args = PgArguments::default();
args.add(id);
let result = sqlx::query_with(
"SELECT \"UserId\", \"Username\", \"DisplayName\", \"Language\", \"Password\", \"Salt\", \"StatusId\" FROM \"Role\".\"User\" WHERE \"UserId\"='$1'",
args,
)
.map(|row: sqlx::postgres::PgRow| User::from_row(&row))
.fetch_one(&mut *connection)
.await;
Ok(result.unwrap())
}
async fn add(
&mut self,
mut connection: PoolConnection<Postgres>,
entity: &User,
) -> Result<(), String> {
let mut args = PgArguments::default();
args.add(entity.user_id.clone());
args.add(entity.username.clone());
args.add(entity.display_name.clone());
args.add(entity.language.clone());
args.add(entity.password.clone());
args.add(entity.salt.clone());
args.add(entity.status_id.clone());
let result = sqlx::query_with("INSERT INTO \"User\" (\"UserId\", \"Username\", \"DisplayName\", \"Language\", \"Password\", \"Salt\", \"StatusId\") VALUES ($1, $2, $3, $4, $5, $6, $7);", args)
.execute(&mut *connection)
.await;
match result {
Ok(_) => Ok(()),
Err(err) => Err(err.to_string()),
}
}
async fn update(
&mut self,
mut connection: PoolConnection<Postgres>,
entity: &User,
) -> Result<(), String> {
let mut args = PgArguments::default();
args.add(entity.user_id.clone());
args.add(entity.username.clone());
args.add(entity.display_name.clone());
args.add(entity.language.clone());
args.add(entity.password.clone());
args.add(entity.salt.clone());
args.add(entity.status_id.clone());
let result = sqlx::query_with("UPDATE \"User\" SET \"Username\" = $2, \"DisplayName\" = $3, \"Language\" = $4, \"Password\" = $5, \"Salt\" = $6, \"StatusId\" = $7 WHERE \"UserId\" = $1;", args)
.execute(&mut *connection)
.await;
match result {
Ok(_) => Ok(()),
Err(err) => Err(err.to_string()),
}
}
async fn delete(
&mut self,
mut connection: PoolConnection<Postgres>,
id: &String,
) -> Result<(), String> {
let mut args = PgArguments::default();
args.add(id);
let result = sqlx::query_with("DELETE FROM \"User\" WHERE \"UserId\" = $1;", args)
.execute(&mut *connection)
.await;
match result {
Ok(_) => Ok(()),
Err(err) => Err(err.to_string()),
}
}
}