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 struct Robot {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DefaultRepository {
|
pub trait DefaultRepository<'f> {
|
||||||
fn add(&mut self, r: Robot) -> TraitFuture<Result<i64, HandlingError>>;
|
fn add(&'f mut self, r: Robot) -> TraitFuture<'f, Result<i64, HandlingError>>;
|
||||||
fn update(&mut self, r: Robot) -> TraitFuture<Result<(), HandlingError>>;
|
fn get_by_id(&'f mut self, id: i64) -> TraitFuture<'f, Result<Robot, HandlingError>>;
|
||||||
fn delete(&mut self, id: i64) -> TraitFuture<Result<(), 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
|
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
|
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
|
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