migrate to sqlite
NOTE: extension loading crashes docker (for some reason)
This commit is contained in:
383
backend/src/lib/outbound/sqlite/warrens.rs
Normal file
383
backend/src/lib/outbound/sqlite/warrens.rs
Normal file
@@ -0,0 +1,383 @@
|
||||
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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 PostgreSQL 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 (
|
||||
name,
|
||||
path
|
||||
) VALUES (
|
||||
$1,
|
||||
$2
|
||||
)
|
||||
RETURNING
|
||||
*
|
||||
",
|
||||
)
|
||||
.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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user