parent
2025a39e62
commit
79bbed4fe0
@ -1,24 +1,35 @@
|
||||
use crate::simple::{HandlingError, TraitFuture};
|
||||
use crate::simple::HandlingError;
|
||||
use crate::simple::TraitFuture;
|
||||
|
||||
pub struct Robot {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub trait DefaultRepository {
|
||||
fn add(&mut self, r: Robot) -> TraitFuture<Result<i64, HandlingError>>;
|
||||
fn update(&mut self, r: Robot) -> TraitFuture<Result<(), HandlingError>>;
|
||||
fn delete(&mut self, id: i64) -> TraitFuture<Result<(), HandlingError>>;
|
||||
pub trait DefaultRepository<'f> {
|
||||
fn add(&'f mut self, r: Robot) -> TraitFuture<'f, Result<i64, HandlingError>>;
|
||||
fn get_by_id(&'f mut self, id: i64) -> TraitFuture<'f, Result<Robot, HandlingError>>;
|
||||
fn update(&'f mut self, r: Robot) -> TraitFuture<Result<(), HandlingError>>;
|
||||
fn delete(&'f mut self, id: i64) -> TraitFuture<Result<(), HandlingError>>;
|
||||
}
|
||||
|
||||
pub async fn add(repo: &mut impl DefaultRepository, r: Robot) -> Result<i64, HandlingError> {
|
||||
pub async fn add<'a>(
|
||||
repo: &'a mut impl DefaultRepository<'a>,
|
||||
r: Robot,
|
||||
) -> Result<i64, HandlingError> {
|
||||
repo.add(r).await
|
||||
}
|
||||
|
||||
pub async fn update(repo: &mut impl DefaultRepository, r: Robot) -> Result<(), HandlingError> {
|
||||
pub async fn update<'a>(
|
||||
repo: &'a mut impl DefaultRepository<'a>,
|
||||
r: Robot,
|
||||
) -> Result<(), HandlingError> {
|
||||
repo.update(r).await
|
||||
}
|
||||
|
||||
pub async fn delete(repo: &mut impl DefaultRepository, id: i64) -> Result<(), HandlingError> {
|
||||
pub async fn delete<'a>(
|
||||
repo: &'a mut impl DefaultRepository<'a>,
|
||||
id: i64,
|
||||
) -> Result<(), HandlingError> {
|
||||
repo.delete(id).await
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
pub mod postgres;
|
||||
pub mod robots;
|
||||
|
||||
@ -1,162 +0,0 @@
|
||||
use crate::simple::TraitFuture;
|
||||
use std::boxed::Box;
|
||||
|
||||
use crate::base::robots;
|
||||
use crate::simple::HandlingError;
|
||||
|
||||
use sqlx::Done;
|
||||
use sqlx::FromRow;
|
||||
|
||||
pub struct Collection<'a> {
|
||||
tx: &'a mut Box<sqlx::Transaction<'static, sqlx::Postgres>>,
|
||||
q: sqlx::query::Query<'a, sqlx::Postgres, sqlx::postgres::PgArguments>,
|
||||
q_id: Option<i64>,
|
||||
}
|
||||
|
||||
impl Collection<'_> {
|
||||
#[allow(dead_code)]
|
||||
pub fn by_id(self, id: i64) -> Self {
|
||||
Self {
|
||||
tx: self.tx,
|
||||
q: self.q,
|
||||
q_id: Some(id),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fetch(self, offset: i64, limit: i64) -> Result<Vec<robots::Robot>, HandlingError> {
|
||||
let result = self
|
||||
.q
|
||||
.bind(self.q_id.is_some())
|
||||
.bind(self.q_id.unwrap_or_default())
|
||||
.bind(offset)
|
||||
.bind(limit)
|
||||
.fetch_all(self.tx.as_mut())
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => v
|
||||
.into_iter()
|
||||
.map(|d| {
|
||||
let (id, name) = <(i64, String)>::from_row(&d)?;
|
||||
Ok(robots::Robot { id: id, name: name })
|
||||
})
|
||||
.collect(),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn paginate(
|
||||
self,
|
||||
offset: i64,
|
||||
limit: i64,
|
||||
) -> Result<(Vec<robots::Robot>, bool), HandlingError> {
|
||||
let mut items = self.fetch(offset, limit + 1).await?;
|
||||
if items.len() > (limit as usize) {
|
||||
let _ = items.pop();
|
||||
Ok((items, true))
|
||||
} else {
|
||||
Ok((items, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RobotsImpl<'a> {
|
||||
pub tx: &'a mut Box<sqlx::Transaction<'static, sqlx::Postgres>>,
|
||||
}
|
||||
|
||||
impl<'a> RobotsImpl<'_> {
|
||||
pub fn new<'b>(tx: &'b mut Box<sqlx::Transaction<'static, sqlx::Postgres>>) -> RobotsImpl<'b> {
|
||||
RobotsImpl { tx: tx }
|
||||
}
|
||||
|
||||
async fn add(&mut self, r: robots::Robot) -> Result<i64, HandlingError> {
|
||||
let result = sqlx::query("INSERT INTO robots (name) VALUES ($1::TEXT) RETURNING id")
|
||||
.bind(r.name)
|
||||
.fetch_one(self.tx.as_mut())
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
let (id,) = <(i64,)>::from_row(&v)?;
|
||||
Ok(id)
|
||||
}
|
||||
Err(sqlx::Error::RowNotFound) => Err(HandlingError::NotFound),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_id(&mut self, id: i64) -> Result<robots::Robot, HandlingError> {
|
||||
let result = sqlx::query("SELECT * FROM robots WHERE id = $1::INTEGER")
|
||||
.bind(id)
|
||||
.fetch_one(self.tx.as_mut())
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
let (id, name) = <(i64, String)>::from_row(&v)?;
|
||||
Ok(robots::Robot { id: id, name: name })
|
||||
}
|
||||
Err(sqlx::Error::RowNotFound) => Err(HandlingError::NotFound),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_all(&'a mut self) -> Result<Collection<'a>, HandlingError> {
|
||||
let all = sqlx::query::<sqlx::Postgres>(
|
||||
"SELECT id, name
|
||||
FROM robots
|
||||
WHERE
|
||||
(CASE WHEN $1::BOOLEAN THEN (id = $2::INTEGER) ELSE TRUE END)
|
||||
OFFSET $3
|
||||
LIMIT $4",
|
||||
);
|
||||
Ok(Collection {
|
||||
tx: self.tx,
|
||||
q: all,
|
||||
q_id: None,
|
||||
})
|
||||
}
|
||||
|
||||
async fn update(&mut self, r: robots::Robot) -> Result<(), HandlingError> {
|
||||
let result = sqlx::query("UPDATE robots SET name = $1::TEXT WHERE id = $2::INTEGER")
|
||||
.bind(r.name)
|
||||
.bind(r.id)
|
||||
.execute(self.tx.as_mut())
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => match v.rows_affected() {
|
||||
1 => Ok(()),
|
||||
0 => Err(HandlingError::NotFound),
|
||||
_ => Err(HandlingError::InternalError),
|
||||
},
|
||||
Err(sqlx::Error::RowNotFound) => Err(HandlingError::NotFound),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete(&mut self, id: i64) -> Result<(), HandlingError> {
|
||||
let result = sqlx::query("DELETE FROM robots WHERE id = $1::INTEGER")
|
||||
.bind(id)
|
||||
.execute(self.tx.as_mut())
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => match v.rows_affected() {
|
||||
1 => Ok(()),
|
||||
0 => Err(HandlingError::NotFound),
|
||||
_ => Err(HandlingError::InternalError),
|
||||
},
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl robots::DefaultRepository for RobotsImpl<'_> {
|
||||
fn add(&mut self, r: robots::Robot) -> TraitFuture<Result<i64, HandlingError>> {
|
||||
Box::pin(self.add(r))
|
||||
}
|
||||
|
||||
fn update(&mut self, r: robots::Robot) -> TraitFuture<Result<(), HandlingError>> {
|
||||
Box::pin(self.update(r))
|
||||
}
|
||||
|
||||
fn delete(&mut self, id: i64) -> TraitFuture<Result<(), HandlingError>> {
|
||||
Box::pin(self.delete(id))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
pub mod postgres;
|
||||
@ -0,0 +1,183 @@
|
||||
use crate::simple::TraitFuture;
|
||||
|
||||
use std::boxed::Box;
|
||||
|
||||
use crate::base::robots;
|
||||
use crate::simple::HandlingError;
|
||||
|
||||
use sqlx::Done;
|
||||
use sqlx::FromRow;
|
||||
|
||||
pub struct Collection<'a, E> {
|
||||
tx: &'a mut Box<E>,
|
||||
q: sqlx::query::Query<'a, sqlx::Postgres, sqlx::postgres::PgArguments>,
|
||||
q_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'c, E> Collection<'c, E>
|
||||
where
|
||||
&'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres> + 'c,
|
||||
{
|
||||
pub fn new(tx: &'c mut Box<E>) -> Collection<'c, E> {
|
||||
let all = sqlx::query::<sqlx::Postgres>(
|
||||
"SELECT id, name
|
||||
FROM robots
|
||||
WHERE
|
||||
(CASE WHEN $1::BOOLEAN THEN (id = $2::INTEGER) ELSE TRUE END)
|
||||
OFFSET $3
|
||||
LIMIT $4",
|
||||
);
|
||||
Self {
|
||||
tx: tx,
|
||||
q: all,
|
||||
q_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn by_id(self, id: i64) -> Self {
|
||||
Self {
|
||||
tx: self.tx,
|
||||
q: self.q,
|
||||
q_id: Some(id),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fetch(self, offset: i64, limit: i64) -> Result<Vec<robots::Robot>, HandlingError> {
|
||||
let result = self
|
||||
.q
|
||||
.bind(self.q_id.is_some())
|
||||
.bind(self.q_id.unwrap_or_default())
|
||||
.bind(offset)
|
||||
.bind(limit)
|
||||
.fetch_all(self.tx.as_mut())
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => v
|
||||
.into_iter()
|
||||
.map(|d| {
|
||||
let (id, name) = <(i64, String)>::from_row(&d)?;
|
||||
Ok(robots::Robot { id: id, name: name })
|
||||
})
|
||||
.collect(),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn paginate(
|
||||
self,
|
||||
offset: i64,
|
||||
limit: i64,
|
||||
) -> Result<(Vec<robots::Robot>, bool), HandlingError> {
|
||||
let mut items = self.fetch(offset, limit + 1).await?;
|
||||
if items.len() > (limit as usize) {
|
||||
let _ = items.pop();
|
||||
Ok((items, true))
|
||||
} else {
|
||||
Ok((items, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RobotsImpl<'a, E> {
|
||||
pub tx: &'a mut Box<E>,
|
||||
}
|
||||
|
||||
pub fn new<'a, E>(tx: &'a mut Box<E>) -> RobotsImpl<'a, E> {
|
||||
RobotsImpl::<'a, E> { tx: tx }
|
||||
}
|
||||
|
||||
async fn add(
|
||||
tx: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
r: robots::Robot,
|
||||
) -> Result<i64, HandlingError> {
|
||||
let result = sqlx::query("INSERT INTO robots (name) VALUES ($1::TEXT) RETURNING id")
|
||||
.bind(r.name)
|
||||
.fetch_one(tx)
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
let (id,) = <(i64,)>::from_row(&v)?;
|
||||
Ok(id)
|
||||
}
|
||||
Err(sqlx::Error::RowNotFound) => Err(HandlingError::NotFound),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_by_id(
|
||||
tx: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
id: i64,
|
||||
) -> Result<robots::Robot, HandlingError> {
|
||||
let result = sqlx::query("SELECT * FROM robots WHERE id = $1::INTEGER")
|
||||
.bind(id)
|
||||
.fetch_one(tx)
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => {
|
||||
let (id, name) = <(i64, String)>::from_row(&v)?;
|
||||
Ok(robots::Robot { id: id, name: name })
|
||||
}
|
||||
Err(sqlx::Error::RowNotFound) => Err(HandlingError::NotFound),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(
|
||||
tx: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
r: robots::Robot,
|
||||
) -> Result<(), HandlingError> {
|
||||
let result = sqlx::query("UPDATE robots SET name = $1::TEXT WHERE id = $2::INTEGER")
|
||||
.bind(r.name)
|
||||
.bind(r.id)
|
||||
.execute(tx)
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => match v.rows_affected() {
|
||||
1 => Ok(()),
|
||||
0 => Err(HandlingError::NotFound),
|
||||
_ => Err(HandlingError::InternalError),
|
||||
},
|
||||
Err(sqlx::Error::RowNotFound) => Err(HandlingError::NotFound),
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
async fn delete(
|
||||
tx: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
id: i64,
|
||||
) -> Result<(), HandlingError> {
|
||||
let result = sqlx::query("DELETE FROM robots WHERE id = $1::INTEGER")
|
||||
.bind(id)
|
||||
.execute(tx)
|
||||
.await;
|
||||
match result {
|
||||
Ok(v) => match v.rows_affected() {
|
||||
1 => Ok(()),
|
||||
0 => Err(HandlingError::NotFound),
|
||||
_ => Err(HandlingError::InternalError),
|
||||
},
|
||||
Err(e) => Err(HandlingError::DBError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'c, E> robots::DefaultRepository<'c> for RobotsImpl<'a, E>
|
||||
where
|
||||
&'c mut E: sqlx::Executor<'c, Database = sqlx::Postgres> + 'c,
|
||||
{
|
||||
fn add(&'c mut self, r: robots::Robot) -> TraitFuture<Result<i64, HandlingError>> {
|
||||
Box::pin(add(self.tx.as_mut(), r))
|
||||
}
|
||||
|
||||
fn get_by_id(&'c mut self, id: i64) -> TraitFuture<Result<robots::Robot, HandlingError>> {
|
||||
Box::pin(get_by_id(self.tx.as_mut(), id))
|
||||
}
|
||||
|
||||
fn update(&'c mut self, r: robots::Robot) -> TraitFuture<Result<(), HandlingError>> {
|
||||
Box::pin(update(self.tx.as_mut(), r))
|
||||
}
|
||||
|
||||
fn delete(&'c mut self, id: i64) -> TraitFuture<Result<(), HandlingError>> {
|
||||
Box::pin(delete(self.tx.as_mut(), id))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue