diff --git a/cipher_core/src/repository/mod.rs b/cipher_core/src/repository/mod.rs index 341d521..a596b33 100644 --- a/cipher_core/src/repository/mod.rs +++ b/cipher_core/src/repository/mod.rs @@ -1,7 +1,9 @@ use std::fmt::Display; +use staff_role_repository::StaffRoleRepository; use user_repository::UserRepository; +pub mod staff_role_repository; pub mod user_repository; #[async_trait::async_trait] @@ -17,6 +19,7 @@ pub trait RepositoryProvider { pub trait Repository where + Self: StaffRoleRepository::BackendError>, Self: UserRepository::BackendError>, { type BackendError: std::error::Error; diff --git a/cipher_core/src/repository/staff_role_repository.rs b/cipher_core/src/repository/staff_role_repository.rs new file mode 100644 index 0000000..14ad956 --- /dev/null +++ b/cipher_core/src/repository/staff_role_repository.rs @@ -0,0 +1,16 @@ +use super::RepositoryError; + +#[async_trait::async_trait] +pub trait StaffRoleRepository { + type BackendError: std::error::Error; + + async fn is_staff_role(&mut self, id: u64) -> Result>; + + async fn staff_roles(&mut self) -> Result, RepositoryError>; + + async fn staff_roles_contains(&mut self, ids: &[u64]) -> Result>; + + async fn set_staff_role(&mut self, id: u64) -> Result<(), RepositoryError>; + + async fn unset_staff_role(&mut self, id: u64) -> Result<(), RepositoryError>; +} diff --git a/cipher_database/src/mysql/repository/mod.rs b/cipher_database/src/mysql/repository/mod.rs index d63ca44..a6770f3 100644 --- a/cipher_database/src/mysql/repository/mod.rs +++ b/cipher_database/src/mysql/repository/mod.rs @@ -7,6 +7,7 @@ use cipher_core::repository::RepositoryProvider; use crate::BackendError; +mod staff_role_repository; mod user_repository; pub struct MysqlRepository<'a> { diff --git a/cipher_database/src/mysql/repository/staff_role_repository.rs b/cipher_database/src/mysql/repository/staff_role_repository.rs new file mode 100644 index 0000000..818d904 --- /dev/null +++ b/cipher_database/src/mysql/repository/staff_role_repository.rs @@ -0,0 +1,106 @@ +use diesel::prelude::*; +use diesel_async::scoped_futures::ScopedFutureExt; +use diesel_async::AsyncConnection; +use diesel_async::RunQueryDsl; +use cipher_core::repository::staff_role_repository::StaffRoleRepository; +use cipher_core::repository::RepositoryError; + +use crate::mysql::schema::staff_roles; +use crate::BackendError; + +use super::MysqlRepository; + +#[async_trait::async_trait] +impl StaffRoleRepository for MysqlRepository<'_> { + type BackendError = BackendError; + + async fn is_staff_role(&mut self, id: u64) -> Result> { + let model_id = id as i64; + + staff_roles::dsl::staff_roles + .filter(staff_roles::dsl::discord_role_id.eq(model_id)) + .first::(&mut self.conn) + .await + .optional() + .map(|option| option.is_some()) + .map_err(|err| RepositoryError(BackendError::from(err))) + } + + async fn staff_roles(&mut self) -> Result, RepositoryError> { + let model_results = staff_roles::dsl::staff_roles + .select(ModelStaffRole::as_select()) + .load(&mut self.conn) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + let results = model_results.into_iter() + .map(|r| r.discord_role_id as u64) + .collect(); + + Ok(results) + } + + async fn staff_roles_contains(&mut self, ids: &[u64]) -> Result> { + let model_ids: Vec<_> = ids.into_iter().map(|&id| id as i64).collect(); + + staff_roles::dsl::staff_roles + .filter(staff_roles::dsl::discord_role_id.eq_any(&model_ids)) + .first::(&mut self.conn) + .await + .optional() + .map(|option| option.is_some()) + .map_err(|err| RepositoryError(BackendError::from(err))) + } + + async fn set_staff_role(&mut self, id: u64) -> Result<(), RepositoryError> { + let new_staff_role = ModelNewStaffRole { + discord_role_id: id as i64, + }; + + self.conn + .transaction::<_, diesel::result::Error, _>(|conn| async move { + diesel::insert_into(staff_roles::table) + .values(&new_staff_role) + .on_conflict_do_nothing() + .execute(conn) + .await + }.scope_boxed()) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + Ok(()) + } + + async fn unset_staff_role(&mut self, id: u64) -> Result<(), RepositoryError> { + let model_id = id as i64; + + self.conn + .transaction::<_, diesel::result::Error, _>(move |conn| async move { + diesel::delete(staff_roles::dsl::staff_roles.filter(staff_roles::dsl::discord_role_id.eq(model_id))) + .execute(conn) + .await + }.scope_boxed()) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + Ok(()) + } +} + +#[derive(Queryable, Selectable, AsChangeset)] +#[diesel(table_name = staff_roles)] +#[diesel(treat_none_as_null = true)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +struct ModelStaffRole { + #[allow(unused)] + id: i32, + discord_role_id: i64, +} + +#[derive(Insertable)] +#[diesel(table_name = staff_roles)] +#[diesel(treat_none_as_null = true)] +#[diesel(check_for_backend(diesel::mysql::Mysql))] +struct ModelNewStaffRole { + discord_role_id: i64, +} diff --git a/cipher_database/src/postgres/repository/mod.rs b/cipher_database/src/postgres/repository/mod.rs index ec555cb..2740376 100644 --- a/cipher_database/src/postgres/repository/mod.rs +++ b/cipher_database/src/postgres/repository/mod.rs @@ -7,6 +7,7 @@ use cipher_core::repository::RepositoryProvider; use crate::BackendError; +mod staff_role_repository; mod user_repository; pub struct PostgresRepository<'a> { diff --git a/cipher_database/src/postgres/repository/staff_role_repository.rs b/cipher_database/src/postgres/repository/staff_role_repository.rs new file mode 100644 index 0000000..c3464f5 --- /dev/null +++ b/cipher_database/src/postgres/repository/staff_role_repository.rs @@ -0,0 +1,106 @@ +use diesel::prelude::*; +use diesel_async::scoped_futures::ScopedFutureExt; +use diesel_async::AsyncConnection; +use diesel_async::RunQueryDsl; +use cipher_core::repository::staff_role_repository::StaffRoleRepository; +use cipher_core::repository::RepositoryError; + +use crate::postgres::schema::staff_roles; +use crate::BackendError; + +use super::PostgresRepository; + +#[async_trait::async_trait] +impl StaffRoleRepository for PostgresRepository<'_> { + type BackendError = BackendError; + + async fn is_staff_role(&mut self, id: u64) -> Result> { + let model_id = id as i64; + + staff_roles::dsl::staff_roles + .filter(staff_roles::dsl::discord_role_id.eq(model_id)) + .first::(&mut self.conn) + .await + .optional() + .map(|option| option.is_some()) + .map_err(|err| RepositoryError(BackendError::from(err))) + } + + async fn staff_roles(&mut self) -> Result, RepositoryError> { + let model_results = staff_roles::dsl::staff_roles + .select(ModelStaffRole::as_select()) + .load(&mut self.conn) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + let results = model_results.into_iter() + .map(|r| r.discord_role_id as u64) + .collect(); + + Ok(results) + } + + async fn staff_roles_contains(&mut self, ids: &[u64]) -> Result> { + let model_ids: Vec<_> = ids.into_iter().map(|&id| id as i64).collect(); + + staff_roles::dsl::staff_roles + .filter(staff_roles::dsl::discord_role_id.eq_any(&model_ids)) + .first::(&mut self.conn) + .await + .optional() + .map(|option| option.is_some()) + .map_err(|err| RepositoryError(BackendError::from(err))) + } + + async fn set_staff_role(&mut self, id: u64) -> Result<(), RepositoryError> { + let new_staff_role = ModelNewStaffRole { + discord_role_id: id as i64, + }; + + self.conn + .transaction::<_, diesel::result::Error, _>(|conn| async move { + diesel::insert_into(staff_roles::table) + .values(&new_staff_role) + .on_conflict_do_nothing() + .execute(conn) + .await + }.scope_boxed()) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + Ok(()) + } + + async fn unset_staff_role(&mut self, id: u64) -> Result<(), RepositoryError> { + let model_id = id as i64; + + self.conn + .transaction::<_, diesel::result::Error, _>(move |conn| async move { + diesel::delete(staff_roles::dsl::staff_roles.filter(staff_roles::dsl::discord_role_id.eq(model_id))) + .execute(conn) + .await + }.scope_boxed()) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + Ok(()) + } +} + +#[derive(Queryable, Selectable, AsChangeset)] +#[diesel(table_name = staff_roles)] +#[diesel(treat_none_as_null = true)] +#[diesel(check_for_backend(diesel::pg::Pg))] +struct ModelStaffRole { + #[allow(unused)] + id: i32, + discord_role_id: i64, +} + +#[derive(Insertable)] +#[diesel(table_name = staff_roles)] +#[diesel(treat_none_as_null = true)] +#[diesel(check_for_backend(diesel::pg::Pg))] +struct ModelNewStaffRole { + discord_role_id: i64, +} diff --git a/cipher_database/src/sqlite/repository/mod.rs b/cipher_database/src/sqlite/repository/mod.rs index 0198811..cf398d6 100644 --- a/cipher_database/src/sqlite/repository/mod.rs +++ b/cipher_database/src/sqlite/repository/mod.rs @@ -8,6 +8,7 @@ use cipher_core::repository::RepositoryProvider; use crate::BackendError; +mod staff_role_repository; mod user_repository; pub struct SqliteRepository<'a> { diff --git a/cipher_database/src/sqlite/repository/staff_role_repository.rs b/cipher_database/src/sqlite/repository/staff_role_repository.rs new file mode 100644 index 0000000..b7316ff --- /dev/null +++ b/cipher_database/src/sqlite/repository/staff_role_repository.rs @@ -0,0 +1,106 @@ +use diesel::prelude::*; +use diesel_async::scoped_futures::ScopedFutureExt; +use diesel_async::AsyncConnection; +use diesel_async::RunQueryDsl; +use cipher_core::repository::staff_role_repository::StaffRoleRepository; +use cipher_core::repository::RepositoryError; + +use crate::sqlite::schema::staff_roles; +use crate::BackendError; + +use super::SqliteRepository; + +#[async_trait::async_trait] +impl StaffRoleRepository for SqliteRepository<'_> { + type BackendError = BackendError; + + async fn is_staff_role(&mut self, id: u64) -> Result> { + let model_id = id as i64; + + staff_roles::dsl::staff_roles + .filter(staff_roles::dsl::discord_role_id.eq(model_id)) + .first::(&mut self.conn) + .await + .optional() + .map(|option| option.is_some()) + .map_err(|err| RepositoryError(BackendError::from(err))) + } + + async fn staff_roles(&mut self) -> Result, RepositoryError> { + let model_results = staff_roles::dsl::staff_roles + .select(ModelStaffRole::as_select()) + .load(&mut self.conn) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + let results = model_results.into_iter() + .map(|r| r.discord_role_id as u64) + .collect(); + + Ok(results) + } + + async fn staff_roles_contains(&mut self, ids: &[u64]) -> Result> { + let model_ids: Vec<_> = ids.into_iter().map(|&id| id as i64).collect(); + + staff_roles::dsl::staff_roles + .filter(staff_roles::dsl::discord_role_id.eq_any(&model_ids)) + .first::(&mut self.conn) + .await + .optional() + .map(|option| option.is_some()) + .map_err(|err| RepositoryError(BackendError::from(err))) + } + + async fn set_staff_role(&mut self, id: u64) -> Result<(), RepositoryError> { + let new_staff_role = ModelNewStaffRole { + discord_role_id: id as i64, + }; + + self.conn + .transaction::<_, diesel::result::Error, _>(|conn| async move { + diesel::insert_into(staff_roles::table) + .values(&new_staff_role) + .on_conflict_do_nothing() + .execute(conn) + .await + }.scope_boxed()) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + Ok(()) + } + + async fn unset_staff_role(&mut self, id: u64) -> Result<(), RepositoryError> { + let model_id = id as i64; + + self.conn + .transaction::<_, diesel::result::Error, _>(move |conn| async move { + diesel::delete(staff_roles::dsl::staff_roles.filter(staff_roles::dsl::discord_role_id.eq(model_id))) + .execute(conn) + .await + }.scope_boxed()) + .await + .map_err(|err| RepositoryError(BackendError::from(err)))?; + + Ok(()) + } +} + +#[derive(Queryable, Selectable, AsChangeset)] +#[diesel(table_name = staff_roles)] +#[diesel(treat_none_as_null = true)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] +struct ModelStaffRole { + #[allow(unused)] + id: i32, + discord_role_id: i64, +} + +#[derive(Insertable)] +#[diesel(table_name = staff_roles)] +#[diesel(treat_none_as_null = true)] +#[diesel(check_for_backend(diesel::sqlite::Sqlite))] +struct ModelNewStaffRole { + discord_role_id: i64, +}