387 lines
9.9 KiB
Rust
387 lines
9.9 KiB
Rust
use anyhow::{Context as _, anyhow};
|
|
use sqlx::{Acquire as _, SqliteConnection};
|
|
use uuid::Uuid;
|
|
|
|
use crate::domain::warren::{
|
|
models::{
|
|
file::AbsoluteFilePath,
|
|
share::{
|
|
CreateShareError, CreateShareRequest, CreateShareResponse, DeleteShareError,
|
|
DeleteShareRequest, DeleteShareResponse, GetShareError, GetShareRequest,
|
|
ListSharesError, ListSharesRequest, ListSharesResponse, Share,
|
|
VerifySharePasswordError, VerifySharePasswordRequest, VerifySharePasswordResponse,
|
|
},
|
|
warren::{
|
|
CreateWarrenError, CreateWarrenRequest, DeleteWarrenError, DeleteWarrenRequest,
|
|
EditWarrenError, EditWarrenRequest, FetchWarrenError, FetchWarrenRequest,
|
|
FetchWarrensError, FetchWarrensRequest, ListWarrensError, ListWarrensRequest, Warren,
|
|
WarrenName,
|
|
},
|
|
},
|
|
ports::WarrenRepository,
|
|
};
|
|
|
|
use super::{Sqlite, is_not_found_error};
|
|
|
|
impl WarrenRepository for Sqlite {
|
|
async fn create_warren(
|
|
&self,
|
|
request: CreateWarrenRequest,
|
|
) -> Result<Warren, CreateWarrenError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let warren = self
|
|
.create_warren(&mut connection, request.name(), request.path())
|
|
.await
|
|
.context("Failed to create new warren")?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn edit_warren(&self, request: EditWarrenRequest) -> Result<Warren, EditWarrenError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let warren = self
|
|
.edit_warren(
|
|
&mut connection,
|
|
request.id(),
|
|
request.name(),
|
|
request.path(),
|
|
)
|
|
.await
|
|
.context("Failed to edit existing warren")?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn delete_warren(
|
|
&self,
|
|
request: DeleteWarrenRequest,
|
|
) -> Result<Warren, DeleteWarrenError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let warren = self
|
|
.delete_warren(&mut connection, request.id())
|
|
.await
|
|
.context("Failed to delete existing warren")?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn fetch_warrens(
|
|
&self,
|
|
request: FetchWarrensRequest,
|
|
) -> Result<Vec<Warren>, FetchWarrensError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let warrens = self
|
|
.fetch_warrens(&mut connection, request.ids())
|
|
.await
|
|
.map_err(|err| anyhow!(err).context("Failed to fetch warrens"))?;
|
|
|
|
Ok(warrens)
|
|
}
|
|
|
|
async fn list_warrens(
|
|
&self,
|
|
_request: ListWarrensRequest,
|
|
) -> Result<Vec<Warren>, ListWarrensError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let warrens = self
|
|
.fetch_all_warrens(&mut connection)
|
|
.await
|
|
.map_err(|err| anyhow!(err).context("Failed to list all warrens"))?;
|
|
|
|
Ok(warrens)
|
|
}
|
|
|
|
async fn fetch_warren(&self, request: FetchWarrenRequest) -> Result<Warren, FetchWarrenError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let warren = self
|
|
.get_warren(&mut connection, request.id())
|
|
.await
|
|
.map_err(|err| {
|
|
if is_not_found_error(&err) {
|
|
return FetchWarrenError::NotFound(request.id().clone());
|
|
}
|
|
|
|
anyhow!(err)
|
|
.context(format!("Failed to fetch warren with id {:?}", request.id()))
|
|
.into()
|
|
})?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn get_warren_share(&self, request: GetShareRequest) -> Result<Share, GetShareError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
super::share::get_share(&mut connection, request)
|
|
.await
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
async fn create_warren_share(
|
|
&self,
|
|
request: CreateShareRequest,
|
|
) -> Result<CreateShareResponse, CreateShareError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
super::share::create_share(&mut connection, request)
|
|
.await
|
|
.map(CreateShareResponse::new)
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
async fn list_warren_shares(
|
|
&self,
|
|
request: ListSharesRequest,
|
|
) -> Result<ListSharesResponse, ListSharesError> {
|
|
let warren = self.fetch_warren((&request).into()).await?;
|
|
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
let path = request.path().clone();
|
|
|
|
super::share::list_shares(&mut connection, request)
|
|
.await
|
|
.map(|shares| ListSharesResponse::new(warren, path, shares))
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
async fn delete_warren_share(
|
|
&self,
|
|
request: DeleteShareRequest,
|
|
) -> Result<DeleteShareResponse, DeleteShareError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
super::share::delete_share(&mut connection, request)
|
|
.await
|
|
.map(DeleteShareResponse::new)
|
|
.map_err(Into::into)
|
|
}
|
|
|
|
async fn verify_warren_share_password(
|
|
&self,
|
|
request: VerifySharePasswordRequest,
|
|
) -> Result<VerifySharePasswordResponse, VerifySharePasswordError> {
|
|
let mut connection = self
|
|
.pool
|
|
.acquire()
|
|
.await
|
|
.context("Failed to get a Sqlite connection")?;
|
|
|
|
super::share::verify_password(&mut connection, request)
|
|
.await
|
|
.map(VerifySharePasswordResponse::new)
|
|
.map_err(Into::into)
|
|
}
|
|
}
|
|
|
|
impl Sqlite {
|
|
async fn create_warren(
|
|
&self,
|
|
connection: &mut SqliteConnection,
|
|
name: &WarrenName,
|
|
path: &AbsoluteFilePath,
|
|
) -> Result<Warren, sqlx::Error> {
|
|
let mut tx = connection.begin().await?;
|
|
|
|
let warren: Warren = sqlx::query_as(
|
|
"
|
|
INSERT INTO warrens (
|
|
id,
|
|
name,
|
|
path
|
|
) VALUES (
|
|
$1,
|
|
$2,
|
|
$3
|
|
)
|
|
RETURNING
|
|
*
|
|
",
|
|
)
|
|
.bind(Uuid::new_v4())
|
|
.bind(name)
|
|
.bind(path)
|
|
.fetch_one(&mut *tx)
|
|
.await?;
|
|
|
|
tx.commit().await?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn edit_warren(
|
|
&self,
|
|
connection: &mut SqliteConnection,
|
|
id: &Uuid,
|
|
name: &WarrenName,
|
|
path: &AbsoluteFilePath,
|
|
) -> Result<Warren, sqlx::Error> {
|
|
let mut tx = connection.begin().await?;
|
|
|
|
let warren: Warren = sqlx::query_as(
|
|
"
|
|
UPDATE
|
|
warrens
|
|
SET
|
|
name = $2,
|
|
path = $3
|
|
WHERE
|
|
id = $1
|
|
RETURNING
|
|
*
|
|
",
|
|
)
|
|
.bind(id)
|
|
.bind(name)
|
|
.bind(path)
|
|
.fetch_one(&mut *tx)
|
|
.await?;
|
|
|
|
tx.commit().await?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn delete_warren(
|
|
&self,
|
|
connection: &mut SqliteConnection,
|
|
id: &Uuid,
|
|
) -> Result<Warren, sqlx::Error> {
|
|
let mut tx = connection.begin().await?;
|
|
|
|
let warren: Warren = sqlx::query_as(
|
|
"
|
|
DELETE FROM
|
|
warrens
|
|
WHERE
|
|
id = $1
|
|
RETURNING
|
|
*
|
|
",
|
|
)
|
|
.bind(id)
|
|
.fetch_one(&mut *tx)
|
|
.await?;
|
|
|
|
tx.commit().await?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn get_warren(
|
|
&self,
|
|
connection: &mut SqliteConnection,
|
|
id: &Uuid,
|
|
) -> Result<Warren, sqlx::Error> {
|
|
let warren: Warren = sqlx::query_as(
|
|
"
|
|
SELECT
|
|
*
|
|
FROM
|
|
warrens
|
|
WHERE
|
|
id = $1
|
|
",
|
|
)
|
|
.bind(id)
|
|
.fetch_one(connection)
|
|
.await?;
|
|
|
|
Ok(warren)
|
|
}
|
|
|
|
async fn fetch_warrens(
|
|
&self,
|
|
connection: &mut SqliteConnection,
|
|
ids: &[Uuid],
|
|
) -> Result<Vec<Warren>, sqlx::Error> {
|
|
let mut ids_as_string = ids.into_iter().fold(String::new(), |mut acc, id| {
|
|
let encoded = hex::encode(id.as_bytes());
|
|
acc.push_str("x'");
|
|
acc.push_str(encoded.as_str());
|
|
acc.push_str("',");
|
|
acc
|
|
});
|
|
ids_as_string.pop();
|
|
|
|
let warrens: Vec<Warren> = sqlx::query_as::<sqlx::Sqlite, Warren>(&format!(
|
|
"
|
|
SELECT
|
|
*
|
|
FROM
|
|
warrens
|
|
WHERE
|
|
id IN ({ids_as_string})
|
|
",
|
|
))
|
|
.fetch_all(&mut *connection)
|
|
.await?;
|
|
|
|
Ok(warrens)
|
|
}
|
|
|
|
async fn fetch_all_warrens(
|
|
&self,
|
|
connection: &mut SqliteConnection,
|
|
) -> Result<Vec<Warren>, sqlx::Error> {
|
|
let warrens: Vec<Warren> = sqlx::query_as::<sqlx::Sqlite, Warren>(
|
|
"
|
|
SELECT
|
|
*
|
|
FROM
|
|
warrens
|
|
",
|
|
)
|
|
.fetch_all(&mut *connection)
|
|
.await?;
|
|
|
|
Ok(warrens)
|
|
}
|
|
}
|